diff --git a/DEPS b/DEPS
index 30df557..4d078a3 100644
--- a/DEPS
+++ b/DEPS
@@ -253,19 +253,19 @@
   # 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': '72d67dfcc93a31c83d878d03d68c8c833caaf74e',
+  'skia_revision': '65ea360613a9b1154f4c575716123c1eb5722964',
   # 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': '445e90fe9b9efa996262e5b424c71e5345e41dae',
+  'v8_revision': 'f212c7856a16d49e23903ce44293e1864f23f195',
   # 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': '4b232a9a826182308e0523a74998e355d3733792',
+  'angle_revision': '4655ef15d128fb5f50fae6d0145cae7908a66fc2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '649d6e46aeaea1740fe8439ce8935142c8c3f36e',
+  'swiftshader_revision': 'eeb535119c68614312df222fb6f9d9345f2ecbf1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -328,7 +328,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': '36cd6608718d1c71b906c2ce7f0db838d5dff5a0',
+  'devtools_frontend_revision': '9756795ffa4648be566f943bc9c2aa138f797e21',
   # 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.
@@ -408,7 +408,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.
-  'libcxxabi_revision':    'e9c9bdf97591f694e9d11159a3aacc76d495b63c',
+  'libcxxabi_revision':    '185051038f204e5cd9881ab55b0044241af839e7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -731,7 +731,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '811ce357d3deb1a24478675890891cabfc2094f2',
+    'url': Var('chromium_git') + '/website.git' + '@' + 'af477ed62bab4a7adedf4c6c7a4ad06c328c5cde',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -836,7 +836,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'wJJtJ-UrEMxHHizlLi13NlMZgfGbojZAKjo7--aoBPsC',
+          'version': 'oskYpRArDkhqWLul2H0cblbkXHvII05FlJUQEhVxnw0C',
         },
       ],
       'dep_type': 'cipd',
@@ -847,7 +847,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'BRekj2m8BGB0svpadpN13WmyMoN7lr4VxzJfc4AcwTsC',
+          'version': '-gn1Jg_viML6w4M94ctcHT0vXcfWeMQrAm2Y855q7ZAC',
         },
       ],
       'dep_type': 'cipd',
@@ -858,7 +858,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'UA1jPG64HUixUn_vXUsV-VrHLrR9iM45tIg2O4oUPcwC',
+          'version': 'CKErZBGVIIbTnYNj2ROKeMSU0y3m2AkR7qaTCPOvJlkC',
         },
       ],
       'dep_type': 'cipd',
@@ -1515,7 +1515,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f4da613d6229df0d6a017448de05d54e7218d58d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'da3eb18b5c1cdaab87292750c2c3dc4138b58874',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1593,7 +1593,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/android/aemu/release/linux-amd64',
-              'version': 'kh_pRBcjUEXYrzw_OXh3BDKYOHY5Hc0YiWnxQqg-EGIC'
+              'version': 'ZrBfBlGrniNxDM181U3v3h-iQkAoWWGnOqBKRb2b3akC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1736,7 +1736,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7afd2efc27572eda0e9b3a8c0831b47f5e6c3353',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '7117f9b68826a214bc988ee78a6ef841cc37487c',
+    Var('webrtc_git') + '/src.git' + '@' + 'f2599a7f4374cb2d5b469c4d6d8e3250bad0a128',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1806,7 +1806,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0b63ee1a711ece2bdcecb3f22650dfb405dfe441',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@dcceaa1653282728b3cf3e00bb30e7385425ed74',
     'condition': 'checkout_src_internal',
   },
 
@@ -1858,7 +1858,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': '4Ivy0ctdTciRAdk9fJQd2iwv7pNhPF5xg8N2Yr6SXiUC',
+        'version': 'SiGpBQU_uIq-knGcvft5AudUKS42c-n7T5vE_KL-jkoC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/components/login/auth/BUILD.gn b/ash/components/login/auth/BUILD.gn
index 65262c3..15b630cd 100644
--- a/ash/components/login/auth/BUILD.gn
+++ b/ash/components/login/auth/BUILD.gn
@@ -69,6 +69,8 @@
     "key.h",
     "login_performer.cc",
     "login_performer.h",
+    "metrics_recorder.cc",
+    "metrics_recorder.h",
     "password_visibility_utils.cc",
     "password_visibility_utils.h",
     "safe_mode_delegate.h",
diff --git a/ash/components/login/auth/login_performer.cc b/ash/components/login/auth/login_performer.cc
index f77f1c9..4e81b1c 100644
--- a/ash/components/login/auth/login_performer.cc
+++ b/ash/components/login/auth/login_performer.cc
@@ -4,12 +4,10 @@
 
 #include "ash/components/login/auth/login_performer.h"
 
+#include "ash/components/login/auth/metrics_recorder.h"
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -20,13 +18,15 @@
 #include "components/user_manager/user_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
-using base::UserMetricsAction;
-
 namespace ash {
 
-LoginPerformer::LoginPerformer(Delegate* delegate)
+LoginPerformer::LoginPerformer(Delegate* delegate,
+                               MetricsRecorder* metrics_recorder)
     : delegate_(delegate),
-      last_login_failure_(AuthFailure::AuthFailureNone()) {}
+      metrics_recorder_(metrics_recorder),
+      last_login_failure_(AuthFailure::AuthFailureNone()) {
+  DCHECK(metrics_recorder_);
+}
 
 LoginPerformer::~LoginPerformer() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -40,11 +40,8 @@
 
 void LoginPerformer::OnAuthFailure(const AuthFailure& failure) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::RecordAction(UserMetricsAction("Login_Failure"));
 
-  UMA_HISTOGRAM_ENUMERATION("Login.FailureReason",
-                            failure.reason(),
-                            AuthFailure::NUM_FAILURE_REASONS);
+  metrics_recorder_->OnAuthFailure(failure.reason());
 
   LOG(ERROR) << "Login failure, reason=" << failure.reason()
              << ", error.state=" << failure.error().state();
@@ -57,11 +54,9 @@
 
 void LoginPerformer::OnAuthSuccess(const UserContext& user_context) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::RecordAction(UserMetricsAction("Login_Success"));
 
   // Do not distinguish between offline and online success.
-  UMA_HISTOGRAM_ENUMERATION("Login.SuccessReason", OFFLINE_AND_ONLINE,
-                            NUM_SUCCESS_REASONS);
+  metrics_recorder_->OnLoginSuccess(OFFLINE_AND_ONLINE);
 
   VLOG(1) << "LoginSuccess hash: " << user_context.GetUserIDHash();
   base::SequencedTaskRunnerHandle::Get()->PostTask(
@@ -71,7 +66,7 @@
 
 void LoginPerformer::OnOffTheRecordAuthSuccess() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::RecordAction(UserMetricsAction("Login_GuestLoginSuccess"));
+  metrics_recorder_->OnGuestLoignSuccess();
 
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&LoginPerformer::NotifyOffTheRecordAuthSuccess,
diff --git a/ash/components/login/auth/login_performer.h b/ash/components/login/auth/login_performer.h
index e126293..5677303e 100644
--- a/ash/components/login/auth/login_performer.h
+++ b/ash/components/login/auth/login_performer.h
@@ -11,9 +11,11 @@
 #include "ash/components/login/auth/auth_status_consumer.h"
 #include "ash/components/login/auth/authenticator.h"
 #include "ash/components/login/auth/extended_authenticator.h"
+#include "ash/components/login/auth/metrics_recorder.h"
 #include "ash/components/login/auth/user_context.h"
 #include "base/callback.h"
 #include "base/component_export.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "components/user_manager/user_type.h"
@@ -55,7 +57,8 @@
     virtual void PolicyLoadFailed() = 0;
   };
 
-  explicit LoginPerformer(Delegate* delegate);
+  explicit LoginPerformer(Delegate* delegate,
+                          MetricsRecorder* metrics_recorder);
 
   LoginPerformer(const LoginPerformer&) = delete;
   LoginPerformer& operator=(const LoginPerformer&) = delete;
@@ -191,6 +194,9 @@
   // Used for logging in.
   scoped_refptr<Authenticator> authenticator_;
 
+  // Used for metric reporting.
+  const raw_ptr<MetricsRecorder> metrics_recorder_;
+
   // Represents last login failure that was encountered when communicating to
   // sign-in server. AuthFailure.LoginFailureNone() by default.
   AuthFailure last_login_failure_;
diff --git a/ash/components/login/auth/metrics_recorder.cc b/ash/components/login/auth/metrics_recorder.cc
new file mode 100644
index 0000000..a66a3ac
--- /dev/null
+++ b/ash/components/login/auth/metrics_recorder.cc
@@ -0,0 +1,43 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/components/login/auth/metrics_recorder.h"
+
+#include "ash/components/login/auth/auth_status_consumer.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+
+namespace ash {
+namespace {
+
+// Histogram for tracking the reason of auth failure
+constexpr char kFailureReasonHistogramName[] = "Login.FailureReason";
+
+// Histogram for tracking the reason of login success
+constexpr char kSuccessReasonHistogramName[] = "Login.SuccessReason";
+
+}  // namespace
+
+MetricsRecorder::MetricsRecorder() {}
+
+MetricsRecorder::~MetricsRecorder() = default;
+
+void MetricsRecorder::OnAuthFailure(const AuthFailure::FailureReason& reason) {
+  base::RecordAction(base::UserMetricsAction("Login_Failure"));
+  UMA_HISTOGRAM_ENUMERATION(kFailureReasonHistogramName, reason,
+                            AuthFailure::NUM_FAILURE_REASONS);
+}
+
+void MetricsRecorder::OnLoginSuccess(const SuccessReason& reason) {
+  base::RecordAction(base::UserMetricsAction("Login_Success"));
+  UMA_HISTOGRAM_ENUMERATION(kSuccessReasonHistogramName, reason,
+                            SuccessReason::NUM_SUCCESS_REASONS);
+}
+
+void MetricsRecorder::OnGuestLoignSuccess() {
+  base::RecordAction(base::UserMetricsAction("Login_GuestLoginSuccess"));
+}
+
+}  // namespace ash
diff --git a/ash/components/login/auth/metrics_recorder.h b/ash/components/login/auth/metrics_recorder.h
new file mode 100644
index 0000000..a13a780
--- /dev/null
+++ b/ash/components/login/auth/metrics_recorder.h
@@ -0,0 +1,37 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_COMPONENTS_LOGIN_AUTH_METRICS_RECORDER_H_
+#define ASH_COMPONENTS_LOGIN_AUTH_METRICS_RECORDER_H_
+
+#include "ash/components/login/auth/auth_status_consumer.h"
+
+namespace ash {
+
+// This class encapsulates metrics reporting. User actions and behaviors are
+// reported in multiple stages of the login flow. This metrics reporter would
+// centralize the tracking and reporting.
+class COMPONENT_EXPORT(ASH_LOGIN_AUTH) MetricsRecorder {
+ public:
+  // Reports various metrics during the login flow.
+  MetricsRecorder();
+  MetricsRecorder(const MetricsRecorder&) = delete;
+  MetricsRecorder& operator=(const MetricsRecorder&) = delete;
+  MetricsRecorder(MetricsRecorder&&) = delete;
+  MetricsRecorder& operator=(MetricsRecorder&&) = delete;
+  ~MetricsRecorder();
+
+  // Logs the auth failure action and reason.
+  void OnAuthFailure(const AuthFailure::FailureReason& failure_reason);
+
+  // Logs the login success action and reason.
+  void OnLoginSuccess(const SuccessReason& reason);
+
+  // Logs the guest login success action.
+  void OnGuestLoignSuccess();
+};
+
+}  // namespace ash
+
+#endif  // ASH_COMPONENTS_LOGIN_AUTH_METRICS_RECORDER_H_
\ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 027b1c4..05a0a81 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -513,7 +513,7 @@
 // Wayland server. On Lacros, it determines whether the power save blocker is
 // invoked via Ozone Wayland (if enabled) or via crosapi (if disabled).
 const base::Feature kEnableIdleInhibit{"EnableIdleInhibit",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables selecting IKEv2 as the VPN provider type when creating a VPN network.
 // This will only take effect when running a compatible kernel, see
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 91ec8d4..2b5f6a1 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -1235,74 +1235,37 @@
       login_views_utils::WrapViewForPreferredSize(
           std::move(padding_below_user_view));
 
-  // Add views in tabbing order; they are rendered in a different order below.
-  views::View* wrapped_password_view_ptr =
-      AddChildView(std::move(wrapped_password_view));
-  views::View* wrapped_online_sign_in_message_view_ptr =
-      AddChildView(std::move(wrapped_online_sign_in_message_view));
-  views::View* wrapped_disabled_auth_message_view_ptr =
-      AddChildView(std::move(wrapped_disabled_auth_message_view));
-  views::View* wrapped_locked_tpm_message_view_ptr =
-      AddChildView(std::move(wrapped_locked_tpm_message_view));
-  views::View* wrapped_pin_input_view_ptr =
-      AddChildView(std::move(wrapped_pin_input_view));
-  views::View* wrapped_pin_view_ptr = AddChildView(std::move(wrapped_pin_view));
-  views::View* wrapped_pin_password_toggle_view_ptr =
-      AddChildView(std::move(wrapped_pin_password_toggle_view));
-  views::View* wrapped_fingerprint_view_ptr;
-  views::View* wrapped_auth_factors_view_ptr;
-  if (smart_lock_ui_revamp_enabled_) {
-    wrapped_auth_factors_view_ptr =
-        AddChildView(std::move(wrapped_auth_factors_view));
-  } else {
-    wrapped_fingerprint_view_ptr =
-        AddChildView(std::move(wrapped_fingerprint_view));
-  }
-  views::View* wrapped_challenge_response_view_ptr =
-      AddChildView(std::move(wrapped_challenge_response_view));
-  views::View* wrapped_user_view_ptr =
-      AddChildView(std::move(wrapped_user_view));
-  views::View* wrapped_padding_below_password_view_ptr =
-      AddChildView(std::move(wrapped_padding_below_password_view));
-  views::View* wrapped_padding_below_user_view_ptr =
-      AddChildView(std::move(wrapped_padding_below_user_view));
-
-  // Use views::GridLayout instead of views::BoxLayout because views::BoxLayout
-  // lays out children according to the view->children order.
-  views::GridLayout* grid_layout =
-      SetLayoutManager(std::make_unique<views::GridLayout>());
-  views::ColumnSet* column_set = grid_layout->AddColumnSet(0);
-  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING,
-                        0 /*resize_percent*/,
-                        views::GridLayout::ColumnSize::kUsePreferred,
-                        0 /*fixed_width*/, 0 /*min_width*/);
-  auto add_view = [&](views::View* view) {
-    grid_layout->StartRow(0 /*vertical_resize*/, 0 /*column_set_id*/);
-    grid_layout->AddExistingView(view);
-  };
-  auto add_padding = [&](int amount) {
-    grid_layout->AddPaddingRow(0 /*vertical_resize*/, amount /*size*/);
-  };
+  auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical,
+      gfx::Insets::TLBR(kDistanceFromTopOfBigUserViewToUserIconDp, 0,
+                        kDistanceFromPinKeyboardToBigUserViewBottomDp, 0)));
+  box_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
 
   // Add views in rendering order.
-  add_padding(kDistanceFromTopOfBigUserViewToUserIconDp);
-  add_view(wrapped_user_view_ptr);
-  add_view(wrapped_padding_below_user_view_ptr);
-  add_view(wrapped_locked_tpm_message_view_ptr);
-  add_view(wrapped_password_view_ptr);
-  add_view(wrapped_online_sign_in_message_view_ptr);
-  add_view(wrapped_disabled_auth_message_view_ptr);
-  add_view(wrapped_pin_input_view_ptr);
-  add_view(wrapped_padding_below_password_view_ptr);
-  add_view(wrapped_pin_view_ptr);
-  add_view(wrapped_pin_password_toggle_view_ptr);
+  auto* user_ptr = AddChildView(std::move(wrapped_user_view));
+  AddChildView(std::move(wrapped_padding_below_user_view));
+  auto* tpm_message_ptr =
+      AddChildView(std::move(wrapped_locked_tpm_message_view));
+  AddChildView(std::move(wrapped_password_view));
+  AddChildView(std::move(wrapped_online_sign_in_message_view));
+  auto* auth_message_ptr =
+      AddChildView(std::move(wrapped_disabled_auth_message_view));
+  AddChildView(std::move(wrapped_pin_input_view));
+  AddChildView(std::move(wrapped_padding_below_password_view));
+  AddChildView(std::move(wrapped_pin_view));
+  AddChildView(std::move(wrapped_pin_password_toggle_view));
   if (smart_lock_ui_revamp_enabled_) {
-    add_view(wrapped_auth_factors_view_ptr);
+    AddChildView(std::move(wrapped_auth_factors_view));
   } else {
-    add_view(wrapped_fingerprint_view_ptr);
+    AddChildView(std::move(wrapped_fingerprint_view));
   }
-  add_view(wrapped_challenge_response_view_ptr);
-  add_padding(kDistanceFromPinKeyboardToBigUserViewBottomDp);
+  auto* challenge_ptr =
+      AddChildView(std::move(wrapped_challenge_response_view));
+
+  // Set up taborder.
+  tpm_message_ptr->InsertAfterInFocusList(auth_message_ptr);
+  user_ptr->InsertAfterInFocusList(challenge_ptr);
 
   // The user needs to be set before SetAuthMethods is called.
   user_view_->UpdateForUser(user, /*animate*/ false);
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_view.cc b/ash/public/cpp/external_arc/message_center/arc_notification_view.cc
index 9b1dfc3..e722133 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_view.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_view.cc
@@ -124,6 +124,19 @@
   content_view_->UpdateCornerRadius(top_radius, bottom_radius);
 }
 
+void ArcNotificationView::UpdateBackgroundPainter() {
+  if (features::IsNotificationsRefreshEnabled()) {
+    SetBackground(views::CreateSolidBackground(
+        shown_in_popup_ ? AshColorProvider::Get()->GetBaseLayerColor(
+                              AshColorProvider::BaseLayerType::kTransparent80)
+                        : AshColorProvider::Get()->GetControlsLayerColor(
+                              AshColorProvider::ControlsLayerType::
+                                  kControlBackgroundColorInactive)));
+  } else {
+    MessageView::UpdateBackgroundPainter();
+  }
+}
+
 void ArcNotificationView::UpdateControlButtonsVisibility() {
   content_view_->UpdateControlButtonsVisibility();
 }
@@ -202,12 +215,6 @@
         GetColorProvider()->GetColor(ui::kColorFocusableBorderFocused),
         gfx::Insets::TLBR(0, 1, 3, 2));
   }
-
-  if (features::IsNotificationsRefreshEnabled() && shown_in_popup_) {
-    SetBackground(
-        views::CreateSolidBackground(AshColorProvider::Get()->GetBaseLayerColor(
-            AshColorProvider::BaseLayerType::kTransparent80)));
-  }
 }
 
 void ArcNotificationView::OnContainerAnimationEnded() {
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_view.h b/ash/public/cpp/external_arc/message_center/arc_notification_view.h
index a70125cb..0188388 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_view.h
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_view.h
@@ -64,6 +64,7 @@
   void OnSnoozeButtonPressed(const ui::Event& event) override;
   void OnThemeChanged() override;
   void UpdateCornerRadius(int top_radius, int bottom_radius) override;
+  void UpdateBackgroundPainter() override;
   base::TimeDelta GetBoundsAnimationDuration(
       const message_center::Notification&) const override;
 
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index e6b3183..c997b48d 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -3008,7 +3008,7 @@
                        set_wallpaper_weak_factory_.GetWeakPtr(), account_id,
                        GetDailyRefreshCollectionId(account_id),
                        ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
-                       /*preview_mode=*/false, std::move(callback)));
+                       std::move(callback)));
   } else {
     StartDailyRefreshTimer();
     std::move(callback).Run(false);
@@ -3019,7 +3019,6 @@
     const AccountId& account_id,
     const std::string& collection_id,
     WallpaperLayout layout,
-    bool preview_mode,
     RefreshWallpaperCallback callback,
     bool success,
     const backdrop::Image& image) {
@@ -3170,7 +3169,7 @@
       base::BindOnce(&WallpaperControllerImpl::SetDailyWallpaper,
                      weak_factory_.GetWeakPtr(), account_id, info.collection_id,
                      ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
-                     /*preview_mode=*/false, base::DoNothing()));
+                     base::DoNothing()));
 }
 
 void WallpaperControllerImpl::HandleOnlineWallpaperInfoSyncedIn(
diff --git a/ash/wallpaper/wallpaper_controller_impl.h b/ash/wallpaper/wallpaper_controller_impl.h
index 23fcc53b..08f3cb4 100644
--- a/ash/wallpaper/wallpaper_controller_impl.h
+++ b/ash/wallpaper/wallpaper_controller_impl.h
@@ -671,7 +671,6 @@
   void SetDailyWallpaper(const AccountId& account_id,
                          const std::string& collection_id,
                          WallpaperLayout layout,
-                         bool preview_mode,
                          RefreshWallpaperCallback callback,
                          bool success,
                          const backdrop::Image& image);
diff --git a/ash/webui/media_app_ui/resources/mock/js/app_main.js b/ash/webui/media_app_ui/resources/mock/js/app_main.js
index 26555b4..ab25be1 100644
--- a/ash/webui/media_app_ui/resources/mock/js/app_main.js
+++ b/ash/webui/media_app_ui/resources/mock/js/app_main.js
@@ -172,7 +172,6 @@
 
     this.replaceChild(child, this.currentMedia);
     this.currentMedia = child;
-    this.delegate.notifyCurrentFile(file.name, mimeType);
   }
 
   updateHandler() {
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
index 70bac3f0..90d6e37 100644
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -27,8 +27,6 @@
 ThreadCacheRegistry g_instance;
 }  // namespace
 
-namespace internal {
-
 namespace tools {
 uintptr_t kThreadCacheNeedleArray[kThreadCacheNeedleArraySize] = {
     kNeedle1, reinterpret_cast<uintptr_t>(&g_instance),
@@ -40,6 +38,8 @@
     kNeedle2};
 }  // namespace tools
 
+namespace internal {
+
 BASE_EXPORT PartitionTlsKey g_thread_cache_key;
 #if defined(PA_THREAD_CACHE_FAST_TLS)
 BASE_EXPORT
@@ -428,8 +428,7 @@
   PA_CHECK(root);
   // See comment in thread_cache.h, this is used to make sure
   // kThreadCacheNeedleArray is kept in the final binary.
-  PA_CHECK(internal::tools::kThreadCacheNeedleArray[0] ==
-           internal::tools::kNeedle1);
+  PA_CHECK(tools::kThreadCacheNeedleArray[0] == tools::kNeedle1);
 
   // Placement new and RawAlloc() are used, as otherwise when this partition is
   // the malloc() implementation, the memory allocated for the new thread cache
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
index c3a12bb7..4241d57 100644
--- a/base/allocator/partition_allocator/thread_cache.h
+++ b/base/allocator/partition_allocator/thread_cache.h
@@ -32,8 +32,6 @@
 
 class ThreadCache;
 
-namespace internal {
-
 namespace tools {
 
 // This is used from ThreadCacheInspector, which runs in a different process. It
@@ -66,6 +64,8 @@
 
 }  // namespace tools
 
+namespace internal {
+
 extern BASE_EXPORT PartitionTlsKey g_thread_cache_key;
 // On Android, we have to go through emutls, since this is always a shared
 // library, so don't bother.
@@ -150,8 +150,8 @@
   static constexpr size_t kMinCachedMemoryForPurging = 500 * 1024;
 
  private:
-  friend class internal::tools::ThreadCacheInspector;
-  friend class internal::tools::HeapDumper;
+  friend class tools::ThreadCacheInspector;
+  friend class tools::HeapDumper;
 
   // Not using base::Lock as the object's constructor must be constexpr.
   internal::Lock lock_;
@@ -327,8 +327,8 @@
       ThreadCacheLimits::kLargeSizeThreshold;
 
  private:
-  friend class internal::tools::HeapDumper;
-  friend class internal::tools::ThreadCacheInspector;
+  friend class tools::HeapDumper;
+  friend class tools::ThreadCacheInspector;
 
   struct Bucket {
     internal::PartitionFreelistEntry* freelist_head = nullptr;
@@ -417,7 +417,7 @@
 
   friend class ThreadCacheRegistry;
   friend class PartitionAllocThreadCacheTest;
-  friend class internal::tools::ThreadCacheInspector;
+  friend class tools::ThreadCacheInspector;
   FRIEND_TEST_ALL_PREFIXES(PartitionAllocThreadCacheTest, Simple);
   FRIEND_TEST_ALL_PREFIXES(PartitionAllocThreadCacheTest,
                            MultipleObjectsCachedPerBucket);
diff --git a/build/config/fuchsia/test/README.md b/build/config/fuchsia/test/README.md
index 9c36f5c7..5654caf 100644
--- a/build/config/fuchsia/test/README.md
+++ b/build/config/fuchsia/test/README.md
@@ -59,10 +59,13 @@
 `fuchsia.ui.policy.Presenter` is additionally required by tests that create
 views.
 
-#### vulkan.shard.test-cml and vulkan_capabilities.test-cmx
+#### vulkan_capabilities.test-cmx
 Corresponds to the `VULKAN` flag. Required for enabling GPU-accelerated
 rendering of the web content.
 
+CFv2 tests should use
+`//third_party/fuchsia-sdk/sdk/pkg/vulkan/client.shard.cml`.
+
 #### web_engine_required_capabilities.test-cmx
 Contains services that need to be present when creating a `fuchsia.web.Context`.
 Note that the `fuchsia.scheduler.ProfileProvider` service is only used in tests
diff --git a/build/config/fuchsia/test/vulkan.shard.test-cml b/build/config/fuchsia/test/vulkan.shard.test-cml
deleted file mode 100644
index a1360de..0000000
--- a/build/config/fuchsia/test/vulkan.shard.test-cml
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  use: [
-    {
-      protocol: [
-        "fuchsia.sysmem.Allocator",
-        "fuchsia.vulkan.loader.Loader",
-      ],
-    },
-  ],
-}
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index f23eb6d6..c61297c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20220402.3.1
+7.20220404.0.1
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index f23eb6d6..02b2a8e3 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-7.20220402.3.1
+7.20220404.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index f23eb6d6..c61297c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20220402.3.1
+7.20220404.0.1
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index c23668d2..091ec28 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -200,8 +200,6 @@
     "metrics/jank_injector.h",
     "metrics/jank_metrics.cc",
     "metrics/jank_metrics.h",
-    "metrics/latency_jank_tracker.cc",
-    "metrics/latency_jank_tracker.h",
     "metrics/latency_ukm_reporter.cc",
     "metrics/latency_ukm_reporter.h",
     "metrics/lcd_text_metrics_reporter.cc",
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 4df9cd4b..d14ff1a 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -5,8 +5,6 @@
 #include "cc/metrics/compositor_frame_reporter.h"
 
 #include <algorithm>
-#include <cstddef>
-#include <cstdint>
 #include <memory>
 #include <string>
 #include <utility>
@@ -22,11 +20,8 @@
 #include "cc/base/rolling_time_delta_history.h"
 #include "cc/metrics/dropped_frame_counter.h"
 #include "cc/metrics/event_latency_tracing_recorder.h"
-#include "cc/metrics/event_metrics.h"
 #include "cc/metrics/frame_sequence_tracker.h"
-#include "cc/metrics/latency_jank_tracker.h"
 #include "cc/metrics/latency_ukm_reporter.h"
-#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
 #include "services/tracing/public/cpp/perfetto/macros.h"
 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_frame_reporter.pbzero.h"
 #include "ui/events/types/event_type.h"
@@ -291,7 +286,6 @@
       std::make_pair(viz_breakdown.swap_timings.swap_end,
                      viz_breakdown.presentation_feedback.timestamp);
   swap_start_ = viz_breakdown.swap_timings.swap_start;
-  swap_end_ = viz_breakdown.swap_timings.swap_end;
 
   if (viz_breakdown.presentation_feedback.ready_timestamp.is_null())
     return;
@@ -603,22 +597,6 @@
                          std::make_move_iterator(events_metrics.end()));
 }
 
-void CompositorFrameReporter::ChronoSortEventMetrics() {
-  std::sort(
-      events_metrics_.begin(), events_metrics_.end(),
-      // if timestamps are different, prioritize the earlier event otherwise,
-      // prioritize having the kFirstGestureScrollUpdate in the loop
-      [](const auto& m1, const auto& m2) -> bool {
-        auto timestamp1 = m1->GetDispatchStageTimestamp(
-            EventMetrics::DispatchStage::kGenerated);
-        auto timestamp2 = m2->GetDispatchStageTimestamp(
-            EventMetrics::DispatchStage::kGenerated);
-        if (timestamp1 != timestamp2)
-          return timestamp1 < timestamp2;
-        return m1->type() == EventMetrics::EventType::kFirstGestureScrollUpdate;
-      });
-}
-
 EventMetrics::List CompositorFrameReporter::TakeEventsMetrics() {
   EventMetrics::List result = std::move(events_metrics_);
   events_metrics_.clear();
@@ -683,13 +661,6 @@
       ReportEventLatencyHistograms();
   }
 
-  if (should_report_metrics_) {
-    // This is necessary as EventLatency events associated with a frame are
-    // not stored in chronological order.
-    ChronoSortEventMetrics();
-    ReportEventLatenciesToJankTracker();
-  }
-
   auto* dropped_frame_counter = global_trackers_.dropped_frame_counter;
   if (dropped_frame_counter) {
     if (TestReportType(FrameReportType::kDroppedFrame)) {
@@ -1140,40 +1111,6 @@
   }
 }
 
-void CompositorFrameReporter::ReportEventLatenciesToJankTracker() {
-  if (events_metrics_.empty() || !global_trackers_.latency_jank_tracker)
-    return;
-  // TODO(crbug.com/1305153): This should check if the frame is presented or
-  // not. But the existing metrics in LatencyTracker are reported for all
-  // swapped frames, So do the same here for now.
-  // if (frame_termination_status_ != FrameTerminationStatus::kPresentedFrame) {
-  //  return;
-  //}
-  const auto end_timestamp = processed_viz_breakdown_
-                                 ? processed_viz_breakdown_->swap_end()
-                                 : base::TimeTicks();
-
-  if (end_timestamp.is_null())
-    return;
-
-  for (const auto& event : events_metrics_) {
-    if (event->type() != EventMetrics::EventType::kGestureScrollUpdate &&
-        event->type() !=
-            EventMetrics::EventType::kInertialGestureScrollUpdate &&
-        event->type() == EventMetrics::EventType::kFirstGestureScrollUpdate) {
-      continue;
-    }
-    const bool first_scroll_update =
-        event->type() == EventMetrics::EventType::kFirstGestureScrollUpdate;
-    const auto event_timestamp = event->GetDispatchStageTimestamp(
-        EventMetrics::DispatchStage::kGenerated);
-    // TODO(crbug.com/1305155): The `end_timestamp` should really be set to
-    // `frame_termination_time_`.
-    global_trackers_.latency_jank_tracker->ReportScrollTimings(
-        event_timestamp, end_timestamp, first_scroll_update);
-  }
-}
-
 base::TimeDelta CompositorFrameReporter::SumOfStageHistory() const {
   base::TimeDelta sum;
   for (const StageData& stage : stage_history_)
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index 5389170..f903e3d2 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -33,13 +33,11 @@
 namespace cc {
 class FrameSequenceTrackerCollection;
 class DroppedFrameCounter;
-class LatencyJankTracker;
 class LatencyUkmReporter;
 
 struct GlobalMetricsTrackers {
   DroppedFrameCounter* dropped_frame_counter = nullptr;
   LatencyUkmReporter* latency_ukm_reporter = nullptr;
-  LatencyJankTracker* latency_jank_tracker = nullptr;
   FrameSequenceTrackerCollection* frame_sequence_trackers = nullptr;
 };
 
@@ -219,7 +217,6 @@
         bool skip_swap_start_to_swap_end_if_breakdown_available) const;
 
     base::TimeTicks swap_start() const { return swap_start_; }
-    base::TimeTicks swap_end() const { return swap_end_; }
 
    private:
     absl::optional<std::pair<base::TimeTicks, base::TimeTicks>>
@@ -227,7 +224,6 @@
 
     bool buffer_ready_available_ = false;
     base::TimeTicks swap_start_;
-    base::TimeTicks swap_end_;
   };
 
   CompositorFrameReporter(const ActiveTrackers& active_trackers,
@@ -273,7 +269,6 @@
   void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown);
 
   void AddEventsMetrics(EventMetrics::List events_metrics);
-  void ChronoSortEventMetrics();
   EventMetrics::List TakeEventsMetrics();
 
   size_t stage_history_size_for_testing() const {
@@ -374,7 +369,6 @@
   void ReportEventLatencyHistograms() const;
   void ReportCompositorLatencyTraceEvents(const FrameInfo& info) const;
   void ReportEventLatencyTraceEvents() const;
-  void ReportEventLatenciesToJankTracker();
 
   void EnableReportType(FrameReportType report_type) {
     report_types_.set(static_cast<size_t>(report_type));
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index 32059e208..fbf02b1 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -32,7 +32,6 @@
       layer_tree_host_id_(layer_tree_host_id),
       latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()) {
   global_trackers_.latency_ukm_reporter = latency_ukm_reporter_.get();
-  global_trackers_.latency_jank_tracker = &latency_jank_tracker_;
 }
 
 CompositorFrameReportingController::~CompositorFrameReportingController() {
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h
index 085db70..ee9cfff 100644
--- a/cc/metrics/compositor_frame_reporting_controller.h
+++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -17,7 +17,6 @@
 #include "cc/metrics/compositor_frame_reporter.h"
 #include "cc/metrics/event_metrics.h"
 #include "cc/metrics/frame_sequence_metrics.h"
-#include "cc/metrics/latency_jank_tracker.h"
 
 namespace viz {
 struct FrameTimingDetails;
@@ -189,7 +188,6 @@
   // DO NOT reorder this line and the ones below. The latency_ukm_reporter_
   // must outlive the objects in |submitted_compositor_frames_|.
   std::unique_ptr<LatencyUkmReporter> latency_ukm_reporter_;
-  LatencyJankTracker latency_jank_tracker_;
 
   std::unique_ptr<CompositorFrameReporter>
       reporters_[PipelineStage::kNumPipelineStages];
diff --git a/cc/metrics/latency_jank_tracker.cc b/cc/metrics/latency_jank_tracker.cc
deleted file mode 100644
index 36696ae..0000000
--- a/cc/metrics/latency_jank_tracker.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/metrics/latency_jank_tracker.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_id_helper.h"
-#include "base/trace_event/typed_macros.h"
-#include "components/viz/common/frame_sinks/begin_frame_args.h"
-#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
-
-namespace cc {
-
-namespace {
-// Checking whether one update event length (measured in frames) is janky
-// compared to another (either previous or next). Update is deemed janky when
-// it's half of a frame longer than a neighbouring update.
-//
-// A small number is added to 0.5 in order to make sure that the comparison does
-// not filter out ratios that are precisely 0.5, which can fall a little above
-// or below exact value due to inherent inaccuracy of operations with
-// floating-point numbers. Value 1e-9 have been chosen as follows: the ratio has
-// less than nanosecond precision in numerator and VSync interval in
-// denominator. Assuming refresh rate more than 1 FPS (and therefore VSync
-// interval less than a second), this ratio should increase with increments more
-// than minimal value in numerator (1ns) divided by maximum value in
-// denominator, giving 1e-9.
-static bool IsJankyComparison(double frames, double other_frames) {
-  return frames > other_frames + 0.5 + 1e-9;
-}
-
-}  // namespace
-
-LatencyJankTracker::LatencyJankTracker() = default;
-LatencyJankTracker::~LatencyJankTracker() = default;
-
-void LatencyJankTracker::ReportScrollTimings(
-    base::TimeTicks original_timestamp,
-    base::TimeTicks gpu_swap_end_timestamp,
-    bool first_frame) {
-  DCHECK(!original_timestamp.is_null());
-  DCHECK(!gpu_swap_end_timestamp.is_null());
-  base::TimeDelta dur = gpu_swap_end_timestamp - original_timestamp;
-
-  if (first_frame) {
-    if (jank_state_.total_update_events_ > 0) {
-      // If we have some data from previous scroll, report it to UMA.
-      UMA_HISTOGRAM_MEDIUM_TIMES("Event.Latency.ScrollUpdate.TotalDuration2",
-                                 jank_state_.total_update_duration_);
-      UMA_HISTOGRAM_MEDIUM_TIMES("Event.Latency.ScrollUpdate.JankyDuration2",
-                                 jank_state_.janky_update_duration_);
-
-      UMA_HISTOGRAM_COUNTS_10000("Event.Latency.ScrollUpdate.TotalEvents2",
-                                 jank_state_.total_update_events_);
-      UMA_HISTOGRAM_COUNTS_10000("Event.Latency.ScrollUpdate.JankyEvents2",
-                                 jank_state_.janky_update_events_);
-
-      if (!jank_state_.total_update_duration_.is_zero()) {
-        UMA_HISTOGRAM_PERCENTAGE(
-            "Event.Latency.ScrollUpdate.JankyDurationPercentage2",
-            static_cast<int>(100 * (jank_state_.janky_update_duration_ /
-                                    jank_state_.total_update_duration_)));
-      }
-    }
-
-    jank_state_ = JankTrackerState{};
-  }
-
-  jank_state_.total_update_events_++;
-  jank_state_.total_update_duration_ += dur;
-
-  // When processing first frame in a scroll, we do not have any other frames to
-  // compare it to, and thus no way to detect the jank.
-  if (!first_frame) {
-    // TODO(b/185884172): Investigate using proper vsync interval.
-
-    // Assuming 60fps, each frame is rendered in (1/60) of a second.
-    // To see how many of those intervals fit into the real frame timing,
-    // we divide it on 1/60 which is the same thing as multiplying by 60.
-    double frames_taken = dur.InSecondsF() * 60;
-    double prev_frames_taken = jank_state_.prev_duration_.InSecondsF() * 60;
-
-    // For each GestureScroll update, we would like to report whether it was
-    // janky. However, in order to do that, we need to compare it both to the
-    // previous as well as to the next event. This condition means that no jank
-    // was reported for the previous frame (as compared to the one before that),
-    // so we need to compare it to the current one and report whether it's
-    // janky:
-    if (!jank_state_.prev_scroll_update_reported_) {
-      // The information about previous GestureScrollUpdate was not reported:
-      // check whether it's janky by comparing to the current frame and report.
-
-      if (IsJankyComparison(prev_frames_taken, frames_taken)) {
-        UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank2", true);
-        jank_state_.janky_update_events_++;
-        jank_state_.janky_update_duration_ += jank_state_.prev_duration_;
-      } else {
-        UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank2", false);
-      }
-    }
-
-    // The current GestureScrollUpdate is janky compared to the previous one.
-    if (IsJankyComparison(frames_taken, prev_frames_taken)) {
-      UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank2", true);
-      jank_state_.janky_update_events_++;
-      jank_state_.janky_update_duration_ += dur;
-
-      // Since we have reported the current event as janky, there is no need to
-      // report anything about it on the next iteration, as we would like to
-      // report every GestureScrollUpdate only once.
-      jank_state_.prev_scroll_update_reported_ = true;
-    } else {
-      // We do not have enough information to report whether the current event
-      // is janky, and need to compare it to the next one before reporting
-      // anything about it.
-      jank_state_.prev_scroll_update_reported_ = false;
-    }
-  }
-
-  jank_state_.prev_duration_ = dur;
-}
-
-}  // namespace cc
diff --git a/cc/metrics/latency_jank_tracker.h b/cc/metrics/latency_jank_tracker.h
deleted file mode 100644
index 885c13d9..0000000
--- a/cc/metrics/latency_jank_tracker.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_METRICS_LATENCY_JANK_TRACKER_H_
-#define CC_METRICS_LATENCY_JANK_TRACKER_H_
-
-#include "base/time/time.h"
-
-namespace cc {
-
-// This is used to track the state of the current scroll and for jank
-// reporting, because we need to compare the current frame with the
-// previous and next frame duration to detect jank, using the
-// frame_time > (prev/next)_frame_time + 0.5 + 1e-9 formula.
-class LatencyJankTracker {
- public:
-  LatencyJankTracker();
-  ~LatencyJankTracker();
-
-  LatencyJankTracker(const LatencyJankTracker&) = delete;
-  LatencyJankTracker& operator=(const LatencyJankTracker&) = delete;
-
-  void ReportScrollTimings(base::TimeTicks original_timestamp,
-                           base::TimeTicks gpu_swap_end_timestamp,
-                           bool first_frame);
-
- private:
-  // Data holder for all intermediate state for jank tracking.
-  struct JankTrackerState {
-    int total_update_events_ = 0;
-    int janky_update_events_ = 0;
-    bool prev_scroll_update_reported_ = false;
-    base::TimeDelta prev_duration_;
-    base::TimeDelta total_update_duration_;
-    base::TimeDelta janky_update_duration_;
-  };
-  JankTrackerState jank_state_;
-};
-
-}  // namespace cc
-
-#endif  // CC_METRICS_LATENCY_JANK_TRACKER_H_
diff --git a/chrome/VERSION b/chrome/VERSION
index 341ab095..924a73d 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=102
 MINOR=0
-BUILD=4984
+BUILD=4985
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
index 350fded..ffad7601 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
@@ -36,7 +36,7 @@
 */
 @JNINamespace("autofill")
 public class AutofillPopupBridge implements AutofillDelegate, DialogInterface.OnClickListener {
-    private final long mNativeAutofillPopup;
+    private long mNativeAutofillPopup;
     private final AutofillPopup mAutofillPopup;
     private AlertDialog mDeletionDialog;
     private final Context mContext;
@@ -75,17 +75,20 @@
 
     @Override
     public void dismissed() {
+        if (mNativeAutofillPopup == 0) return;
         AutofillPopupBridgeJni.get().popupDismissed(mNativeAutofillPopup, AutofillPopupBridge.this);
     }
 
     @Override
     public void suggestionSelected(int listIndex) {
+        if (mNativeAutofillPopup == 0) return;
         AutofillPopupBridgeJni.get().suggestionSelected(
                 mNativeAutofillPopup, AutofillPopupBridge.this, listIndex);
     }
 
     @Override
     public void deleteSuggestion(int listIndex) {
+        if (mNativeAutofillPopup == 0) return;
         AutofillPopupBridgeJni.get().deletionRequested(
                 mNativeAutofillPopup, AutofillPopupBridge.this, listIndex);
     }
@@ -97,6 +100,7 @@
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
+        if (mNativeAutofillPopup == 0) return;
         assert which == DialogInterface.BUTTON_POSITIVE;
         AutofillPopupBridgeJni.get().deletionConfirmed(
                 mNativeAutofillPopup, AutofillPopupBridge.this);
@@ -107,6 +111,7 @@
      */
     @CalledByNative
     private void dismiss() {
+        mNativeAutofillPopup = 0;
         if (mAutofillPopup != null) mAutofillPopup.dismiss();
         if (mDeletionDialog != null) mDeletionDialog.dismiss();
         mWebContentsAccessibility.onAutofillPopupDismissed();
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e7ad66a..22a7dd4 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2553,9 +2553,15 @@
     ]
   }
   if (is_linux || is_chromeos) {
+    sources += [
+      "component_updater/screen_ai_component_installer.cc",
+      "component_updater/screen_ai_component_installer.h",
+    ]
+
     deps += [
       "//chrome/browser/error_reporting",
       "//components/services/screen_ai/public/cpp:screen_ai_service_router_factory",
+      "//components/services/screen_ai/public/cpp:utilities",
     ]
   }
 
@@ -3609,10 +3615,8 @@
       "apps/intent_helper/apps_navigation_throttle.h",
       "apps/intent_helper/apps_navigation_types.cc",
       "apps/intent_helper/apps_navigation_types.h",
-      "apps/intent_helper/intent_picker_auto_display_service.cc",
-      "apps/intent_helper/intent_picker_auto_display_service.h",
-      "apps/intent_helper/intent_picker_auto_display_service_factory.cc",
-      "apps/intent_helper/intent_picker_auto_display_service_factory.h",
+      "apps/intent_helper/intent_picker_auto_display_prefs.cc",
+      "apps/intent_helper/intent_picker_auto_display_prefs.h",
       "apps/intent_helper/intent_picker_constants.h",
       "apps/intent_helper/intent_picker_features.cc",
       "apps/intent_helper/intent_picker_features.h",
diff --git a/chrome/browser/apps/app_service/app_service_proxy_ash.cc b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
index 62c976b..b2d65c6 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_ash.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
@@ -128,6 +128,12 @@
   return instance_registry_;
 }
 
+apps::AppPlatformMetrics* AppServiceProxyAsh::AppPlatformMetrics() {
+  return app_platform_metrics_service_
+             ? app_platform_metrics_service_->AppPlatformMetrics()
+             : nullptr;
+}
+
 apps::BrowserAppInstanceTracker*
 AppServiceProxyAsh::BrowserAppInstanceTracker() {
   return browser_app_instance_tracker_.get();
@@ -138,10 +144,10 @@
   return browser_app_instance_registry_.get();
 }
 
-apps::AppPlatformMetrics* AppServiceProxyAsh::AppPlatformMetrics() {
-  return app_platform_metrics_service_
-             ? app_platform_metrics_service_->AppPlatformMetrics()
-             : nullptr;
+void AppServiceProxyAsh::RegisterCrosApiSubScriber(
+    SubscriberCrosapi* subscriber) {
+  crosapi_subscriber_ = subscriber;
+  // TODO(crbug.com/1253250): Init apps and preferred apps.
 }
 
 void AppServiceProxyAsh::Uninstall(
@@ -260,6 +266,8 @@
 }
 
 void AppServiceProxyAsh::Shutdown() {
+  crosapi_subscriber_ = nullptr;
+
   app_platform_metrics_service_.reset();
 
   uninstall_dialogs_.clear();
diff --git a/chrome/browser/apps/app_service/app_service_proxy_ash.h b/chrome/browser/apps/app_service/app_service_proxy_ash.h
index dc52e79..91c646e 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_ash.h
+++ b/chrome/browser/apps/app_service/app_service_proxy_ash.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_base.h"
 #include "chrome/browser/apps/app_service/paused_apps.h"
 #include "chrome/browser/apps/app_service/publisher_host.h"
+#include "chrome/browser/apps/app_service/subscriber_crosapi.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/icon_types.h"
@@ -74,6 +75,9 @@
   apps::BrowserAppInstanceTracker* BrowserAppInstanceTracker();
   apps::BrowserAppInstanceRegistry* BrowserAppInstanceRegistry();
 
+  // Registers `crosapi_subscriber_`.
+  void RegisterCrosApiSubScriber(SubscriberCrosapi* subscriber);
+
   // apps::AppServiceProxyBase overrides:
   void Uninstall(const std::string& app_id,
                  apps::mojom::UninstallSource uninstall_source,
@@ -202,6 +206,8 @@
   void OnInstanceRegistryWillBeDestroyed(
       apps::InstanceRegistry* cache) override;
 
+  SubscriberCrosapi* crosapi_subscriber_ = nullptr;
+
   std::unique_ptr<PublisherHost> publisher_host_;
 
   bool arc_is_registered_ = false;
diff --git a/chrome/browser/apps/app_service/subscriber_crosapi.cc b/chrome/browser/apps/app_service/subscriber_crosapi.cc
index 303dd58..419c1056 100644
--- a/chrome/browser/apps/app_service/subscriber_crosapi.cc
+++ b/chrome/browser/apps/app_service/subscriber_crosapi.cc
@@ -127,6 +127,8 @@
   mojo::PendingRemote<apps::mojom::Subscriber> app_service_subscriber;
   receivers_.Add(this, app_service_subscriber.InitWithNewPipeAndPassReceiver());
   app_service->RegisterSubscriber(std::move(app_service_subscriber), nullptr);
+
+  proxy->RegisterCrosApiSubScriber(this);
 }
 
 void SubscriberCrosapi::Launch(crosapi::mojom::LaunchParamsPtr launch_params) {
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
index 3f9717cf..6b756d7 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/launch_utils.h"
 #include "chrome/browser/apps/intent_helper/apps_navigation_types.h"
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_features.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_internal.h"
 #include "chrome/browser/apps/intent_helper/metrics/intent_handling_metrics.h"
@@ -62,26 +62,22 @@
   if (!ShouldOverrideUrlLoading(GetStartingGURL(navigation_handle), url))
     return false;
 
-  IntentPickerAutoDisplayService* ui_auto_display_service =
-      IntentPickerAutoDisplayService::Get(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
 
   // On devices with tablet form factor we should not pop out the intent
   // picker if Chrome has been chosen by the user as the platform for this URL.
   // TODO(crbug.com/1225828): Handle this for lacros-chrome as well.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (ash::switches::IsTabletFormFactor()) {
-    if (ui_auto_display_service->GetLastUsedPlatformForTablets(url) ==
-        IntentPickerAutoDisplayService::Platform::kChrome) {
+    if (IntentPickerAutoDisplayPrefs::GetLastUsedPlatformForTablets(
+            profile, url) == IntentPickerAutoDisplayPrefs::Platform::kChrome) {
       return false;
     }
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // If the preferred app is use browser, do not show the intent picker.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
   auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
 
   if (proxy) {
@@ -93,7 +89,7 @@
     }
   }
 
-  return ui_auto_display_service->ShouldAutoDisplayUi(url);
+  return IntentPickerAutoDisplayPrefs::ShouldAutoDisplayUi(profile, url);
 }
 
 PickerShowState GetPickerShowState(
@@ -106,7 +102,6 @@
 }
 
 void OnAppIconsLoaded(content::WebContents* web_contents,
-                      IntentPickerAutoDisplayService* ui_auto_display_service,
                       const GURL& url,
                       std::vector<IntentPickerAppInfo> apps) {
   ShowIntentPickerBubbleForApps(
@@ -114,7 +109,7 @@
       /*show_stay_in_chrome=*/true,
       /*show_remember_selection=*/true,
       base::BindOnce(&OnIntentPickerClosedChromeOs, web_contents,
-                     ui_auto_display_service, PickerShowState::kPopOut, url));
+                     PickerShowState::kPopOut, url));
 }
 
 }  // namespace
@@ -130,50 +125,42 @@
       IntentHandlingMetrics::IntentPickerIconEvent::kAutoPopOut);
 
   content::WebContents* web_contents = navigation_handle->GetWebContents();
-  IntentPickerAutoDisplayService* ui_auto_display_service =
-      IntentPickerAutoDisplayService::Get(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
   const GURL& url = navigation_handle->GetURL();
 
   IntentPickerTabHelper::LoadAppIcons(
       web_contents, std::move(apps),
-      base::BindOnce(&OnAppIconsLoaded, web_contents, ui_auto_display_service,
-                     url));
+      base::BindOnce(&OnAppIconsLoaded, web_contents, url));
 }
 
-void OnIntentPickerClosedChromeOs(
-    content::WebContents* web_contents,
-    IntentPickerAutoDisplayService* ui_auto_display_service,
-    PickerShowState show_state,
-    const GURL& url,
-    const std::string& launch_name,
-    PickerEntryType entry_type,
-    IntentPickerCloseReason close_reason,
-    bool should_persist) {
+void OnIntentPickerClosedChromeOs(content::WebContents* web_contents,
+                                  PickerShowState show_state,
+                                  const GURL& url,
+                                  const std::string& launch_name,
+                                  PickerEntryType entry_type,
+                                  IntentPickerCloseReason close_reason,
+                                  bool should_persist) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
 // TODO(crbug.com/1225828): Handle this for lacros-chrome as well.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (ash::switches::IsTabletFormFactor() && should_persist) {
     // On devices of tablet form factor, until the user has decided to persist
     // the setting, the browser-side intent picker should always be seen.
-    auto platform = IntentPickerAutoDisplayService::Platform::kNone;
+    auto platform = IntentPickerAutoDisplayPrefs::Platform::kNone;
     if (entry_type == PickerEntryType::kArc) {
-      platform = IntentPickerAutoDisplayService::Platform::kArc;
+      platform = IntentPickerAutoDisplayPrefs::Platform::kArc;
     } else if (entry_type == PickerEntryType::kUnknown &&
                close_reason == IntentPickerCloseReason::STAY_IN_CHROME) {
-      platform = IntentPickerAutoDisplayService::Platform::kChrome;
+      platform = IntentPickerAutoDisplayPrefs::Platform::kChrome;
     }
-    IntentPickerAutoDisplayService::Get(
-        Profile::FromBrowserContext(web_contents->GetBrowserContext()))
-        ->UpdatePlatformForTablets(url, platform);
+    IntentPickerAutoDisplayPrefs::UpdatePlatformForTablets(profile, url,
+                                                           platform);
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   const bool should_launch_app =
       close_reason == IntentPickerCloseReason::OPEN_APP;
 
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
   auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
 
   // If the picker was closed without an app being chosen,
@@ -181,8 +168,8 @@
   // stop the UI from showing after 2+ dismissals.
   if (entry_type == PickerEntryType::kUnknown &&
       close_reason == IntentPickerCloseReason::DIALOG_DEACTIVATED &&
-      ui_auto_display_service) {
-    ui_auto_display_service->IncrementPickerUICounter(url);
+      show_state == PickerShowState::kPopOut) {
+    IntentPickerAutoDisplayPrefs::IncrementPickerUICounter(profile, url);
   }
 
   if (should_persist) {
@@ -208,7 +195,7 @@
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
 
   if (base::FeatureList::IsEnabled(features::kLinkCapturingUiUpdate)) {
-    IntentPickerAutoDisplayService::Get(profile)->ResetIntentChipCounter(url);
+    IntentPickerAutoDisplayPrefs::ResetIntentChipCounter(profile, url);
   }
 
   auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
index 83fb217a..e5f1c8a 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
@@ -10,8 +10,6 @@
 #include "chrome/browser/apps/intent_helper/apps_navigation_types.h"
 #include "url/gurl.h"
 
-class IntentPickerAutoDisplayService;
-
 namespace content {
 class NavigationHandle;
 class WebContents;
@@ -29,15 +27,13 @@
   kPopOut = 2,   // show the intent picker icon and pop out bubble
 };
 
-void OnIntentPickerClosedChromeOs(
-    content::WebContents* web_contents,
-    IntentPickerAutoDisplayService* ui_auto_display_service,
-    PickerShowState show_state,
-    const GURL& url,
-    const std::string& launch_name,
-    PickerEntryType entry_type,
-    IntentPickerCloseReason close_reason,
-    bool should_persist);
+void OnIntentPickerClosedChromeOs(content::WebContents* web_contents,
+                                  PickerShowState show_state,
+                                  const GURL& url,
+                                  const std::string& launch_name,
+                                  PickerEntryType entry_type,
+                                  IntentPickerCloseReason close_reason,
+                                  bool should_persist);
 
 void LaunchAppFromIntentPickerChromeOs(content::WebContents* web_contents,
                                        const GURL& url,
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.cc
similarity index 75%
rename from chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
rename to chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.cc
index 4a6111c..0fceba1 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h"
 
 #include "base/values.h"
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -44,23 +43,18 @@
 }  // namespace
 
 // static
-IntentPickerAutoDisplayService* IntentPickerAutoDisplayService::Get(
-    Profile* profile) {
-  return IntentPickerAutoDisplayServiceFactory::GetForProfile(profile);
-}
-
-IntentPickerAutoDisplayService::IntentPickerAutoDisplayService(Profile* profile)
-    : profile_(profile) {}
-
-bool IntentPickerAutoDisplayService::ShouldAutoDisplayUi(const GURL& url) {
+bool IntentPickerAutoDisplayPrefs::ShouldAutoDisplayUi(Profile* profile,
+                                                       const GURL& url) {
   base::Value pref_dict = GetAutoDisplayDictForSettings(
-      HostContentSettingsMapFactory::GetForProfile(profile_), url);
+      HostContentSettingsMapFactory::GetForProfile(profile), url);
 
   return pref_dict.FindIntKey(kAutoDisplayKey).value_or(0) < kDismissThreshold;
 }
 
-void IntentPickerAutoDisplayService::IncrementPickerUICounter(const GURL& url) {
-  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile_);
+// static
+void IntentPickerAutoDisplayPrefs::IncrementPickerUICounter(Profile* profile,
+                                                            const GURL& url) {
+  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile);
   base::Value pref_dict = GetAutoDisplayDictForSettings(settings_map, url);
 
   int dismissed_count = pref_dict.FindIntKey(kAutoDisplayKey).value_or(0);
@@ -71,10 +65,11 @@
       std::move(pref_dict));
 }
 
-IntentPickerAutoDisplayService::ChipState
-IntentPickerAutoDisplayService::GetChipStateAndIncrementCounter(
-    const GURL& url) {
-  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile_);
+// static
+IntentPickerAutoDisplayPrefs::ChipState
+IntentPickerAutoDisplayPrefs::GetChipStateAndIncrementCounter(Profile* profile,
+                                                              const GURL& url) {
+  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile);
   base::Value pref_dict = GetAutoDisplayDictForSettings(settings_map, url);
 
   int display_count = pref_dict.FindIntKey(kIntentChipCountKey).value_or(0);
@@ -91,8 +86,10 @@
   return ChipState::kExpanded;
 }
 
-void IntentPickerAutoDisplayService::ResetIntentChipCounter(const GURL& url) {
-  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile_);
+// static
+void IntentPickerAutoDisplayPrefs::ResetIntentChipCounter(Profile* profile,
+                                                          const GURL& url) {
+  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile);
   base::Value pref_dict = GetAutoDisplayDictForSettings(settings_map, url);
 
   pref_dict.SetIntKey(kIntentChipCountKey, 0);
@@ -102,10 +99,12 @@
       std::move(pref_dict));
 }
 
-IntentPickerAutoDisplayService::Platform
-IntentPickerAutoDisplayService::GetLastUsedPlatformForTablets(const GURL& url) {
+// static
+IntentPickerAutoDisplayPrefs::Platform
+IntentPickerAutoDisplayPrefs::GetLastUsedPlatformForTablets(Profile* profile,
+                                                            const GURL& url) {
   base::Value pref_dict = GetAutoDisplayDictForSettings(
-      HostContentSettingsMapFactory::GetForProfile(profile_), url);
+      HostContentSettingsMapFactory::GetForProfile(profile), url);
   int platform = pref_dict.FindIntKey(kPlatformKey).value_or(0);
 
   DCHECK_GE(platform, static_cast<int>(Platform::kNone));
@@ -114,10 +113,11 @@
   return static_cast<Platform>(platform);
 }
 
-void IntentPickerAutoDisplayService::UpdatePlatformForTablets(
-    const GURL& url,
-    Platform platform) {
-  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile_);
+// static
+void IntentPickerAutoDisplayPrefs::UpdatePlatformForTablets(Profile* profile,
+                                                            const GURL& url,
+                                                            Platform platform) {
+  auto* settings_map = HostContentSettingsMapFactory::GetForProfile(profile);
   base::Value pref_dict = GetAutoDisplayDictForSettings(settings_map, url);
 
   DCHECK_GE(static_cast<int>(platform), static_cast<int>(Platform::kNone));
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h
similarity index 65%
rename from chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
rename to chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h
index 59f227bd..f9bb645 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h
@@ -2,18 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_H_
-#define CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_H_
+#ifndef CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_PREFS_H_
+#define CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_PREFS_H_
 
-#include "base/memory/raw_ptr.h"
-#include "components/keyed_service/core/keyed_service.h"
 #include "url/gurl.h"
 
 class Profile;
 
 // Stores and manages user preferences about whether Intent Picker UI should be
 // automatically displayed for each origin.
-class IntentPickerAutoDisplayService : public KeyedService {
+class IntentPickerAutoDisplayPrefs {
  public:
   // The platform selected by the user to handle this URL for devices of tablet
   // form factor.
@@ -23,42 +21,35 @@
   // text) or collapsed (just an icon).
   enum class ChipState { kExpanded = 0, kCollapsed = 1 };
 
-  static IntentPickerAutoDisplayService* Get(Profile* profile);
-
-  explicit IntentPickerAutoDisplayService(Profile* profile);
-  IntentPickerAutoDisplayService(const IntentPickerAutoDisplayService&) =
-      delete;
-  IntentPickerAutoDisplayService& operator=(
-      const IntentPickerAutoDisplayService&) = delete;
-
   // Returns whether or not a likely |url| has triggered the UI 2+ times without
   // the user engaging.
-  bool ShouldAutoDisplayUi(const GURL& url);
+  static bool ShouldAutoDisplayUi(Profile* profile, const GURL& url);
 
   // Keep track of the |url| repetitions.
-  void IncrementPickerUICounter(const GURL& url);
+  static void IncrementPickerUICounter(Profile* profile, const GURL& url);
 
   // Returns a ChipState indicating whether the Intent Chip should be shown as
   // expanded or collapsed for a given URL. Increments an internal counter to
   // track the number of times the chip has been shown for that URL.
-  ChipState GetChipStateAndIncrementCounter(const GURL& url);
+  static ChipState GetChipStateAndIncrementCounter(Profile* profile,
+                                                   const GURL& url);
 
   // Reset the intent chip counter to 0. When this is called, it allows the
   // GetChipStateAndIncrementCounter function will return an Expanded ChipState
   // another 3 times for that |url|.
-  void ResetIntentChipCounter(const GURL& url);
+  static void ResetIntentChipCounter(Profile* profile, const GURL& url);
 
   // Returns the last platform selected by the user to handle |url|.
   // If it has not been checked then it will return |Platform::kNone|
   // for devices of tablet form factor.
-  Platform GetLastUsedPlatformForTablets(const GURL& url);
+  static Platform GetLastUsedPlatformForTablets(Profile* profile,
+                                                const GURL& url);
 
   // Updates the Platform to |platform| for |url| for devices of
   // tablet form factor.
-  void UpdatePlatformForTablets(const GURL& url, Platform platform);
-
- private:
-  raw_ptr<Profile> profile_;
+  static void UpdatePlatformForTablets(Profile* profile,
+                                       const GURL& url,
+                                       Platform platform);
 };
 
-#endif  // CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_H_
+#endif  // CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_PREFS_H_
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs_unittest.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs_unittest.cc
new file mode 100644
index 0000000..8c9bed1
--- /dev/null
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs_unittest.cc
@@ -0,0 +1,160 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using PickerPrefs = IntentPickerAutoDisplayPrefs;
+
+class IntentPickerAutoDisplayPrefsTest : public testing::Test {
+ public:
+  IntentPickerAutoDisplayPrefsTest()
+      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
+
+ protected:
+  content::BrowserTaskEnvironment task_environment_;
+};
+
+TEST_F(IntentPickerAutoDisplayPrefsTest, GetPlatform) {
+  GURL url1("https://www.google.com/abcde");
+  GURL url2("https://www.google.com/hi");
+  GURL url3("https://www.boogle.com/a");
+
+  TestingProfile profile;
+
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url1));
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url2));
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url3));
+
+  // Update platform to a value and check value has updated.
+  PickerPrefs::UpdatePlatformForTablets(&profile, url1,
+                                        PickerPrefs::Platform::kArc);
+  EXPECT_EQ(PickerPrefs::Platform::kArc,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url1));
+  // Url with the same host should also have updated value.
+  EXPECT_EQ(PickerPrefs::Platform::kArc,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url2));
+
+  // Url with a different host should have original value.
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url3));
+
+  // Update platform and check value has updated.
+  PickerPrefs::UpdatePlatformForTablets(&profile, url2,
+                                        PickerPrefs::Platform::kChrome);
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url1));
+  // Url with the same host should also have updated value.
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url2));
+
+  // Url with a different host should have original value.
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url3));
+
+  // Update platform and check value has updated.
+  PickerPrefs::UpdatePlatformForTablets(&profile, url3,
+                                        PickerPrefs::Platform::kArc);
+  // Url with different hosts should have original value.
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url1));
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url2));
+
+  // Url value should be updated.
+  EXPECT_EQ(PickerPrefs::Platform::kArc,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url3));
+
+  PickerPrefs::UpdatePlatformForTablets(&profile, url3,
+                                        PickerPrefs::Platform::kNone);
+  // Url value should be updated.
+  EXPECT_EQ(PickerPrefs::Platform::kNone,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url3));
+  // Url with different hosts should have original value.
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url1));
+  EXPECT_EQ(PickerPrefs::Platform::kChrome,
+            PickerPrefs::GetLastUsedPlatformForTablets(&profile, url2));
+}
+
+// Checks that calling IncrementCounter twice for a particular URL causes
+// the UI to no longer be auto-displayed for that URL.
+TEST_F(IntentPickerAutoDisplayPrefsTest, ShouldAutoDisplayUi) {
+  GURL url1("https://www.google.com/abcde");
+  GURL url2("https://www.google.com/hi");
+  GURL url3("https://www.boogle.com/a");
+
+  TestingProfile profile;
+
+  EXPECT_TRUE(PickerPrefs::ShouldAutoDisplayUi(&profile, url1));
+  PickerPrefs::IncrementPickerUICounter(&profile, url1);
+  EXPECT_TRUE(PickerPrefs::ShouldAutoDisplayUi(&profile, url1));
+  PickerPrefs::IncrementPickerUICounter(&profile, url1);
+  EXPECT_FALSE(PickerPrefs::ShouldAutoDisplayUi(&profile, url1));
+
+  // Should return false for a different URL on the same host.
+  EXPECT_FALSE(PickerPrefs::ShouldAutoDisplayUi(&profile, url2));
+  // Should return true for a different host.
+  EXPECT_TRUE(PickerPrefs::ShouldAutoDisplayUi(&profile, url3));
+}
+
+TEST_F(IntentPickerAutoDisplayPrefsTest, ResetIntentChipCounter) {
+  GURL url("https://www.google.com/abcde");
+
+  TestingProfile profile;
+
+  // Increment counter a few times.
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kExpanded);
+
+  // Reset the count back to 0.
+  PickerPrefs::ResetIntentChipCounter(&profile, url);
+
+  // Since the counter is reset, the chip is expanded another 3 times
+  // before collapsing.
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url),
+            PickerPrefs::ChipState::kCollapsed);
+}
+
+// Checks that calling GetChipStateAndIncrementCounter tracks views per-URL
+// and collapses the chip after a fixed number of views.
+TEST_F(IntentPickerAutoDisplayPrefsTest, GetChipStateAndIncrementCounter) {
+  using ChipState = PickerPrefs::ChipState;
+
+  GURL url1("https://www.google.com/abcde");
+  GURL url2("https://www.google.com/hi");
+  GURL url3("https://www.boogle.com/a");
+
+  TestingProfile profile;
+
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url1),
+            ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url2),
+            ChipState::kExpanded);
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url2),
+            ChipState::kExpanded);
+  // Fourth view for a host should be collapsed.
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url1),
+            ChipState::kCollapsed);
+
+  // URL on a different host should still be expanded.
+  EXPECT_EQ(PickerPrefs::GetChipStateAndIncrementCounter(&profile, url3),
+            ChipState::kExpanded);
+}
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.cc
deleted file mode 100644
index 09c12e49..0000000
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h"
-
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_context.h"
-
-// static
-IntentPickerAutoDisplayService*
-IntentPickerAutoDisplayServiceFactory::GetForProfile(Profile* profile) {
-  return static_cast<IntentPickerAutoDisplayService*>(
-      GetInstance()->GetServiceForBrowserContext(profile,
-                                                 /*create_if_necessary=*/true));
-}
-
-// static
-IntentPickerAutoDisplayServiceFactory*
-IntentPickerAutoDisplayServiceFactory::GetInstance() {
-  return base::Singleton<IntentPickerAutoDisplayServiceFactory>::get();
-}
-
-IntentPickerAutoDisplayServiceFactory::IntentPickerAutoDisplayServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "IntentPickerAutoDisplayService",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-IntentPickerAutoDisplayServiceFactory::
-    ~IntentPickerAutoDisplayServiceFactory() = default;
-
-KeyedService* IntentPickerAutoDisplayServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new IntentPickerAutoDisplayService(
-      Profile::FromBrowserContext(context));
-}
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h
deleted file mode 100644
index 7b7c0c9..0000000
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_FACTORY_H_
-
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-class IntentPickerAutoDisplayService;
-class Profile;
-
-class IntentPickerAutoDisplayServiceFactory
-    : public BrowserContextKeyedServiceFactory {
- public:
-  static IntentPickerAutoDisplayService* GetForProfile(Profile* profile);
-  static IntentPickerAutoDisplayServiceFactory* GetInstance();
-  IntentPickerAutoDisplayServiceFactory(
-      const IntentPickerAutoDisplayServiceFactory&) = delete;
-  IntentPickerAutoDisplayServiceFactory& operator=(
-      const IntentPickerAutoDisplayServiceFactory&) = delete;
-
- private:
-  friend struct base::DefaultSingletonTraits<
-      IntentPickerAutoDisplayServiceFactory>;
-
-  IntentPickerAutoDisplayServiceFactory();
-  ~IntentPickerAutoDisplayServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory Overrides:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-};
-
-#endif  // CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_FACTORY_H_
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_unittest.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_unittest.cc
deleted file mode 100644
index 16f7b5d..0000000
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service_unittest.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-class IntentPickerAutoDisplayServiceTest : public testing::Test {
- public:
-  IntentPickerAutoDisplayServiceTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
-
- protected:
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-TEST_F(IntentPickerAutoDisplayServiceTest, GetPlatform) {
-  GURL url1("https://www.google.com/abcde");
-  GURL url2("https://www.google.com/hi");
-  GURL url3("https://www.boogle.com/a");
-
-  TestingProfile profile;
-  IntentPickerAutoDisplayService* service =
-      IntentPickerAutoDisplayService::Get(&profile);
-
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url1));
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url2));
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url3));
-
-  // Update platform to a value and check value has updated.
-  service->UpdatePlatformForTablets(
-      url1, IntentPickerAutoDisplayService::Platform::kArc);
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kArc,
-            service->GetLastUsedPlatformForTablets(url1));
-  // Url with the same host should also have updated value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kArc,
-            service->GetLastUsedPlatformForTablets(url2));
-
-  // Url with a different host should have original value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url3));
-
-  // Update platform and check value has updated.
-  service->UpdatePlatformForTablets(
-      url2, IntentPickerAutoDisplayService::Platform::kChrome);
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url1));
-  // Url with the same host should also have updated value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url2));
-
-  // Url with a different host should have original value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url3));
-
-  // Update platform and check value has updated.
-  service->UpdatePlatformForTablets(
-      url3, IntentPickerAutoDisplayService::Platform::kArc);
-  // Url with different hosts should have original value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url1));
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url2));
-
-  // Url value should be updated.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kArc,
-            service->GetLastUsedPlatformForTablets(url3));
-
-  service->UpdatePlatformForTablets(
-      url3, IntentPickerAutoDisplayService::Platform::kNone);
-  // Url value should be updated.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kNone,
-            service->GetLastUsedPlatformForTablets(url3));
-  // Url with different hosts should have original value.
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url1));
-  EXPECT_EQ(IntentPickerAutoDisplayService::Platform::kChrome,
-            service->GetLastUsedPlatformForTablets(url2));
-}
-
-// Checks that calling IncrementCounter twice for a particular URL causes
-// the UI to no longer be auto-displayed for that URL.
-TEST_F(IntentPickerAutoDisplayServiceTest, ShouldAutoDisplayUi) {
-  GURL url1("https://www.google.com/abcde");
-  GURL url2("https://www.google.com/hi");
-  GURL url3("https://www.boogle.com/a");
-
-  TestingProfile profile;
-  IntentPickerAutoDisplayService* service =
-      IntentPickerAutoDisplayService::Get(&profile);
-
-  EXPECT_TRUE(service->ShouldAutoDisplayUi(url1));
-  service->IncrementPickerUICounter(url1);
-  EXPECT_TRUE(service->ShouldAutoDisplayUi(url1));
-  service->IncrementPickerUICounter(url1);
-  EXPECT_FALSE(service->ShouldAutoDisplayUi(url1));
-
-  // Should return false for a different URL on the same host.
-  EXPECT_FALSE(service->ShouldAutoDisplayUi(url2));
-  // Should return true for a different host.
-  EXPECT_TRUE(service->ShouldAutoDisplayUi(url3));
-}
-
-TEST_F(IntentPickerAutoDisplayServiceTest, ResetIntentChipCounter) {
-  GURL url("https://www.google.com/abcde");
-
-  TestingProfile profile;
-  IntentPickerAutoDisplayService* service =
-      IntentPickerAutoDisplayService::Get(&profile);
-
-  // Increment counter a few times.
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kExpanded);
-
-  // Reset the count back to 0.
-  service->ResetIntentChipCounter(url);
-
-  // Since the counter is reset, the chip is expanded another 3 times
-  // before collapsing.
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url),
-            IntentPickerAutoDisplayService::ChipState::kCollapsed);
-}
-
-// Checks that calling GetChipStateAndIncrementCounter tracks views per-URL
-// and collapses the chip after a fixed number of views.
-TEST_F(IntentPickerAutoDisplayServiceTest, GetChipStateAndIncrementCounter) {
-  using ChipState = IntentPickerAutoDisplayService::ChipState;
-
-  GURL url1("https://www.google.com/abcde");
-  GURL url2("https://www.google.com/hi");
-  GURL url3("https://www.boogle.com/a");
-
-  TestingProfile profile;
-  IntentPickerAutoDisplayService* service =
-      IntentPickerAutoDisplayService::Get(&profile);
-
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url1),
-            ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url2),
-            ChipState::kExpanded);
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url2),
-            ChipState::kExpanded);
-  // Fourth view for a host should be collapsed.
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url1),
-            ChipState::kCollapsed);
-
-  // URL on a different host should still be expanded.
-  EXPECT_EQ(service->GetChipStateAndIncrementCounter(url3),
-            ChipState::kExpanded);
-}
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
index 750c39e1..2e0fd3d0 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
@@ -11,7 +11,7 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_features.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_internal.h"
 #include "chrome/browser/profiles/profile.h"
@@ -69,7 +69,7 @@
   if (base::FeatureList::IsEnabled(features::kLinkCapturingUiUpdate)) {
     Profile* profile =
         Profile::FromBrowserContext(web_contents->GetBrowserContext());
-    IntentPickerAutoDisplayService::Get(profile)->ResetIntentChipCounter(url);
+    IntentPickerAutoDisplayPrefs::ResetIntentChipCounter(profile, url);
   }
 
   switch (app_type) {
@@ -89,38 +89,26 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
-void OnIntentPickerClosed(
-    content::WebContents* web_contents,
-    IntentPickerAutoDisplayService* ui_auto_display_service,
-    const GURL& url,
-    const std::string& launch_name,
-    PickerEntryType entry_type,
-    IntentPickerCloseReason close_reason,
-    bool should_persist) {
+void OnIntentPickerClosed(content::WebContents* web_contents,
+                          const GURL& url,
+                          const std::string& launch_name,
+                          PickerEntryType entry_type,
+                          IntentPickerCloseReason close_reason,
+                          bool should_persist) {
 #if BUILDFLAG(IS_CHROMEOS)
-  OnIntentPickerClosedChromeOs(web_contents, ui_auto_display_service,
-                               PickerShowState::kOmnibox, url, launch_name,
-                               entry_type, close_reason, should_persist);
+  OnIntentPickerClosedChromeOs(web_contents, PickerShowState::kOmnibox, url,
+                               launch_name, entry_type, close_reason,
+                               should_persist);
 #else
   const bool should_launch_app =
       close_reason == apps::IntentPickerCloseReason::OPEN_APP;
   if (should_launch_app) {
     LaunchAppFromIntentPicker(web_contents, url, launch_name, entry_type);
   }
-
-  if (entry_type == PickerEntryType::kUnknown &&
-      close_reason == IntentPickerCloseReason::DIALOG_DEACTIVATED &&
-      ui_auto_display_service) {
-    // We reach here if the picker was closed without an app being chosen, e.g.
-    // due to the tab being closed. Keep count of this scenario so we can stop
-    // the UI from showing after 2+ dismissals.
-    ui_auto_display_service->IncrementPickerUICounter(url);
-  }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
 void OnAppIconsLoaded(content::WebContents* web_contents,
-                      IntentPickerAutoDisplayService* ui_auto_display_service,
                       const GURL& url,
                       std::vector<IntentPickerAppInfo> apps) {
   ShowIntentPickerBubbleForApps(
@@ -132,8 +120,7 @@
       /*show_stay_in_chrome=*/false,
       /*show_remember_selection=*/false,
 #endif  // BUILDFLAG(IS_CHROMEOS)
-      base::BindOnce(&OnIntentPickerClosed, web_contents,
-                     ui_auto_display_service, url));
+      base::BindOnce(&OnIntentPickerClosed, web_contents, url));
 }
 
 std::vector<IntentPickerAppInfo> GetAppsForIntentPicker(
@@ -190,8 +177,7 @@
 
   IntentPickerTabHelper::LoadAppIcons(
       web_contents, std::move(apps),
-      base::BindOnce(&OnAppIconsLoaded, web_contents,
-                     /*ui_auto_display_service=*/nullptr, url));
+      base::BindOnce(&OnAppIconsLoaded, web_contents, url));
 }
 
 bool IntentPickerPwaPersistenceEnabled() {
diff --git a/chrome/browser/ash/app_mode/kiosk_profile_loader.cc b/chrome/browser/ash/app_mode/kiosk_profile_loader.cc
index 0eb84ed5..8cf307df 100644
--- a/chrome/browser/ash/app_mode/kiosk_profile_loader.cc
+++ b/chrome/browser/ash/app_mode/kiosk_profile_loader.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_types.h"
 #include "chrome/browser/ash/login/auth/chrome_login_performer.h"
+#include "chrome/browser/ash/login/ui/login_display_host.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/userdataauth/userdataauth_client.h"
@@ -154,7 +155,8 @@
 }
 
 void KioskProfileLoader::LoginAsKioskAccount() {
-  login_performer_ = std::make_unique<ChromeLoginPerformer>(this);
+  login_performer_ = std::make_unique<ChromeLoginPerformer>(
+      this, LoginDisplayHost::default_host()->metrics_recorder());
   switch (app_type_) {
     case KioskAppType::kArcApp:
       login_performer_->LoginAsArcKioskAccount(account_id_);
diff --git a/chrome/browser/ash/app_mode/startup_app_launcher.cc b/chrome/browser/ash/app_mode/startup_app_launcher.cc
index 19e0be8..b393126 100644
--- a/chrome/browser/ash/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/ash/app_mode/startup_app_launcher.cc
@@ -14,17 +14,14 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/net/delay_network_call.h"
 #include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h"
+#include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h"
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher_update_checker.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/install_tracker_factory.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/crx_file/id_util.h"
 #include "extensions/browser/app_window/app_window.h"
@@ -55,7 +52,6 @@
     : KioskAppLauncher(delegate), profile_(profile), app_id_(app_id) {
   DCHECK(profile_);
   DCHECK(crx_file::id_util::IdIsValid(app_id_));
-  kiosk_app_manager_observation_.Observe(KioskAppManager::Get());
 }
 
 StartupAppLauncher::~StartupAppLauncher() {
@@ -77,7 +73,7 @@
     return;
 
   if (delegate_->ShouldSkipAppInstallation()) {
-    FinalizeAppInstall();
+    OnInstallSuccess();
     return;
   }
 
@@ -85,6 +81,7 @@
   // external cache initially. Update the external cache now that the network
   // is ready for sure.
   state_ = LaunchState::kWaitingForCache;
+  kiosk_app_manager_observation_.Observe(KioskAppManager::Get());
   KioskAppManager::Get()->UpdateExternalCache();
 }
 
@@ -135,7 +132,7 @@
   }
 
   if (delegate_->ShouldSkipAppInstallation()) {
-    FinalizeAppInstall();
+    OnInstallSuccess();
     return;
   }
 
@@ -187,33 +184,79 @@
       app_id_);
 }
 
+void StartupAppLauncher::BeginInstall() {
+  state_ = LaunchState::kInstallingApp;
+  delegate_->OnAppInstalling();
+  installer_ = std::make_unique<ChromeKioskAppInstaller>(
+      profile_, KioskAppManager::Get()->CreatePrimaryAppInstallData(app_id_),
+      delegate_);
+  installer_->BeginInstall(base::BindOnce(
+      &StartupAppLauncher::OnInstallComplete, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void StartupAppLauncher::OnInstallComplete(
+    ChromeKioskAppInstaller::InstallResult result) {
+  DCHECK(state_ == LaunchState::kInstallingApp);
+
+  installer_.reset();
+
+  switch (result) {
+    case ChromeKioskAppInstaller::InstallResult::kSuccess:
+      OnInstallSuccess();
+      return;
+    case ChromeKioskAppInstaller::InstallResult::kUnableToInstall:
+      OnLaunchFailure(KioskAppLaunchError::Error::kUnableToInstall);
+      return;
+    case ChromeKioskAppInstaller::InstallResult::kNotKioskEnabled:
+      OnLaunchFailure(KioskAppLaunchError::Error::kNotKioskEnabled);
+      return;
+    case ChromeKioskAppInstaller::InstallResult::kNetworkMissing:
+      if (!RetryWhenNetworkIsAvailable())
+        OnLaunchFailure(KioskAppLaunchError::Error::kUnableToLaunch);
+      return;
+  }
+}
+
+void StartupAppLauncher::OnInstallSuccess() {
+  state_ = LaunchState::kReadyToLaunch;
+  // Updates to cached primary app crx will be ignored after this point, so
+  // there is no need to observe the kiosk app manager any longer.
+  kiosk_app_manager_observation_.Reset();
+  delegate_->OnAppPrepared();
+}
+
 void StartupAppLauncher::LaunchApp() {
   if (state_ != LaunchState::kReadyToLaunch) {
     NOTREACHED();
     SYSLOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
   }
 
-  const Extension* extension = GetPrimaryAppExtension();
-  CHECK(extension);
+  launcher_ = std::make_unique<ChromeKioskAppLauncher>(
+      profile_, app_id_, delegate_->IsNetworkReady());
 
-  if (!extensions::KioskModeInfo::IsKioskEnabled(extension)) {
-    OnLaunchFailure(KioskAppLaunchError::Error::kNotKioskEnabled);
-    return;
+  launcher_->LaunchApp(base::BindOnce(&StartupAppLauncher::OnLaunchComplete,
+                                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+void StartupAppLauncher::OnLaunchComplete(
+    ChromeKioskAppLauncher::LaunchResult result) {
+  DCHECK(state_ == LaunchState::kReadyToLaunch);
+
+  launcher_.reset();
+
+  switch (result) {
+    case ChromeKioskAppLauncher::LaunchResult::kSuccess:
+      KioskAppManager::Get()->InitSession(profile_, app_id_);
+      OnLaunchSuccess();
+      return;
+    case ChromeKioskAppLauncher::LaunchResult::kUnableToLaunch:
+      OnLaunchFailure(KioskAppLaunchError::Error::kUnableToLaunch);
+      return;
+    case ChromeKioskAppLauncher::LaunchResult::kNetworkMissing:
+      if (!RetryWhenNetworkIsAvailable())
+        OnLaunchFailure(KioskAppLaunchError::Error::kUnableToLaunch);
+      return;
   }
-
-  SYSLOG(INFO) << "Attempt to launch app.";
-
-  // Always open the app in a window.
-  ::OpenApplication(
-      profile_,
-      apps::AppLaunchParams(
-          extension->id(), apps::mojom::LaunchContainer::kLaunchContainerWindow,
-          WindowOpenDisposition::NEW_WINDOW,
-          apps::mojom::LaunchSource::kFromKiosk));
-
-  KioskAppManager::Get()->InitSession(profile_, app_id_);
-
-  OnLaunchSuccess();
 }
 
 void StartupAppLauncher::OnLaunchSuccess() {
@@ -246,48 +289,4 @@
   delegate_->OnLaunchFailed(error);
 }
 
-void StartupAppLauncher::FinalizeAppInstall() {
-  BeginInstall(/*finalize_only=*/true);
-}
-
-void StartupAppLauncher::BeginInstall(bool finalize_only) {
-  state_ = LaunchState::kInstallingApp;
-  if (!finalize_only) {
-    delegate_->OnAppInstalling();
-  }
-  installer_ = std::make_unique<ChromeKioskAppInstaller>(
-      profile_, KioskAppManager::Get()->CreatePrimaryAppInstallData(app_id_),
-      delegate_, finalize_only);
-  installer_->BeginInstall(base::BindOnce(
-      &StartupAppLauncher::OnInstallComplete, weak_ptr_factory_.GetWeakPtr()));
-}
-
-void StartupAppLauncher::OnInstallComplete(
-    ChromeKioskAppInstaller::InstallResult result) {
-  DCHECK(state_ == LaunchState::kInstallingApp);
-
-  switch (result) {
-    case ChromeKioskAppInstaller::InstallResult::kSuccess:
-      state_ = LaunchState::kReadyToLaunch;
-      // Updates to cached primary app crx will be ignored after this point,
-      // so there is no need to observe the kiosk app manager any longer.
-      kiosk_app_manager_observation_.Reset();
-      delegate_->OnAppPrepared();
-      return;
-    case ChromeKioskAppInstaller::InstallResult::kUnableToInstall:
-      OnLaunchFailure(KioskAppLaunchError::Error::kUnableToInstall);
-      return;
-    case ChromeKioskAppInstaller::InstallResult::kNotKioskEnabled:
-      OnLaunchFailure(KioskAppLaunchError::Error::kNotKioskEnabled);
-      return;
-    case ChromeKioskAppInstaller::InstallResult::kUnableToLaunch:
-      OnLaunchFailure(KioskAppLaunchError::Error::kUnableToLaunch);
-      return;
-    case ChromeKioskAppInstaller::InstallResult::kNetworkMissing:
-      if (!RetryWhenNetworkIsAvailable())
-        OnLaunchFailure(KioskAppLaunchError::Error::kUnableToLaunch);
-      return;
-  }
-}
-
 }  // namespace ash
diff --git a/chrome/browser/ash/app_mode/startup_app_launcher.h b/chrome/browser/ash/app_mode/startup_app_launcher.h
index 7859151..ac72d53 100644
--- a/chrome/browser/ash/app_mode/startup_app_launcher.h
+++ b/chrome/browser/ash/app_mode/startup_app_launcher.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
 #include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h"
+#include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/extensions/install_tracker.h"
 #include "extensions/browser/app_window/app_window_registry.h"
@@ -60,16 +61,18 @@
   // KioskAppLauncher:
   void Initialize() override;
   void ContinueWithNetworkReady() override;
-  void LaunchApp() override;
   void RestartLauncher() override;
+  void LaunchApp() override;
+
+  void BeginInstall();
+  void OnInstallComplete(ChromeKioskAppInstaller::InstallResult result);
+  void OnInstallSuccess();
+
+  void OnLaunchComplete(ChromeKioskAppLauncher::LaunchResult result);
 
   void OnLaunchSuccess();
   void OnLaunchFailure(KioskAppLaunchError::Error error);
 
-  void FinalizeAppInstall();
-  void BeginInstall(bool finalize_only = false);
-  void OnInstallComplete(ChromeKioskAppInstaller::InstallResult result);
-
   void MaybeInitializeNetwork();
   bool RetryWhenNetworkIsAvailable();
   void OnKioskAppDataLoadStatusChanged(const std::string& app_id);
@@ -89,6 +92,7 @@
   LaunchState state_ = LaunchState::kNotStarted;
 
   std::unique_ptr<ChromeKioskAppInstaller> installer_;
+  std::unique_ptr<ChromeKioskAppLauncher> launcher_;
 
   extensions::AppWindowRegistry* window_registry_;
 
diff --git a/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc b/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc
index d68bef12a..5fe5ded1 100644
--- a/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc
+++ b/chrome/browser/ash/app_mode/startup_app_launcher_unittest.cc
@@ -55,6 +55,7 @@
 using ::testing::AssertionFailure;
 using ::testing::AssertionResult;
 using ::testing::AssertionSuccess;
+using ::testing::ElementsAre;
 
 namespace ash {
 
@@ -847,6 +848,8 @@
 
   EXPECT_FALSE(kiosk_app_session_initialized_);
 
+  startup_app_launcher_->LaunchApp();
+
   EXPECT_TRUE(registry()->enabled_extensions().Contains(kTestPrimaryAppId));
   EXPECT_TRUE(registry()->enabled_extensions().Contains(kSecondaryAppId));
   EXPECT_TRUE(registry()->disabled_extensions().Contains(kExtraSecondaryAppId));
@@ -854,8 +857,6 @@
             extensions::ExtensionPrefs::Get(browser_context())
                 ->GetDisableReasons(kExtraSecondaryAppId));
 
-  startup_app_launcher_->LaunchApp();
-
   EXPECT_EQ(std::vector<LaunchState>({LaunchState::kLaunchSucceeded}),
             startup_launch_delegate_.launch_state_changes());
   EXPECT_EQ(1, app_launch_tracker_->kiosk_launch_count());
@@ -999,13 +1000,19 @@
 
   startup_app_launcher_->Initialize();
 
-  EXPECT_EQ(std::vector<LaunchState>({LaunchState::kInstallingApp}),
-            startup_launch_delegate_.launch_state_changes());
+  EXPECT_THAT(startup_launch_delegate_.launch_state_changes(),
+              ElementsAre(LaunchState::kInstallingApp));
   startup_launch_delegate_.ClearLaunchStateChanges();
 
   ASSERT_TRUE(FinishPrimaryAppInstall(primary_app_builder));
 
-  // After install is complete we should realize that the app is not offline
+  EXPECT_THAT(startup_launch_delegate_.launch_state_changes(),
+              ElementsAre(LaunchState::kReadyToLaunch));
+  startup_launch_delegate_.ClearLaunchStateChanges();
+
+  startup_app_launcher_->LaunchApp();
+
+  // When trying to launch app we should realize that the app is not offline
   // enabled and request a network connection.
   startup_launch_delegate_.WaitForLaunchStates(
       {LaunchState::kInitializingNetwork});
diff --git a/chrome/browser/ash/app_mode/test_kiosk_extension_builder.h b/chrome/browser/ash/app_mode/test_kiosk_extension_builder.h
index b9f648a..13fae61 100644
--- a/chrome/browser/ash/app_mode/test_kiosk_extension_builder.h
+++ b/chrome/browser/ash/app_mode/test_kiosk_extension_builder.h
@@ -20,6 +20,7 @@
 
 // Wrapper around extensions::ExtensionBuilder for creating extension::Extension
 // instances for usage in kiosk app tests.
+// TODO(b/227985497): Turn this into a proper builder
 class TestKioskExtensionBuilder {
  public:
   TestKioskExtensionBuilder(extensions::Manifest::Type type,
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc
index b6a3096..398a63b 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.cc
@@ -212,16 +212,14 @@
                                                          : install_url();
 }
 
-void WebKioskAppData::UpdateFromWebAppInfo(
-    std::unique_ptr<WebAppInstallInfo> app_info) {
-  DCHECK(app_info);
-  name_ = base::UTF16ToUTF8(app_info->title);
+void WebKioskAppData::UpdateFromWebAppInfo(const WebAppInstallInfo& app_info) {
+  name_ = base::UTF16ToUTF8(app_info.title);
   base::FilePath cache_dir;
   if (delegate_)
     delegate_->GetKioskAppIconCacheDir(&cache_dir);
 
-  auto it = app_info->icon_bitmaps.any.find(kIconSize);
-  if (it != app_info->icon_bitmaps.any.end()) {
+  auto it = app_info.icon_bitmaps.any.find(kIconSize);
+  if (it != app_info.icon_bitmaps.any.end()) {
     const SkBitmap& bitmap = it->second;
     icon_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
     icon_.MakeThreadSafe();
@@ -232,7 +230,7 @@
   DictionaryPrefUpdate dict_update(local_state, dictionary_name());
   SaveToDictionary(dict_update);
 
-  launch_url_ = GURL(app_info->start_url);
+  launch_url_ = GURL(app_info.start_url);
   dict_update->FindDictKey(KioskAppDataBase::kKeyApps)
       ->FindDictKey(app_id())
       ->SetStringKey(kKeyLaunchUrl, launch_url_.spec());
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h
index 01614e25..bb1c749a 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h
@@ -56,7 +56,7 @@
   // update.
   void SetStatus(Status status, bool notify = true);
 
-  void UpdateFromWebAppInfo(std::unique_ptr<WebAppInstallInfo> app_info);
+  void UpdateFromWebAppInfo(const WebAppInstallInfo& app_info);
 
   void SetOnLoadedCallbackForTesting(base::OnceClosure callback);
 
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc
index d875d3e..3a0d55d 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc
@@ -237,9 +237,9 @@
   EXPECT_EQ(app_data.GetLaunchableUrl(), GURL(kAppUrl));
 
   // `start_url` is treated as launchable URL if the app has been installed.
-  auto app_info = std::make_unique<WebAppInstallInfo>();
-  app_info->start_url = GURL(kStartUrl);
-  app_data.UpdateFromWebAppInfo(std::move(app_info));
+  WebAppInstallInfo app_info;
+  app_info.start_url = GURL(kStartUrl);
+  app_data.UpdateFromWebAppInfo(app_info);
   app_data.LoadFromCache();
   WaitForAppDataChange(1);
   EXPECT_EQ(app_data.status(), WebKioskAppData::Status::kInstalled);
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.cc
index e8a61207..cb50057c 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/window_properties.h"
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h"
 #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -21,12 +22,21 @@
 #include "chrome/common/chrome_features.h"
 #include "chromeos/ui/base/window_pin_type.h"
 #include "components/account_id/account_id.h"
+#include "components/webapps/browser/install_result_code.h"
 #include "ui/aura/window.h"
 #include "ui/base/page_transition_types.h"
 #include "url/origin.h"
 
 namespace ash {
 
+namespace {
+
+void RecordKioskWebAppInstallError(webapps::InstallResultCode code) {
+  base::UmaHistogramEnumeration("Kiosk.WebApp.InstallError", code);
+}
+
+}  // namespace
+
 // The delay time of closing the splash window when a lacros-browser window is
 // launched.
 constexpr base::TimeDelta kSplashWindowCloseDelayTime = base::Seconds(1);
@@ -80,24 +90,27 @@
 }
 
 void WebKioskAppLauncher::OnAppDataObtained(
-    std::unique_ptr<WebAppInstallInfo> app_info) {
-  if (!app_info) {
+    web_app::WebAppInstallTask::WebAppInstallInfoOrErrorCode info) {
+  if (absl::holds_alternative<webapps::InstallResultCode>(info)) {
+    RecordKioskWebAppInstallError(absl::get<webapps::InstallResultCode>(info));
     // Notify about failed installation, let the controller decide what to do.
     delegate_->OnLaunchFailed(KioskAppLaunchError::Error::kUnableToInstall);
     return;
   }
 
-  // When received |app_info->start_url| origin does not match the origin of
+  DCHECK(absl::holds_alternative<WebAppInstallInfo>(info));
+  const auto& app_info = absl::get<WebAppInstallInfo>(info);
+
+  // When received |app_info.start_url| origin does not match the origin of
   // |install_url|, fail.
   if (url::Origin::Create(GetCurrentApp()->install_url()) !=
-      url::Origin::Create(app_info->start_url)) {
+      url::Origin::Create(app_info.start_url)) {
     VLOG(1) << "Origin of the app does not match the origin of install url";
     delegate_->OnLaunchFailed(KioskAppLaunchError::Error::kUnableToLaunch);
     return;
   }
 
-  WebKioskAppManager::Get()->UpdateAppByAccountId(account_id_,
-                                                  std::move(app_info));
+  WebKioskAppManager::Get()->UpdateAppByAccountId(account_id_, app_info);
   delegate_->OnAppPrepared();
 }
 
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.h b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.h
index 3f6b899..04af7a12 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.h
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_id.h"
+#include "chrome/browser/web_applications/web_app_install_task.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_url_loader.h"
 #include "components/account_id/account_id.h"
@@ -26,7 +27,6 @@
 class Profile;
 
 namespace web_app {
-class WebAppInstallTask;
 class WebAppUrlLoader;
 class WebAppDataRetriever;
 }  // namespace web_app
@@ -75,7 +75,8 @@
 
   // Callback method triggered after web application and its icon are obtained
   // from `WebKioskAppManager`.
-  void OnAppDataObtained(std::unique_ptr<WebAppInstallInfo> app_info);
+  void OnAppDataObtained(
+      web_app::WebAppInstallTask::WebAppInstallInfoOrErrorCode);
 
   // Callback method triggered after the lacros-chrome window is created.
   void OnLacrosWindowCreated(crosapi::mojom::CreationResult result);
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc
index 796686d..935b36b 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/wm_helper_chromeos.h"
 #include "components/user_manager/scoped_user_manager.h"
+#include "components/webapps/browser/install_result_code.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -130,10 +131,10 @@
     app_manager_->AddAppForTesting(account_id_, GURL(kAppInstallUrl));
 
     if (installed) {
-      auto info = std::make_unique<WebAppInstallInfo>();
-      info->start_url = GURL(kAppLaunchUrl);
-      info->title = kAppTitle;
-      app_manager_->UpdateAppByAccountId(account_id_, std::move(info));
+      WebAppInstallInfo info;
+      info.start_url = GURL(kAppLaunchUrl);
+      info.title = kAppTitle;
+      app_manager_->UpdateAppByAccountId(account_id_, info);
     }
   }
 
@@ -302,6 +303,8 @@
 }
 
 TEST_F(WebKioskAppLauncherTest, UrlNotLoaded) {
+  base::HistogramTester histogram;
+
   SetupAppData(/*installed*/ false);
 
   base::RunLoop loop1;
@@ -322,6 +325,11 @@
   loop2.Run();
 
   EXPECT_NE(app_data()->status(), WebKioskAppData::Status::kInstalled);
+
+  content::FetchHistogramsFromChildProcesses();
+  histogram.ExpectUniqueSample(
+      "Kiosk.WebApp.InstallError",
+      webapps::InstallResultCode::kInstallURLLoadTimeOut, 1);
 }
 
 TEST_F(WebKioskAppLauncherTest, SkipInstallation) {
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.cc
index 7198195..93a1fd4 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.cc
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.cc
@@ -93,10 +93,10 @@
 
 void WebKioskAppManager::UpdateAppByAccountId(
     const AccountId& account_id,
-    std::unique_ptr<WebAppInstallInfo> app_info) {
+    const WebAppInstallInfo& app_info) {
   for (auto& web_app : apps_) {
     if (web_app->account_id() == account_id) {
-      web_app->UpdateFromWebAppInfo(std::move(app_info));
+      web_app->UpdateFromWebAppInfo(app_info);
       return;
     }
   }
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h
index 20b83e4..4c37e113 100644
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h
+++ b/chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h
@@ -54,7 +54,7 @@
 
   // Updates app by the data obtained during installation.
   void UpdateAppByAccountId(const AccountId& account_id,
-                            std::unique_ptr<WebAppInstallInfo> app_info);
+                            const WebAppInstallInfo& app_info);
 
   // Adds fake apps in tests.
   void AddAppForTesting(const AccountId& account_id, const GURL& install_url);
diff --git a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc
index 704f829..d1c7584 100644
--- a/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc
+++ b/chrome/browser/ash/apps/apk_web_app_installer_browsertest.cc
@@ -434,8 +434,8 @@
   {
     for (const auto& id : installed_web_app_ids_) {
       base::RunLoop run_loop;
-      provider_->install_finalizer().UninstallExternalWebApp(
-          id, webapps::WebappUninstallSource::kArc,
+      provider_->install_finalizer().UninstallWebApp(
+          id, webapps::WebappUninstallSource::kShelf,
           base::BindLambdaForTesting([&](webapps::UninstallResultCode code) {
             EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess);
             run_loop.Quit();
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_util.cc b/chrome/browser/ash/crosapi/browser_data_migrator_util.cc
index a7f9902c..62bf1b9e 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_util.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_util.cc
@@ -145,35 +145,42 @@
 constexpr char kIndexedDBBlobExtension[] = ".indexeddb.blob";
 constexpr char kIndexedDBLevelDBExtension[] = ".indexeddb.leveldb";
 
-// Chrome instance type (Ash or Lacros).
-enum class ChromeType {
-  kAsh = 0,
-  kLacros = 1,
-};
-
-void SplitPreferenceKey(base::Value::Dict* root_dict,
-                        const base::StringPiece key,
-                        ChromeType chrome_type) {
-  base::Value::Dict* dict = root_dict->FindDictByDottedPath(key);
-  if (!dict)
-    return;
-
+void UpdatePreferencesDictByType(base::Value::Dict& dict,
+                                 ChromeType chrome_type) {
   std::vector<std::string> keys_to_remove;
-  for (const auto entry : *dict) {
-    const base::StringPiece extension_id = entry.first;
-    bool keep_extension = base::Contains(kExtensionsAshOnly, extension_id);
 
-    if (((chrome_type == ChromeType::kLacros) && keep_extension) ||
-        ((chrome_type == ChromeType::kAsh) && !keep_extension)) {
+  // Collect keys that don't belong in `chrome_type`.
+  for (const auto entry : dict) {
+    const base::StringPiece extension_id = entry.first;
+    bool ash_extension = base::Contains(kExtensionsAshOnly, extension_id);
+
+    if (((chrome_type == ChromeType::kLacros) && ash_extension) ||
+        ((chrome_type == ChromeType::kAsh) && !ash_extension)) {
       keys_to_remove.emplace_back(extension_id);
     }
   }
 
+  // Delete those keys.
   for (const std::string& k : keys_to_remove) {
-    dict->Remove(k);
+    dict.Remove(k);
   }
 }
 
+void UpdatePreferencesListByType(base::Value::List& list,
+                                 ChromeType chrome_type) {
+  // Erase all elements in the list that don't belong in `chrome_type`.
+  list.EraseIf([&](const base::Value& item) {
+    if (!item.is_string())
+      return false;
+
+    const base::StringPiece extension_id = item.GetString();
+    bool ash_extension = base::Contains(kExtensionsAshOnly, extension_id);
+
+    return ((chrome_type == ChromeType::kLacros) && ash_extension) ||
+           ((chrome_type == ChromeType::kAsh) && !ash_extension);
+  });
+}
+
 }  // namespace
 
 CancelFlag::CancelFlag() : cancelled_(false) {}
@@ -693,6 +700,20 @@
   return true;
 }
 
+void UpdatePreferencesKeyByType(base::Value::Dict* root_dict,
+                                const base::StringPiece key,
+                                ChromeType chrome_type) {
+  base::Value* value = root_dict->FindByDottedPath(key);
+  if (!value)
+    return;
+
+  if (value->is_dict()) {
+    UpdatePreferencesDictByType(value->GetDict(), chrome_type);
+  } else if (value->is_list()) {
+    UpdatePreferencesListByType(value->GetList(), chrome_type);
+  }
+}
+
 absl::optional<PreferencesContents> MigratePreferencesContents(
     const base::StringPiece original_contents) {
   // Parse the original JSON file from Ash.
@@ -732,8 +753,8 @@
 
   // Some preferences need to be split between Ash and Lacros.
   for (const char* key : kSplitPreferencesKeys) {
-    SplitPreferenceKey(ash_root_dict, key, ChromeType::kAsh);
-    SplitPreferenceKey(lacros_root_dict, key, ChromeType::kLacros);
+    UpdatePreferencesKeyByType(ash_root_dict, key, ChromeType::kAsh);
+    UpdatePreferencesKeyByType(lacros_root_dict, key, ChromeType::kLacros);
   }
 
   // Generate the resulting JSON.
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_util.h b/chrome/browser/ash/crosapi/browser_data_migrator_util.h
index 4bec3a9e..fced3eb 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_util.h
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_util.h
@@ -11,6 +11,7 @@
 
 #include "base/files/file_path.h"
 #include "base/synchronization/atomic_flag.h"
+#include "base/values.h"
 #include "chrome/browser/ash/crosapi/migration_progress_tracker.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/leveldatabase/env_chromium.h"
@@ -242,11 +243,18 @@
   std::string lacros;
 };
 
+// Chrome instance type (Ash or Lacros).
+enum class ChromeType {
+  kAsh,
+  kLacros,
+};
+
 // Preferences's keys that have to be split between Ash and Lacros
 // based on extension id.
-// TODO(andreaorru): fill this in with the complete list.
 constexpr const char* kSplitPreferencesKeys[] = {
-    "extensions.settings",
+    "app_list.local_state",  "extensions.pinned_extensions",
+    "extensions.settings",   "extensions.toolbar",
+    "updateclientdata.apps", "web_apps.web_app_ids",
 };
 // Preferences's keys that should not be migrated to Lacros.
 constexpr const char* kAshOnlyPreferencesKeys[] = {
@@ -438,6 +446,24 @@
                     const base::FilePath& target_path,
                     const LevelDBType leveldb_type);
 
+// Manipulates the given representation of Preferences (`root_dict`)
+// so that the given key only contains values relevant to Ash or
+// Lacros, depending on `chrome_type`.
+//
+// If the entry in `root_dict` at `key` is a dict in the format
+// { <AppId> : { ... }, ... }, it will change the dict to contain only
+// AppIds of extensions meant to be in `chrome_type` (Ash or Lacros).
+//
+// If the entry is a list in the format [ <AppId>, ... ], it will
+// change the list to contain only AppIds of extensions meant to be
+// in `chrome_type` (Ash or Lacros).
+//
+// If the entry is a list in any other format, if it doesn't exist,
+// or if it's not container type, no changes will be performed.
+void UpdatePreferencesKeyByType(base::Value::Dict* root_dict,
+                                const base::StringPiece key,
+                                ChromeType chrome_type);
+
 // Given a `original_contents` string containing the original Preferences
 // file, return the migrated Ash and Lacros versions of Preferences.
 absl::optional<PreferencesContents> MigratePreferencesContents(
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_util_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_util_unittest.cc
index 6e2947d..56b8a63 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_util_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_util_unittest.cc
@@ -646,19 +646,82 @@
       kDryRunDeleteAndCopyMigrationHasEnoughDiskSpace, 1);
 }
 
-TEST(BrowserDataMigratorUtilTest, MigratePreferencesContents) {
-  const std::string keep_extension_key =
+TEST(BrowserDataMigratorUtilTest, UpdatePreferencesKeyByType) {
+  const std::string keep_extension_dict_key =
       std::string("extensions.settings.") + kExtensionsAshOnly[0];
-  const std::string move_extension_key =
+  const std::string move_extension_dict_key =
       std::string("extensions.settings.") + kMoveExtensionId;
 
+  base::Value::List extension_list;
+  extension_list.Append(kExtensionsAshOnly[0]);
+  extension_list.Append(kMoveExtensionId);
+  const std::string extension_list_key = "extensions.pinned_extensions";
+
+  // List of dictionaries instead of list of strings as expected.
+  // {"extensions.toolbar": [
+  //   { <kExtensionsAshOnly[0]> : "test1"},
+  //   { <kMoveExtensionId> : "test2"},
+  // ]}
+  base::Value::Dict wrong_type_value1;
+  wrong_type_value1.Set(kExtensionsAshOnly[0], "test1");
+  base::Value::Dict wrong_type_value2;
+  wrong_type_value2.Set(kMoveExtensionId, "test2");
+  base::Value::List wrong_type_list;
+  wrong_type_list.Append(std::move(wrong_type_value1));
+  wrong_type_list.Append(std::move(wrong_type_value2));
+  const std::string wrong_type_key = "extensions.toolbar";
+
+  base::Value::Dict ash_dict;
+  ash_dict.SetByDottedPath(keep_extension_dict_key, "test1");
+  ash_dict.SetByDottedPath(move_extension_dict_key, "test2");
+  ash_dict.SetByDottedPath(extension_list_key, std::move(extension_list));
+  ash_dict.SetByDottedPath(wrong_type_key, std::move(wrong_type_list));
+  base::Value::Dict lacros_dict = ash_dict.Clone();
+
+  UpdatePreferencesKeyByType(&ash_dict, "extensions.settings",
+                             ChromeType::kAsh);
+  UpdatePreferencesKeyByType(&lacros_dict, "extensions.settings",
+                             ChromeType::kLacros);
+
+  // Test Ash against expected results.
+  base::Value::Dict* d = ash_dict.FindDictByDottedPath("extensions.settings");
+  EXPECT_NE(nullptr, d);
+  EXPECT_EQ(1, d->size());
+  EXPECT_EQ(kExtensionsAshOnly[0], d->begin()->first);
+  // If a type other than string is found in a list, it will be left unchanged.
+  base::Value::List* l = ash_dict.FindListByDottedPath(wrong_type_key);
+  EXPECT_NE(nullptr, l);
+  EXPECT_EQ(2, l->size());
+
+  // Test Lacros against expected results.
+  d = lacros_dict.FindDictByDottedPath("extensions.settings");
+  EXPECT_NE(nullptr, d);
+  EXPECT_EQ(1, d->size());
+  EXPECT_EQ(kMoveExtensionId, d->begin()->first);
+  l = lacros_dict.FindListByDottedPath(wrong_type_key);
+  EXPECT_NE(nullptr, l);
+  EXPECT_EQ(2, l->size());
+}
+
+TEST(BrowserDataMigratorUtilTest, MigratePreferencesContents) {
+  const std::string keep_extension_dict_key =
+      std::string("extensions.settings.") + kExtensionsAshOnly[0];
+  const std::string move_extension_dict_key =
+      std::string("extensions.settings.") + kMoveExtensionId;
+
+  base::Value::List extension_list;
+  extension_list.Append(kExtensionsAshOnly[0]);
+  extension_list.Append(kMoveExtensionId);
+  const std::string extension_list_key = "extensions.pinned_extensions";
+
   std::string original_contents;
   base::Value::Dict dict;
   dict.SetByDottedPath(kLacrosOnlyPreferencesKeys[0], "test1");
   dict.SetByDottedPath(kAshOnlyPreferencesKeys[0], "test2");
   dict.SetByDottedPath("unrelated.key", "test3");
-  dict.SetByDottedPath(keep_extension_key, "test4");
-  dict.SetByDottedPath(move_extension_key, "test5");
+  dict.SetByDottedPath(keep_extension_dict_key, "test4");
+  dict.SetByDottedPath(move_extension_dict_key, "test5");
+  dict.SetByDottedPath(extension_list_key, std::move(extension_list));
   base::JSONWriter::Write(dict, &original_contents);
 
   auto contents = MigratePreferencesContents(original_contents);
@@ -674,8 +737,14 @@
             *ash_root_dict->FindStringByDottedPath(kAshOnlyPreferencesKeys[0]));
   EXPECT_EQ("test3", *ash_root_dict->FindStringByDottedPath("unrelated.key"));
   EXPECT_EQ("test4",
-            *ash_root_dict->FindStringByDottedPath(keep_extension_key));
-  EXPECT_EQ(nullptr, ash_root_dict->FindStringByDottedPath(move_extension_key));
+            *ash_root_dict->FindStringByDottedPath(keep_extension_dict_key));
+  EXPECT_EQ(nullptr,
+            ash_root_dict->FindStringByDottedPath(move_extension_dict_key));
+  base::Value::List* ash_extension_list =
+      ash_root_dict->FindListByDottedPath(extension_list_key);
+  EXPECT_NE(nullptr, ash_extension_list);
+  EXPECT_EQ(1, ash_extension_list->size());
+  EXPECT_EQ(kExtensionsAshOnly[0], ash_extension_list->front().GetString());
 
   absl::optional<base::Value> lacros_root =
       base::JSONReader::Read(contents->lacros);
@@ -689,9 +758,14 @@
   EXPECT_EQ("test3",
             *lacros_root_dict->FindStringByDottedPath("unrelated.key"));
   EXPECT_EQ(nullptr,
-            lacros_root_dict->FindStringByDottedPath(keep_extension_key));
+            lacros_root_dict->FindStringByDottedPath(keep_extension_dict_key));
   EXPECT_EQ("test5",
-            *lacros_root_dict->FindStringByDottedPath(move_extension_key));
+            *lacros_root_dict->FindStringByDottedPath(move_extension_dict_key));
+  base::Value::List* lacros_extension_list =
+      lacros_root_dict->FindListByDottedPath(extension_list_key);
+  EXPECT_NE(nullptr, lacros_extension_list);
+  EXPECT_EQ(1, lacros_extension_list->size());
+  EXPECT_EQ(kMoveExtensionId, lacros_extension_list->front().GetString());
 }
 
 TEST(BrowserDataMigratorUtilTest, MigratePreferences) {
diff --git a/chrome/browser/ash/crosapi/move_migrator.cc b/chrome/browser/ash/crosapi/move_migrator.cc
index 1eef81e7..1d9c3744 100644
--- a/chrome/browser/ash/crosapi/move_migrator.cc
+++ b/chrome/browser/ash/crosapi/move_migrator.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/crosapi/move_migrator.h"
 
+#include <errno.h>
+
 #include <memory>
 #include <string>
 
@@ -14,8 +16,12 @@
 #include "base/files/file_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "base/timer/elapsed_timer.h"
 #include "base/values.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator_util.h"
@@ -53,6 +59,13 @@
   if (IsResumeStep(resume_step)) {
     const int resume_count =
         UpdateResumeAttemptCountForUser(local_state_, user_id_hash_);
+
+    if (resume_count > 0) {
+      LOG(WARNING) << "Resuming move migration for the " << resume_count
+                   << "th time.";
+      UMA_HISTOGRAM_COUNTS_100(kMoveMigratorResumeCount, resume_count);
+    }
+
     if (resume_count > kMoveMigrationResumeCountLimit) {
       LOG(ERROR) << "The number of resume attempt limit has reached. Marking "
                     "move migration as completed.";
@@ -62,6 +75,7 @@
   }
 
   // Start or resume migration.
+  UMA_HISTOGRAM_ENUMERATION(kMoveMigratorResumeStepUMA, resume_step);
   switch (resume_step) {
     case ResumeStep::kStart:
       base::ThreadPool::PostTaskAndReplyWithResult(
@@ -113,9 +127,7 @@
       LOG(ERROR)
           << "This state indicates that migration was marked as completed by"
              "`MoveMigrator` but was not by `BrowserDataMigratorImpl`";
-      std::move(finished_callback_)
-          .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-                {BrowserDataMigrator::ResultKind::kSucceeded}});
+      InvokeCallback({TaskStatus::kSucceeded});
       return;
   }
 }
@@ -201,9 +213,10 @@
 }
 
 // static
-MoveMigrator::PreMigrationCleanUpResult MoveMigrator::PreMigrationCleanUp(
+MoveMigrator::TaskResult MoveMigrator::PreMigrationCleanUp(
     const base::FilePath& original_profile_dir) {
   LOG(WARNING) << "Running PreMigrationCleanUp()";
+  base::ElapsedTimer timer;
 
   const base::FilePath new_user_dir =
       original_profile_dir.Append(browser_data_migrator_util::kLacrosDir);
@@ -212,7 +225,7 @@
     // Delete an existing lacros profile before the migration.
     if (!base::DeletePathRecursively(new_user_dir)) {
       PLOG(ERROR) << "Deleting " << new_user_dir.value() << " failed: ";
-      return {false};
+      return {TaskStatus::kPreMigrationCleanUpDeleteLacrosDirFailed, errno};
     }
   }
 
@@ -226,7 +239,7 @@
     // tmp_user_dir once we start deleting items from the Ash PDD.
     if (!base::DeletePathRecursively(tmp_user_dir)) {
       PLOG(ERROR) << "Deleting " << tmp_user_dir.value() << " failed: ";
-      return {false};
+      return {TaskStatus::kPreMigrationCleanUpDeleteTmpDirFailed, errno};
     }
   }
 
@@ -237,7 +250,7 @@
     // migration attempt. Similar considerations to tmp_user_dir apply.
     if (!base::DeletePathRecursively(tmp_split_dir)) {
       PLOG(ERROR) << "Deleting" << tmp_split_dir.value() << " failed: ";
-      return {false};
+      return {TaskStatus::kPreMigrationCleanUpDeleteTmpSplitDirFailed, errno};
     }
   }
 
@@ -267,28 +280,27 @@
       browser_data_migrator_util::ExtraBytesRequiredToBeFreed(
           need_copy_items.total_size, original_profile_dir);
 
-  return {true, extra_bytes_required_to_be_freed};
-}
-
-void MoveMigrator::OnPreMigrationCleanUp(
-    MoveMigrator::PreMigrationCleanUpResult result) {
-  if (!result.success) {
-    LOG(ERROR) << "PreMigrationCleanup() failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kFailed,
-              {BrowserDataMigrator::ResultKind::kFailed}});
-    return;
-  }
-
-  if (result.extra_bytes_required_to_be_freed.value() > 0u) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorPreMigrationCleanUpTimeUMA,
+                             timer.Elapsed());
+  if (extra_bytes_required_to_be_freed > 0u) {
+    UMA_HISTOGRAM_CUSTOM_COUNTS(kMoveMigratorExtraSpaceRequiredMB,
+                                extra_bytes_required_to_be_freed / 1024 / 1024,
+                                1, 10000, 100);
     LOG(ERROR) << "Not enough disk space available to carry out the migration "
                   "safely. Need to free up "
-               << result.extra_bytes_required_to_be_freed.value()
-               << " bytes from " << original_profile_dir_.value();
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kFailed,
-              {BrowserDataMigratorImpl::ResultKind::kFailed,
-               result.extra_bytes_required_to_be_freed}});
+               << extra_bytes_required_to_be_freed << " bytes from "
+               << original_profile_dir;
+    return {TaskStatus::kPreMigrationCleanUpNotEnoughSpace, absl::nullopt,
+            extra_bytes_required_to_be_freed};
+  }
+
+  return {TaskStatus::kSucceeded};
+}
+
+void MoveMigrator::OnPreMigrationCleanUp(MoveMigrator::TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
+    LOG(ERROR) << "PreMigrationCleanup() failed.";
+    InvokeCallback(result);
     return;
   }
 
@@ -303,15 +315,16 @@
 }
 
 // static
-bool MoveMigrator::SetupLacrosDir(
+MoveMigrator::TaskResult MoveMigrator::SetupLacrosDir(
     const base::FilePath& original_profile_dir,
     std::unique_ptr<MigrationProgressTracker> progress_tracker,
     scoped_refptr<browser_data_migrator_util::CancelFlag> cancel_flag) {
   LOG(WARNING) << "Running SetupLacrosDir()";
+  base::ElapsedTimer timer;
 
   if (cancel_flag->IsSet()) {
     LOG(WARNING) << "Migration is cancelled.";
-    return false;
+    return {TaskStatus::kCancelled};
   }
   const base::FilePath tmp_user_dir =
       original_profile_dir.Append(browser_data_migrator_util::kMoveTmpDir);
@@ -320,11 +333,11 @@
 
   if (!base::CreateDirectory(tmp_user_dir)) {
     PLOG(ERROR) << "CreateDirectory() failed for  " << tmp_user_dir.value();
-    return false;
+    return {TaskStatus::kSetupLacrosDirCreateTmpDirFailed, errno};
   }
   if (!base::CreateDirectory(tmp_profile_dir)) {
     PLOG(ERROR) << "CreateDirectory() failed for  " << tmp_profile_dir.value();
-    return false;
+    return {TaskStatus::kSetupLacrosDirCreateTmpProfileDirFailed, errno};
   }
 
   browser_data_migrator_util::TargetItems need_copy_items =
@@ -334,27 +347,35 @@
 
   progress_tracker->SetTotalSizeToCopy(need_copy_items.total_size);
 
+  base::ElapsedTimer timer_for_copy;
   if (!browser_data_migrator_util::CopyTargetItems(
           tmp_profile_dir, need_copy_items, cancel_flag.get(),
           progress_tracker.get())) {
+    if (cancel_flag->IsSet()) {
+      return {TaskStatus::kCancelled};
+    }
     LOG(ERROR) << "CopyTargetItems() failed for need_copy_items.";
-    return false;
+    return {TaskStatus::kSetupLacrosDirCopyTargetItemsFailed, errno};
   }
+  UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorSetupLacrosDirCopyTargetItemsTimeUMA,
+                             timer_for_copy.Elapsed());
 
   if (!base::WriteFile(tmp_user_dir.Append(chrome::kFirstRunSentinel), "")) {
     LOG(ERROR) << "WriteFile() failed for " << chrome::kFirstRunSentinel;
-    return false;
+    return {TaskStatus::kSetupLacrosDirWriteFirstRunSentinelFileFailed, errno};
   }
 
-  return true;
+  return {TaskStatus::kSucceeded};
 }
 
-void MoveMigrator::OnSetupLacrosDir(bool success) {
-  if (!success) {
+void MoveMigrator::OnSetupLacrosDir(TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
     LOG(ERROR) << "MoveMigrator::SetupLacrosDir() failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-              {BrowserDataMigrator::ResultKind::kFailed}});
+    if (cancel_flag_->IsSet()) {
+      UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorCancelledMigrationTimeUMA,
+                                 timer_.Elapsed());
+    }
+    InvokeCallback(result);
     return;
   }
 
@@ -368,7 +389,7 @@
 }
 
 // static
-bool MoveMigrator::SetupAshSplitDir(
+MoveMigrator::TaskResult MoveMigrator::SetupAshSplitDir(
     const base::FilePath& original_profile_dir) {
   LOG(WARNING) << "Running SetupAshSplitDir()";
 
@@ -380,7 +401,7 @@
       original_profile_dir.Append(browser_data_migrator_util::kSplitTmpDir);
   if (!base::CreateDirectory(tmp_split_dir)) {
     PLOG(ERROR) << "CreateDirectory() failed for  " << tmp_split_dir.value();
-    return false;
+    return {TaskStatus::kSetupAshDirCreateSplitDirFailed, errno};
   }
 
   // Create Ash's version of `Local Storage`, holding *only* the keys
@@ -398,7 +419,7 @@
                 .Append(browser_data_migrator_util::kLocalStorageLeveldbName),
             browser_data_migrator_util::LevelDBType::kLocalStorage)) {
       LOG(ERROR) << "MigrateLevelDB() failed for `Local Storage`";
-      return false;
+      return {TaskStatus::kSetupAshDirMigrateLevelDBForLocalStateFailed};
     }
   }
 
@@ -409,7 +430,7 @@
               original_profile_dir.Append(path), tmp_split_dir.Append(path),
               browser_data_migrator_util::LevelDBType::kStateStore)) {
         LOG(ERROR) << "MigrateLevelDB() failed for `" << path << "`";
-        return false;
+        return {TaskStatus::kSetupAshDirMigrateLevelDBForStateFailed};
       }
     }
   }
@@ -420,18 +441,16 @@
           tmp_split_dir.Append(chrome::kPreferencesFilename),
           tmp_profile_dir.Append(chrome::kPreferencesFilename))) {
     LOG(ERROR) << "MigratePreferences() failed.";
-    return false;
+    return {TaskStatus::kSetupAshDirMigratePreferencesFailed};
   }
 
-  return true;
+  return {TaskStatus::kSucceeded};
 }
 
-void MoveMigrator::OnSetupAshSplitDir(bool success) {
-  if (!success) {
+void MoveMigrator::OnSetupAshSplitDir(TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
     LOG(ERROR) << "MoveMigrator::SetupAshSplitDir() failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-              {BrowserDataMigratorImpl::ResultKind::kFailed}});
+    InvokeCallback(result);
     return;
   }
 
@@ -453,21 +472,22 @@
 }
 
 // static
-bool MoveMigrator::MoveLacrosItemsToNewDir(
+MoveMigrator::TaskResult MoveMigrator::MoveLacrosItemsToNewDir(
     const base::FilePath& original_profile_dir) {
   LOG(WARNING) << "Running MoveLacrosItemsToNewDir()";
 
+  base::ElapsedTimer timer;
+
   browser_data_migrator_util::TargetItems lacros_items =
       browser_data_migrator_util::GetTargetItems(
           original_profile_dir, browser_data_migrator_util::ItemType::kLacros);
 
   for (const auto& item : lacros_items.items) {
     if (item.is_directory && !base::PathIsWritable(item.path)) {
-      // TODO(ythjkt): Add a UMA.
       PLOG(ERROR) << "The current process does not have write permission to "
                      "the directory "
                   << item.path.value();
-      return false;
+      return {TaskStatus::kMoveLacrosItemsToNewDirNoWritePerm, errno};
     }
   }
 
@@ -479,18 +499,19 @@
     if (!base::Move(item.path, tmp_profile_dir.Append(item.path.BaseName()))) {
       PLOG(ERROR) << "Failed to move item " << item.path.value() << " to "
                   << tmp_profile_dir.Append(item.path.BaseName()) << ": ";
-      return false;
+      return {TaskStatus::kMoveLacrosItemsToNewDirMoveFailed, errno};
     }
   }
-  return true;
+
+  UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorMoveLacrosItemsTimeUMA,
+                             timer.Elapsed());
+  return {TaskStatus::kSucceeded};
 }
 
-void MoveMigrator::OnMoveLacrosItemsToNewDir(bool success) {
-  if (!success) {
+void MoveMigrator::OnMoveLacrosItemsToNewDir(TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
     LOG(ERROR) << "Moving Lacros items to temporary directory failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-              {BrowserDataMigrator::ResultKind::kFailed}});
+    InvokeCallback(result);
     return;
   }
 
@@ -507,7 +528,7 @@
 }
 
 // static
-bool MoveMigrator::MoveSplitItemsToOriginalDir(
+MoveMigrator::TaskResult MoveMigrator::MoveSplitItemsToOriginalDir(
     const base::FilePath& original_profile_dir) {
   LOG(WARNING) << "Running MoveSplitItemsToOriginalDir()";
 
@@ -527,7 +548,8 @@
     if (!base::Move(path, ash_path)) {
       PLOG(ERROR) << "Failed moving " << path.value() << " to "
                   << ash_path.value();
-      return false;
+      return {TaskStatus::kMoveSplitItemsToOriginalDirMoveSplitItemsFailed,
+              errno};
     }
   }
 
@@ -545,7 +567,7 @@
     if (!base::CreateDirectory(ash_extensions_dir)) {
       PLOG(ERROR) << "CreateDirectory() failed for  "
                   << ash_extensions_dir.value();
-      return false;
+      return {TaskStatus::kMoveSplitItemsToOriginalDirCreateDirFailed, errno};
     }
 
     for (const char* extension_id :
@@ -556,7 +578,8 @@
         if (!base::Move(lacros_path, ash_path)) {
           PLOG(ERROR) << "Failed moving " << lacros_path.value() << " to "
                       << ash_path.value();
-          return false;
+          return {TaskStatus::kMoveSplitItemsToOriginalDirMoveExtensionsFailed,
+                  errno};
         }
       }
     }
@@ -572,7 +595,7 @@
     if (!base::CreateDirectory(ash_indexed_db_dir)) {
       PLOG(ERROR) << "CreateDirectory() failed for  "
                   << ash_indexed_db_dir.value();
-      return false;
+      return {TaskStatus::kMoveSplitItemsToOriginalDirCreateDirFailed, errno};
     }
 
     for (const char* extension_id :
@@ -586,7 +609,8 @@
         if (!base::Move(blob_path, ash_blob_path)) {
           PLOG(ERROR) << "Failed moving " << blob_path.value() << " to "
                       << ash_blob_path.value();
-          return false;
+          return {TaskStatus::kMoveSplitItemsToOriginalDirMoveIndexedDBFailed,
+                  errno};
         }
       }
       if (base::PathExists(leveldb_path)) {
@@ -595,21 +619,20 @@
         if (!base::Move(leveldb_path, ash_indexed_db_dir)) {
           PLOG(ERROR) << "Failed moving " << leveldb_path.value() << " to "
                       << ash_leveldb_path.value();
-          return false;
+          return {TaskStatus::kMoveSplitItemsToOriginalDirMoveIndexedDBFailed,
+                  errno};
         }
       }
     }
   }
 
-  return true;
+  return {TaskStatus::kSucceeded};
 }
 
-void MoveMigrator::OnMoveSplitItemsToOriginalDir(bool success) {
-  if (!success) {
+void MoveMigrator::OnMoveSplitItemsToOriginalDir(TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
     LOG(ERROR) << "Moving split objects has failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-              {BrowserDataMigratorImpl::ResultKind::kFailed}});
+    InvokeCallback(result);
     return;
   }
 
@@ -626,7 +649,7 @@
 }
 
 // static
-bool MoveMigrator::MoveTmpDirToLacrosDir(
+MoveMigrator::TaskResult MoveMigrator::MoveTmpDirToLacrosDir(
     const base::FilePath& original_profile_dir) {
   LOG(WARNING) << "Running MoveTmpDirToLacrosDir()";
 
@@ -644,27 +667,116 @@
                 << original_profile_dir
                        .Append(browser_data_migrator_util::kLacrosDir)
                        .value();
-    return false;
+    return {TaskStatus::kMoveTmpDirToLacrosDirMoveFailed, errno};
   }
 
-  return true;
+  return {TaskStatus::kSucceeded};
 }
 
-void MoveMigrator::OnMoveTmpDirToLacrosDir(bool success) {
-  if (!success) {
+void MoveMigrator::OnMoveTmpDirToLacrosDir(TaskResult result) {
+  if (result.status != TaskStatus::kSucceeded) {
     LOG(ERROR) << "Moving tmp dir to lacros dir failed.";
-    std::move(finished_callback_)
-        .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-              {BrowserDataMigrator::ResultKind::kFailed}});
+    InvokeCallback(result);
     return;
   }
 
+  UMA_HISTOGRAM_MEDIUM_TIMES(kMoveMigratorSuccessfulMigrationTimeUMA,
+                             timer_.Elapsed());
   SetResumeStep(local_state_, user_id_hash_, ResumeStep::kCompleted);
 
   LOG(WARNING) << "Move migration completed successfully.";
+  InvokeCallback(result);
+}
+
+void MoveMigrator::InvokeCallback(TaskResult result) {
+  UMA_HISTOGRAM_ENUMERATION(kMoveMigratorTaskStatusUMA, result.status);
+  if (result.status != TaskStatus::kSucceeded &&
+      result.posix_errno.has_value()) {
+    RecordPosixErrnoUMA(result.status, result.posix_errno.value());
+  }
+
   std::move(finished_callback_)
-      .Run({BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
-            {BrowserDataMigratorImpl::ResultKind::kSucceeded}});
+      .Run(ToBrowserDataMigratorMigrationResult(result));
+}
+
+BrowserDataMigratorImpl::MigrationResult
+MoveMigrator::ToBrowserDataMigratorMigrationResult(TaskResult result) {
+  switch (result.status) {
+    case TaskStatus::kSucceeded:
+      return {BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
+              {BrowserDataMigratorImpl::ResultKind::kSucceeded}};
+    case TaskStatus::kCancelled:
+      return {BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
+              {BrowserDataMigratorImpl::ResultKind::kSkipped}};
+    case TaskStatus::kPreMigrationCleanUpDeleteLacrosDirFailed:
+    case TaskStatus::kPreMigrationCleanUpDeleteTmpDirFailed:
+    case TaskStatus::kPreMigrationCleanUpDeleteTmpSplitDirFailed:
+      return {BrowserDataMigratorImpl::DataWipeResult::kFailed,
+              {BrowserDataMigratorImpl::ResultKind::kFailed}};
+    case TaskStatus::kPreMigrationCleanUpNotEnoughSpace:
+      return {BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
+              {BrowserDataMigratorImpl::ResultKind::kFailed,
+               result.extra_bytes_required_to_be_freed.value()}};
+    case TaskStatus::kSetupLacrosDirCreateTmpDirFailed:
+    case TaskStatus::kSetupLacrosDirCreateTmpProfileDirFailed:
+    case TaskStatus::kSetupLacrosDirCopyTargetItemsFailed:
+    case TaskStatus::kSetupLacrosDirWriteFirstRunSentinelFileFailed:
+    case TaskStatus::kSetupAshDirCreateSplitDirFailed:
+    case TaskStatus::kSetupAshDirMigrateLevelDBForLocalStateFailed:
+    case TaskStatus::kSetupAshDirMigrateLevelDBForStateFailed:
+    case TaskStatus::kSetupAshDirMigratePreferencesFailed:
+    case TaskStatus::kMoveLacrosItemsToNewDirNoWritePerm:
+    case TaskStatus::kMoveLacrosItemsToNewDirMoveFailed:
+    case TaskStatus::kMoveSplitItemsToOriginalDirMoveSplitItemsFailed:
+    case TaskStatus::kMoveSplitItemsToOriginalDirCreateDirFailed:
+    case TaskStatus::kMoveSplitItemsToOriginalDirMoveExtensionsFailed:
+    case TaskStatus::kMoveSplitItemsToOriginalDirMoveIndexedDBFailed:
+    case TaskStatus::kMoveTmpDirToLacrosDirMoveFailed:
+      return {BrowserDataMigratorImpl::DataWipeResult::kSucceeded,
+              {BrowserDataMigratorImpl::ResultKind::kFailed}};
+  }
+}
+
+// static
+void MoveMigrator::RecordPosixErrnoUMA(TaskStatus task_status,
+                                       const int posix_errno) {
+  if (posix_errno == 0)
+    return;
+
+  std::string uma_name =
+      kMoveMigratorPosixErrnoUMA + TaskStatusToString(task_status);
+  base::UmaHistogramSparse(uma_name, posix_errno);
+}
+
+// static
+std::string MoveMigrator::TaskStatusToString(TaskStatus task_status) {
+  switch (task_status) {
+#define MAPPING(name)       \
+  case TaskStatus::k##name: \
+    return #name
+    MAPPING(Succeeded);
+    MAPPING(Cancelled);
+    MAPPING(PreMigrationCleanUpDeleteLacrosDirFailed);
+    MAPPING(PreMigrationCleanUpDeleteTmpDirFailed);
+    MAPPING(PreMigrationCleanUpDeleteTmpSplitDirFailed);
+    MAPPING(PreMigrationCleanUpNotEnoughSpace);
+    MAPPING(SetupLacrosDirCreateTmpDirFailed);
+    MAPPING(SetupLacrosDirCreateTmpProfileDirFailed);
+    MAPPING(SetupLacrosDirCopyTargetItemsFailed);
+    MAPPING(SetupLacrosDirWriteFirstRunSentinelFileFailed);
+    MAPPING(SetupAshDirCreateSplitDirFailed);
+    MAPPING(SetupAshDirMigrateLevelDBForLocalStateFailed);
+    MAPPING(SetupAshDirMigrateLevelDBForStateFailed);
+    MAPPING(SetupAshDirMigratePreferencesFailed);
+    MAPPING(MoveLacrosItemsToNewDirNoWritePerm);
+    MAPPING(MoveLacrosItemsToNewDirMoveFailed);
+    MAPPING(MoveSplitItemsToOriginalDirMoveSplitItemsFailed);
+    MAPPING(MoveSplitItemsToOriginalDirCreateDirFailed);
+    MAPPING(MoveSplitItemsToOriginalDirMoveExtensionsFailed);
+    MAPPING(MoveSplitItemsToOriginalDirMoveIndexedDBFailed);
+    MAPPING(MoveTmpDirToLacrosDirMoveFailed);
+#undef MAPPING
+  }
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/crosapi/move_migrator.h b/chrome/browser/ash/crosapi/move_migrator.h
index 12a6e246..d2cf53a 100644
--- a/chrome/browser/ash/crosapi/move_migrator.h
+++ b/chrome/browser/ash/crosapi/move_migrator.h
@@ -13,6 +13,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/timer/elapsed_timer.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator_util.h"
 #include "chrome/browser/ash/crosapi/migration_progress_tracker.h"
@@ -40,6 +41,28 @@
 // completing the migration.
 constexpr int kMoveMigrationResumeCountLimit = 5;
 
+// The following are UMA names.
+constexpr char kMoveMigratorResumeCount[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.ResumeCount";
+constexpr char kMoveMigratorResumeStepUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.ResumeStep";
+constexpr char kMoveMigratorTaskStatusUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.TaskStatus";
+constexpr char kMoveMigratorExtraSpaceRequiredMB[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.ExtraSpaceRequiredMB";
+constexpr char kMoveMigratorPreMigrationCleanUpTimeUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.PreMigrationCleanUpTimeMS";
+constexpr char kMoveMigratorSetupLacrosDirCopyTargetItemsTimeUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.SetupLacrosDirCopyTargetItemsTimeMS";
+constexpr char kMoveMigratorCancelledMigrationTimeUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.CancelledMigrationTimeMS";
+constexpr char kMoveMigratorSuccessfulMigrationTimeUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.SuccessfulMigrationTimeMS";
+constexpr char kMoveMigratorMoveLacrosItemsTimeUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.MoveLacrosItemsTimeMS";
+constexpr char kMoveMigratorPosixErrnoUMA[] =
+    "Ash.BrowserDataMigrator.MoveMigrator.PosixErrno.";
+
 // 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
 // forward, to the new profile data directory
@@ -56,6 +79,9 @@
 // 6) Rename <Ash PDD>/<kMoveTmpDir>/ as <Ash PDD>/lacros/.
 class MoveMigrator : public BrowserDataMigratorImpl::MigratorDelegate {
  public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  //
   // Indicate which step the migration should be resumed from if left unfinished
   // in the previous attempt.
   enum class ResumeStep {
@@ -64,17 +90,7 @@
     kMoveSplitItems = 2,
     kMoveTmpDir = 3,
     kCompleted = 4,
-  };
-
-  // Return value of `PreMigrationCleanUp()`.
-  struct PreMigrationCleanUpResult {
-    // Whether cleanup has succeeded or not.
-    bool success;
-
-    // Extra bytes required to be freed if the migrator requires more space to
-    // be carried out. Only set if `success` is true. This value is set to 0 if
-    // no freeing up of disk is required.
-    absl::optional<uint64_t> extra_bytes_required_to_be_freed;
+    kMaxValue = kCompleted,
   };
 
   MoveMigrator(
@@ -116,6 +132,7 @@
       MoveMigratorTest,
       MoveLacrosItemsToNewDirFailIfNoWritePermForLacrosItem);
   FRIEND_TEST_ALL_PREFIXES(MoveMigratorTest, MoveLacrosItemsToNewDir);
+  FRIEND_TEST_ALL_PREFIXES(MoveMigratorTest, RecordPosixErrnoUMA);
   FRIEND_TEST_ALL_PREFIXES(MoveMigratorMigrateTest,
                            MigrateResumeFromMoveLacrosItems);
   FRIEND_TEST_ALL_PREFIXES(MoveMigratorMigrateTest,
@@ -125,6 +142,48 @@
   friend class BrowserDataMigratorResumeOnSignInTest;
   friend class BrowserDataMigratorResumeRestartInSession;
 
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  //
+  // This enum corresponds to MoveMigratorTaskStatus in histograms.xml
+  // and enums.xml.
+  enum class TaskStatus {
+    kSucceeded = 0,
+    kCancelled = 1,
+    kPreMigrationCleanUpDeleteLacrosDirFailed = 2,
+    kPreMigrationCleanUpDeleteTmpDirFailed = 3,
+    kPreMigrationCleanUpDeleteTmpSplitDirFailed = 4,
+    kPreMigrationCleanUpNotEnoughSpace = 5,
+    kSetupLacrosDirCreateTmpDirFailed = 6,
+    kSetupLacrosDirCreateTmpProfileDirFailed = 7,
+    kSetupLacrosDirCopyTargetItemsFailed = 8,
+    kSetupLacrosDirWriteFirstRunSentinelFileFailed = 9,
+    kSetupAshDirCreateSplitDirFailed = 10,
+    kSetupAshDirMigrateLevelDBForLocalStateFailed = 11,
+    kSetupAshDirMigrateLevelDBForStateFailed = 12,
+    kSetupAshDirMigratePreferencesFailed = 13,
+    kMoveLacrosItemsToNewDirNoWritePerm = 14,
+    kMoveLacrosItemsToNewDirMoveFailed = 15,
+    kMoveSplitItemsToOriginalDirMoveSplitItemsFailed = 16,
+    kMoveSplitItemsToOriginalDirCreateDirFailed = 17,
+    kMoveSplitItemsToOriginalDirMoveExtensionsFailed = 18,
+    kMoveSplitItemsToOriginalDirMoveIndexedDBFailed = 19,
+    kMoveTmpDirToLacrosDirMoveFailed = 20,
+    kMaxValue = kMoveTmpDirToLacrosDirMoveFailed,
+  };
+
+  struct TaskResult {
+    TaskStatus status;
+
+    // Value of `errno` set after a task has failed.
+    absl::optional<int> posix_errno;
+
+    // Extra bytes required to be freed if the migrator requires more space to
+    // be carried out. Only set if `status` is
+    // `kPreMigrationCleanUpNotEnoughSpace`.
+    absl::optional<uint64_t> extra_bytes_required_to_be_freed;
+  };
+
   // Called to determine where to start the migration. Returns
   // `ResumeStep::kStart` unless there is a step recorded in `Local State` from
   // the previous migration i.e. the previous migration did not complete and
@@ -155,53 +214,73 @@
   // `PreMigrationCleanUpResult::extra_bytes_required_to_be_freed`. It also
   // deletes `ItemType::kDeletable` items to free up extra space but this does
   // not affect `PreMigrationCleanUpResult::success`.
-  static PreMigrationCleanUpResult PreMigrationCleanUp(
+  static TaskResult PreMigrationCleanUp(
       const base::FilePath& original_profile_dir);
 
   // Called as a reply to `PreMigrationCleanUp()`.  Posts
   // `SetupLacrosRemoveHardLinksFromAshDir()` as the next step.
-  void OnPreMigrationCleanUp(PreMigrationCleanUpResult);
+  void OnPreMigrationCleanUp(TaskResult);
 
   // Set up lacros user directory by copying `ItemType::kNeedCopy` items
   // and also creating `First Run` file in Lacros user data dir.
-  static bool SetupLacrosDir(
+  static TaskResult SetupLacrosDir(
       const base::FilePath& original_profile_dir,
       std::unique_ptr<MigrationProgressTracker> progress_tracker,
       scoped_refptr<browser_data_migrator_util::CancelFlag> cancel_flag);
 
   // Called as a reply to `SetupLacrosDir()`. Posts
   // `SetupAshSplitDir()` as the next step.
-  void OnSetupLacrosDir(bool success);
+  void OnSetupLacrosDir(TaskResult);
 
   // 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 bool SetupAshSplitDir(const base::FilePath& original_profile_dir);
+  static TaskResult SetupAshSplitDir(
+      const base::FilePath& original_profile_dir);
 
   // Called as a reply to `SetupAshSplitDir()`. Posts `MoveLacrosItemsToNewDir`
   // as the next step.
-  void OnSetupAshSplitDir(bool success);
+  void OnSetupAshSplitDir(TaskResult);
 
   // Move `ItemType::kLacros` in the original profile
   // directory to the temp dir.
-  static bool MoveLacrosItemsToNewDir(
+  static TaskResult MoveLacrosItemsToNewDir(
       const base::FilePath& original_profile_dir);
 
   // Called as a reply to `MoveLacrosItemsToNewDir()`.
-  void OnMoveLacrosItemsToNewDir(bool success);
+  void OnMoveLacrosItemsToNewDir(TaskResult);
 
   // Moves newly created split items to the original profile directory.
-  static bool MoveSplitItemsToOriginalDir(
+  static TaskResult MoveSplitItemsToOriginalDir(
       const base::FilePath& original_profile_dir);
 
   // Called as a reply to `MoveSplitItemsToOriginalDir`.
-  void OnMoveSplitItemsToOriginalDir(bool success);
+  void OnMoveSplitItemsToOriginalDir(TaskResult);
 
   // Moves newly created `kMoveTmpDir` to `kLacrosDir`.
   // Completes the migration.
-  static bool MoveTmpDirToLacrosDir(const base::FilePath& original_profile_dir);
+  static TaskResult MoveTmpDirToLacrosDir(
+      const base::FilePath& original_profile_dir);
 
   // Called as a reply to `MoveTmpDirToLacrosDir()`.
-  void OnMoveTmpDirToLacrosDir(bool success);
+  void OnMoveTmpDirToLacrosDir(TaskResult);
+
+  // Records the final status of the migration in `kMoveMigratorTaskStatusUMA`
+  // and calls `finished_callback_`. This function gets called once regardless
+  // of whether the migration succeeded or not.
+  void InvokeCallback(TaskResult);
+
+  // Converts `TaskResult` to `BrowserDataMigratorImpl::MigrationResult`.
+  BrowserDataMigratorImpl::MigrationResult ToBrowserDataMigratorMigrationResult(
+      TaskResult result);
+
+  // Record UMA of the form
+  // "Ash.BrowserDataMigrator.MoveMigrator.PosixErrno.{task_status}" with the
+  // value of `errno`.
+  static void RecordPosixErrnoUMA(TaskStatus task_status,
+                                  const int posix_errno);
+
+  // Convert `TaskStatus` to string.
+  static std::string TaskStatusToString(TaskStatus task_status);
 
   // Path to the original profile data directory, which is directly under the
   // user data directory.
@@ -224,6 +303,10 @@
   // Call this on UI thread.
   MigrationFinishedCallback finished_callback_;
 
+  // Timer to count time since the initialization of the class. Used to get UMA
+  // data on how long the migration takes.
+  const base::ElapsedTimer timer_;
+
   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 8b06055..fc8cc9b 100644
--- a/chrome/browser/ash/crosapi/move_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/move_migrator_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/crosapi/move_migrator.h"
 
+#include <errno.h>
+
 #include <map>
 #include <memory>
 #include <string>
@@ -19,6 +21,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator.h"
 #include "chrome/browser/ash/crosapi/browser_data_migrator_util.h"
@@ -281,10 +284,10 @@
   const base::FilePath original_profile_dir_1 =
       scoped_temp_dir.GetPath().Append("user1");
   EXPECT_TRUE(base::CreateDirectory(original_profile_dir_1));
-  MoveMigrator::PreMigrationCleanUpResult result_1 =
+  MoveMigrator::TaskResult result_1 =
       MoveMigrator::PreMigrationCleanUp(original_profile_dir_1);
-  ASSERT_TRUE(result_1.success);
-  EXPECT_EQ(result_1.extra_bytes_required_to_be_freed, 0u);
+  ASSERT_EQ(result_1.status, MoveMigrator::TaskStatus::kSucceeded);
+  EXPECT_FALSE(result_1.extra_bytes_required_to_be_freed.has_value());
 
   // `PreMigrationCleanUp()` deletes any `.../lacros/` directory and returns
   // true.
@@ -298,10 +301,10 @@
                                 .Append(chrome::kFirstRunSentinel),
                             "", 0),
             0);
-  MoveMigrator::PreMigrationCleanUpResult result_2 =
+  MoveMigrator::TaskResult result_2 =
       MoveMigrator::PreMigrationCleanUp(original_profile_dir_2);
-  ASSERT_TRUE(result_2.success);
-  EXPECT_EQ(result_2.extra_bytes_required_to_be_freed, 0u);
+  ASSERT_EQ(result_2.status, MoveMigrator::TaskStatus::kSucceeded);
+  EXPECT_FALSE(result_2.extra_bytes_required_to_be_freed.has_value());
   EXPECT_FALSE(base::PathExists(
       original_profile_dir_2.Append(browser_data_migrator_util::kLacrosDir)));
 
@@ -312,10 +315,10 @@
   ASSERT_EQ(base::WriteFile(original_profile_dir_3.Append(kCacheFilePath),
                             kDataContent, kDataSize),
             kDataSize);
-  MoveMigrator::PreMigrationCleanUpResult result_3 =
+  MoveMigrator::TaskResult result_3 =
       MoveMigrator::PreMigrationCleanUp(original_profile_dir_3);
-  ASSERT_TRUE(result_3.success);
-  EXPECT_EQ(result_3.extra_bytes_required_to_be_freed, 0u);
+  ASSERT_EQ(result_3.status, MoveMigrator::TaskStatus::kSucceeded);
+  EXPECT_FALSE(result_3.extra_bytes_required_to_be_freed.has_value());
   EXPECT_FALSE(base::PathExists(
       original_profile_dir_3.Append(browser_data_migrator_util::kLacrosDir)));
   EXPECT_FALSE(base::PathExists(original_profile_dir_3.Append(kCacheFilePath)));
@@ -333,10 +336,10 @@
                           .Append("TestFile"),
                       kDataContent, kDataSize),
       kDataSize);
-  MoveMigrator::PreMigrationCleanUpResult result_4 =
+  MoveMigrator::TaskResult result_4 =
       MoveMigrator::PreMigrationCleanUp(original_profile_dir_4);
-  ASSERT_TRUE(result_4.success);
-  EXPECT_EQ(result_4.extra_bytes_required_to_be_freed, 0u);
+  ASSERT_EQ(result_4.status, MoveMigrator::TaskStatus::kSucceeded);
+  EXPECT_FALSE(result_4.extra_bytes_required_to_be_freed.has_value());
   EXPECT_FALSE(base::PathExists(
       original_profile_dir_4.Append(browser_data_migrator_util::kSplitTmpDir)));
 }
@@ -352,8 +355,9 @@
   scoped_refptr<browser_data_migrator_util::CancelFlag> cancel_flag =
       base::MakeRefCounted<browser_data_migrator_util::CancelFlag>();
 
-  EXPECT_TRUE(MoveMigrator::SetupLacrosDir(
-      original_profile_dir, std::move(progress_tracker), cancel_flag));
+  MoveMigrator::TaskResult result = MoveMigrator::SetupLacrosDir(
+      original_profile_dir, std::move(progress_tracker), cancel_flag);
+  ASSERT_EQ(result.status, MoveMigrator::TaskStatus::kSucceeded);
 
   const base::FilePath tmp_user_dir =
       original_profile_dir.Append(browser_data_migrator_util::kMoveTmpDir);
@@ -377,7 +381,8 @@
           .Append(browser_data_migrator_util::kLacrosProfilePath);
 
   ASSERT_TRUE(base::CreateDirectory(tmp_profile_dir));
-  EXPECT_TRUE(MoveMigrator::MoveLacrosItemsToNewDir(original_profile_dir));
+  ASSERT_EQ(MoveMigrator::MoveLacrosItemsToNewDir(original_profile_dir).status,
+            MoveMigrator::TaskStatus::kSucceeded);
 
   EXPECT_FALSE(
       base::PathExists(original_profile_dir.Append(kBookmarksFilePath)));
@@ -400,7 +405,12 @@
   base::SetPosixFilePermissions(original_profile_dir.Append(kBookmarksFilePath),
                                 0500);
 
-  EXPECT_FALSE(MoveMigrator::MoveLacrosItemsToNewDir(original_profile_dir));
+  MoveMigrator::TaskResult result =
+      MoveMigrator::MoveLacrosItemsToNewDir(original_profile_dir);
+  ASSERT_EQ(result.status,
+            MoveMigrator::TaskStatus::kMoveLacrosItemsToNewDirNoWritePerm);
+  ASSERT_TRUE(result.posix_errno.has_value());
+  ASSERT_EQ(result.posix_errno.value(), EACCES);
 }
 
 TEST(MoveMigratorTest, SetupAshSplitDir) {
@@ -418,7 +428,8 @@
   ASSERT_TRUE(base::CreateDirectory(tmp_user_dir));
   ASSERT_TRUE(base::CreateDirectory(tmp_profile_dir));
 
-  EXPECT_TRUE(MoveMigrator::SetupAshSplitDir(original_profile_dir));
+  EXPECT_EQ(MoveMigrator::SetupAshSplitDir(original_profile_dir).status,
+            MoveMigrator::TaskStatus::kSucceeded);
 
   const base::FilePath tmp_split_dir =
       original_profile_dir.Append(browser_data_migrator_util::kSplitTmpDir);
@@ -480,6 +491,18 @@
   EXPECT_FALSE(MoveMigrator::ResumeRequired(&pref_service, user_id_hash));
 }
 
+TEST(MoveMigratorTest, RecordPosixErrnoUMA) {
+  base::HistogramTester histogram_tester;
+
+  MoveMigrator::RecordPosixErrnoUMA(
+      MoveMigrator::TaskStatus::kMoveLacrosItemsToNewDirNoWritePerm, EPERM);
+
+  std::string uma_name =
+      "Ash.BrowserDataMigrator.MoveMigrator.PosixErrno."
+      "MoveLacrosItemsToNewDirNoWritePerm";
+  histogram_tester.ExpectBucketCount(uma_name, EPERM, 1);
+}
+
 class MoveMigratorMigrateTest : public ::testing::Test {
  public:
   MoveMigratorMigrateTest()
@@ -903,7 +926,7 @@
   run_loop_->Run();
 
   EXPECT_EQ(data_wipe_result_,
-            BrowserDataMigratorImpl::DataWipeResult::kFailed);
+            BrowserDataMigratorImpl::DataWipeResult::kSucceeded);
   EXPECT_EQ(data_migration_result_.kind,
             BrowserDataMigrator::ResultKind::kFailed);
   EXPECT_EQ(100u, data_migration_result_.required_size);
diff --git a/chrome/browser/ash/file_manager/path_util.cc b/chrome/browser/ash/file_manager/path_util.cc
index 2bfcbc2..0b8c4f5b 100644
--- a/chrome/browser/ash/file_manager/path_util.cc
+++ b/chrome/browser/ash/file_manager/path_util.cc
@@ -87,6 +87,11 @@
 // Sync with the volume provider in ARC++ side.
 constexpr char kArcRemovableMediaContentUrlPrefix[] =
     "content://org.chromium.arc.volumeprovider/";
+// A predefined removable media UUID for testing. Defined in
+// ash/components/arc/volume_mounter/arc_volume_mounter_bridge.cc.
+// TODO(crbug.com/1274481): Move ash-wide constants to a common place.
+constexpr char kArcRemovableMediaUuidForTesting[] =
+    "00000000000000000000000000000000DEADBEEF";
 // The dummy UUID of the MyFiles volume is taken from
 // ash/components/arc/volume_mounter/arc_volume_mounter_bridge.cc.
 // TODO(crbug.com/929031): Move MyFiles constants to a common place.
@@ -636,10 +641,10 @@
     if (volume_name.empty())
       return false;
     const std::string fs_uuid = GetFsUuidForRemovableMedia(volume_name);
-    if (fs_uuid.empty())
-      return false;
     // Replace the volume name in the relative path with the UUID.
-    base::FilePath relative_path_with_uuid = base::FilePath(fs_uuid);
+    // When no UUID is found for the volume, use the predefined one for testing.
+    base::FilePath relative_path_with_uuid = base::FilePath(
+        fs_uuid.empty() ? kArcRemovableMediaUuidForTesting : fs_uuid);
     if (!base::FilePath(volume_name)
              .AppendRelativePath(relative_path, &relative_path_with_uuid)) {
       LOG(WARNING) << "Failed to replace volume name \"" << volume_name
diff --git a/chrome/browser/ash/login/app_mode/web_kiosk_browsertest.cc b/chrome/browser/ash/login/app_mode/web_kiosk_browsertest.cc
index b8b79e3f..8a9ceaf 100644
--- a/chrome/browser/ash/login/app_mode/web_kiosk_browsertest.cc
+++ b/chrome/browser/ash/login/app_mode/web_kiosk_browsertest.cc
@@ -89,11 +89,10 @@
   }
 
   void MakeAppAlreadyInstalled() {
-    auto info = std::make_unique<WebAppInstallInfo>();
-    info->start_url = GURL(kAppLaunchUrl);
-    info->title = kAppTitle;
-    WebKioskAppManager::Get()->UpdateAppByAccountId(account_id(),
-                                                    std::move(info));
+    WebAppInstallInfo info;
+    info.start_url = GURL(kAppLaunchUrl);
+    info.title = kAppTitle;
+    WebKioskAppManager::Get()->UpdateAppByAccountId(account_id(), info);
   }
 
   bool LaunchApp() {
diff --git a/chrome/browser/ash/login/auth/chrome_login_performer.cc b/chrome/browser/ash/login/auth/chrome_login_performer.cc
index 41a89192..45a38c67 100644
--- a/chrome/browser/ash/login/auth/chrome_login_performer.cc
+++ b/chrome/browser/ash/login/auth/chrome_login_performer.cc
@@ -22,8 +22,9 @@
 
 namespace ash {
 
-ChromeLoginPerformer::ChromeLoginPerformer(Delegate* delegate)
-    : LoginPerformer(delegate) {}
+ChromeLoginPerformer::ChromeLoginPerformer(Delegate* delegate,
+                                           MetricsRecorder* metrics_recorder)
+    : LoginPerformer(delegate, metrics_recorder) {}
 
 ChromeLoginPerformer::~ChromeLoginPerformer() {}
 
diff --git a/chrome/browser/ash/login/auth/chrome_login_performer.h b/chrome/browser/ash/login/auth/chrome_login_performer.h
index f1a3499..f8216ee 100644
--- a/chrome/browser/ash/login/auth/chrome_login_performer.h
+++ b/chrome/browser/ash/login/auth/chrome_login_performer.h
@@ -12,6 +12,7 @@
 #include "ash/components/login/auth/authenticator.h"
 #include "ash/components/login/auth/extended_authenticator.h"
 #include "ash/components/login/auth/login_performer.h"
+#include "ash/components/login/auth/metrics_recorder.h"
 #include "ash/components/login/auth/user_context.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/login/wildcard_login_checker.h"
@@ -33,7 +34,8 @@
 
 class ChromeLoginPerformer : public LoginPerformer {
  public:
-  explicit ChromeLoginPerformer(Delegate* delegate);
+  explicit ChromeLoginPerformer(Delegate* delegate,
+                                MetricsRecorder* metrics_recorder);
 
   ChromeLoginPerformer(const ChromeLoginPerformer&) = delete;
   ChromeLoginPerformer& operator=(const ChromeLoginPerformer&) = delete;
diff --git a/chrome/browser/ash/login/existing_user_controller.cc b/chrome/browser/ash/login/existing_user_controller.cc
index 2c917b7..eabdbf3 100644
--- a/chrome/browser/ash/login/existing_user_controller.cc
+++ b/chrome/browser/ash/login/existing_user_controller.cc
@@ -598,7 +598,8 @@
   if (!login_performer_.get() || num_login_attempts_ <= 1) {
     // Only one instance of LoginPerformer should exist at a time.
     login_performer_.reset(nullptr);
-    login_performer_ = std::make_unique<ChromeLoginPerformer>(this);
+    login_performer_ = std::make_unique<ChromeLoginPerformer>(
+        this, GetLoginDisplayHost()->metrics_recorder());
   }
   if (IsActiveDirectoryManaged() &&
       user_context.GetUserType() != user_manager::USER_TYPE_ACTIVE_DIRECTORY) {
@@ -1227,7 +1228,8 @@
 
   // Only one instance of LoginPerformer should exist at a time.
   login_performer_.reset(nullptr);
-  login_performer_ = std::make_unique<ChromeLoginPerformer>(this);
+  login_performer_ = std::make_unique<ChromeLoginPerformer>(
+      this, GetLoginDisplayHost()->metrics_recorder());
   login_performer_->LoginOffTheRecord();
   SendAccessibilityAlert(
       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_OFFRECORD));
@@ -1521,7 +1523,8 @@
   VLOG(2) << "LoginAsPublicSessionInternal for user: "
           << user_context.GetAccountId();
   login_performer_.reset(nullptr);
-  login_performer_ = std::make_unique<ChromeLoginPerformer>(this);
+  login_performer_ = std::make_unique<ChromeLoginPerformer>(
+      this, GetLoginDisplayHost()->metrics_recorder());
   login_performer_->LoginAsPublicSession(user_context);
   SendAccessibilityAlert(
       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
diff --git a/chrome/browser/ash/login/oobe_screen.cc b/chrome/browser/ash/login/oobe_screen.cc
index 45319fa..27b0f4be 100644
--- a/chrome/browser/ash/login/oobe_screen.cc
+++ b/chrome/browser/ash/login/oobe_screen.cc
@@ -10,7 +10,13 @@
 
 OobeScreenId::OobeScreenId(const std::string& name) : name(name) {}
 
-OobeScreenId::OobeScreenId(const StaticOobeScreenId& id) : name(id.name) {}
+OobeScreenId::OobeScreenId(const StaticOobeScreenId& id)
+    : name(id.name) {
+  if (id.external_api_prefix)
+    external_api_prefix = id.external_api_prefix;
+  // TODO(https://crbug.com/1312879): Uncomment when the bug is fixed.
+  // DCHECK(!external_api_prefix.empty());
+}
 
 bool OobeScreenId::operator==(const OobeScreenId& rhs) const {
   return name == rhs.name;
diff --git a/chrome/browser/ash/login/oobe_screen.h b/chrome/browser/ash/login/oobe_screen.h
index 1bbc7a1..5d1ea70 100644
--- a/chrome/browser/ash/login/oobe_screen.h
+++ b/chrome/browser/ash/login/oobe_screen.h
@@ -28,13 +28,14 @@
 // Identifiers an OOBE screen.
 struct OobeScreenId {
   // Create an identifier from a string.
+  // TODO(https://crbug.com/1312880): Remove this.
   explicit OobeScreenId(const std::string& id);
   // Create an identifier from a statically created identifier. This is implicit
   // to make StaticOobeScreenId act more like OobeScreenId.
   OobeScreenId(const StaticOobeScreenId& id);
 
-  // Name of the screen.
   std::string name;
+  std::string external_api_prefix;
 
   bool operator==(const OobeScreenId& rhs) const;
   bool operator!=(const OobeScreenId& rhs) const;
@@ -47,6 +48,7 @@
 // the data in the binary instead of std::string.
 struct StaticOobeScreenId {
   const char* name;
+  const char* external_api_prefix = nullptr;
 
   OobeScreenId AsId() const;
 };
diff --git a/chrome/browser/ash/login/screen_manager.cc b/chrome/browser/ash/login/screen_manager.cc
index 0f2b1f89..6189942 100644
--- a/chrome/browser/ash/login/screen_manager.cc
+++ b/chrome/browser/ash/login/screen_manager.cc
@@ -7,7 +7,9 @@
 #include <iostream>
 #include <utility>
 
+#include "base/containers/flat_map.h"
 #include "base/memory/ptr_util.h"
+#include "chrome/browser/ash/login/oobe_screen.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 
 namespace ash {
@@ -16,9 +18,9 @@
 
 ScreenManager::~ScreenManager() = default;
 
-void ScreenManager::Init(std::vector<std::unique_ptr<BaseScreen>> screens) {
-  for (auto&& screen : screens)
-    screens_[screen->screen_id()] = std::move(screen);
+void ScreenManager::Init(
+    std::vector<std::pair<OobeScreenId, std::unique_ptr<BaseScreen>>> screens) {
+  screens_ = decltype(screens_)(std::move(screens));
 }
 
 BaseScreen* ScreenManager::GetScreen(OobeScreenId screen) {
diff --git a/chrome/browser/ash/login/screen_manager.h b/chrome/browser/ash/login/screen_manager.h
index b38f5635..71302b9 100644
--- a/chrome/browser/ash/login/screen_manager.h
+++ b/chrome/browser/ash/login/screen_manager.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_SCREEN_MANAGER_H_
 #define CHROME_BROWSER_ASH_LOGIN_SCREEN_MANAGER_H_
 
-#include <map>
 #include <memory>
+#include <vector>
 
-#include "base/gtest_prod_util.h"
+#include "base/containers/flat_map.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
 
 namespace ash {
@@ -25,7 +25,8 @@
   ~ScreenManager();
 
   // Initialize all screen instances.
-  void Init(std::vector<std::unique_ptr<BaseScreen>> screens);
+  void Init(std::vector<std::pair<OobeScreenId, std::unique_ptr<BaseScreen>>>
+                screens);
 
   // Destroys all screen instances.
   void Shutdown();
@@ -40,7 +41,7 @@
 
  private:
   // Created screens.
-  std::map<OobeScreenId, std::unique_ptr<BaseScreen>> screens_;
+  base::flat_map<OobeScreenId, std::unique_ptr<BaseScreen>> screens_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/screens/base_screen.h b/chrome/browser/ash/login/screens/base_screen.h
index 15ee0db..9e78be1 100644
--- a/chrome/browser/ash/login/screens/base_screen.h
+++ b/chrome/browser/ash/login/screens/base_screen.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "ash/public/cpp/login_accelerators.h"
-#include "base/gtest_prod_util.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
 #include "chrome/browser/ash/login/wizard_context.h"
diff --git a/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.cc b/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.cc
index c01b8b84..40f0751 100644
--- a/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.cc
+++ b/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h"
 
 #include "base/logging.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
@@ -39,11 +40,11 @@
 }  // namespace
 
 EnableAdbSideloadingScreen::EnableAdbSideloadingScreen(
-    EnableAdbSideloadingScreenView* view,
+    base::WeakPtr<EnableAdbSideloadingScreenView> view,
     const base::RepeatingClosure& exit_callback)
     : BaseScreen(EnableAdbSideloadingScreenView::kScreenId,
                  OobeScreenPriority::SCREEN_DEVICE_DEVELOPER_MODIFICATION),
-      view_(view),
+      view_(std::move(view)),
       exit_callback_(exit_callback) {
   if (view_)
     view_->Bind(this);
@@ -167,10 +168,4 @@
   help_app_->ShowHelpTopic(topic);
 }
 
-void EnableAdbSideloadingScreen::OnViewDestroyed(
-    EnableAdbSideloadingScreenView* view) {
-  if (view_ == view)
-    view_ = nullptr;
-}
-
 }  // namespace ash
diff --git a/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h b/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h
index 9bb3ec6..3f077e6e 100644
--- a/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h
+++ b/chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h
@@ -23,7 +23,7 @@
 // adb sideloading screen to users.
 class EnableAdbSideloadingScreen : public BaseScreen {
  public:
-  EnableAdbSideloadingScreen(EnableAdbSideloadingScreenView* view,
+  EnableAdbSideloadingScreen(base::WeakPtr<EnableAdbSideloadingScreenView> view,
                              const base::RepeatingClosure& exit_callback);
 
   EnableAdbSideloadingScreen(const EnableAdbSideloadingScreen&) = delete;
@@ -32,9 +32,6 @@
 
   ~EnableAdbSideloadingScreen() override;
 
-  // Called by EnableAdbSideloadingHandler.
-  void OnViewDestroyed(EnableAdbSideloadingScreenView* view);
-
   // Registers Local State preferences.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
@@ -60,7 +57,7 @@
   // Help application used for help dialogs.
   scoped_refptr<HelpAppLauncher> help_app_;
 
-  EnableAdbSideloadingScreenView* view_;
+  base::WeakPtr<EnableAdbSideloadingScreenView> view_;
   base::RepeatingClosure exit_callback_;
   base::WeakPtrFactory<EnableAdbSideloadingScreen> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ash/login/screens/error_screen.cc b/chrome/browser/ash/login/screens/error_screen.cc
index 896295ab..46ba6ac 100644
--- a/chrome/browser/ash/login/screens/error_screen.cc
+++ b/chrome/browser/ash/login/screens/error_screen.cc
@@ -413,7 +413,8 @@
   if (guest_login_performer_)
     return;
 
-  guest_login_performer_ = std::make_unique<ChromeLoginPerformer>(this);
+  guest_login_performer_ = std::make_unique<ChromeLoginPerformer>(
+      this, LoginDisplayHost::default_host()->metrics_recorder());
   guest_login_performer_->LoginOffTheRecord();
 }
 
diff --git a/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.cc b/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.cc
index d00151f9..eb871977 100644
--- a/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.cc
+++ b/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h"
+#include "base/memory/weak_ptr.h"
 
 namespace ash {
 
@@ -10,22 +11,21 @@
 using ::testing::AtLeast;
 
 MockEnableAdbSideloadingScreen::MockEnableAdbSideloadingScreen(
-    EnableAdbSideloadingScreenView* view,
+    base::WeakPtr<EnableAdbSideloadingScreenView> view,
     const base::RepeatingClosure& exit_callback)
-    : EnableAdbSideloadingScreen(view, exit_callback) {}
+    : EnableAdbSideloadingScreen(std::move(view), exit_callback) {}
 
-MockEnableAdbSideloadingScreen::~MockEnableAdbSideloadingScreen() {}
+MockEnableAdbSideloadingScreen::~MockEnableAdbSideloadingScreen() = default;
 
 void MockEnableAdbSideloadingScreen::ExitScreen() {
   exit_callback()->Run();
 }
 
-MockEnableAdbSideloadingScreenView::MockEnableAdbSideloadingScreenView() {}
+MockEnableAdbSideloadingScreenView::MockEnableAdbSideloadingScreenView() =
+    default;
 
-MockEnableAdbSideloadingScreenView::~MockEnableAdbSideloadingScreenView() {
-  if (screen_)
-    screen_->OnViewDestroyed(this);
-}
+MockEnableAdbSideloadingScreenView::~MockEnableAdbSideloadingScreenView() =
+    default;
 
 void MockEnableAdbSideloadingScreenView::Bind(
     EnableAdbSideloadingScreen* screen) {
diff --git a/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h b/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h
index 3f119e1..e88e4bc6 100644
--- a/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h
+++ b/chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_SCREENS_MOCK_ENABLE_ADB_SIDELOADING_SCREEN_H_
 #define CHROME_BROWSER_ASH_LOGIN_SCREENS_MOCK_ENABLE_ADB_SIDELOADING_SCREEN_H_
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/login/screens/enable_adb_sideloading_screen.h"
 #include "chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -13,8 +14,9 @@
 
 class MockEnableAdbSideloadingScreen : public EnableAdbSideloadingScreen {
  public:
-  MockEnableAdbSideloadingScreen(EnableAdbSideloadingScreenView* view,
-                                 const base::RepeatingClosure& exit_callback);
+  MockEnableAdbSideloadingScreen(
+      base::WeakPtr<EnableAdbSideloadingScreenView> view,
+      const base::RepeatingClosure& exit_callback);
   ~MockEnableAdbSideloadingScreen() override;
 
   MOCK_METHOD(void, ShowImpl, ());
diff --git a/chrome/browser/ash/login/ui/login_display_host.cc b/chrome/browser/ash/login/ui/login_display_host.cc
index eb755f53..1e16d4808 100644
--- a/chrome/browser/ash/login/ui/login_display_host.cc
+++ b/chrome/browser/ash/login/ui/login_display_host.cc
@@ -14,6 +14,7 @@
 LoginDisplayHost::LoginDisplayHost() {
   DCHECK(default_host() == nullptr);
   default_host_ = this;
+  metrics_recorder_ = std::make_unique<MetricsRecorder>();
 }
 
 LoginDisplayHost::~LoginDisplayHost() {
diff --git a/chrome/browser/ash/login/ui/login_display_host.h b/chrome/browser/ash/login/ui/login_display_host.h
index 948bfc0..165cd2a 100644
--- a/chrome/browser/ash/login/ui/login_display_host.h
+++ b/chrome/browser/ash/login/ui/login_display_host.h
@@ -38,6 +38,7 @@
 namespace ash {
 class KioskAppId;
 class KioskLaunchController;
+class MetricsRecorder;
 class WebUILoginView;
 class WizardController;
 enum class OobeDialogState;
@@ -75,6 +76,9 @@
   // Returns the default LoginDisplayHost instance if it has been created.
   static LoginDisplayHost* default_host() { return default_host_; }
 
+  // Returns an owned pointer to the MetricsRecorder instance.
+  MetricsRecorder* metrics_recorder() { return metrics_recorder_.get(); }
+
   // Returns an unowned pointer to the LoginDisplay instance.
   virtual LoginDisplay* GetLoginDisplay() = 0;
 
@@ -267,6 +271,9 @@
   // Global LoginDisplayHost instance.
   static LoginDisplayHost* default_host_;
 
+  // Owned pointer to MetricsRecorder instance.
+  std::unique_ptr<MetricsRecorder> metrics_recorder_;
+
   // Callback to be executed when WebUI is started.
   base::RepeatingClosure on_wizard_controller_created_for_tests_;
 };
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index 7fff190..32816f5 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -55,6 +55,7 @@
 #include "chrome/browser/ash/login/hwid_checker.h"
 #include "chrome/browser/ash/login/login_pref_names.h"
 #include "chrome/browser/ash/login/login_wizard.h"
+#include "chrome/browser/ash/login/oobe_screen.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/ash/login/screens/active_directory_login_screen.h"
 #include "chrome/browser/ash/login/screens/active_directory_password_change_screen.h"
@@ -529,13 +530,14 @@
   testing_factory = std::move(factory);
 }
 
-std::vector<std::unique_ptr<BaseScreen>> WizardController::CreateScreens() {
+std::vector<std::pair<OobeScreenId, std::unique_ptr<BaseScreen>>>
+WizardController::CreateScreens() {
   OobeUI* oobe_ui = GetOobeUI();
 
-  std::vector<std::unique_ptr<BaseScreen>> result;
+  std::vector<std::pair<OobeScreenId, std::unique_ptr<BaseScreen>>> result;
 
   auto append = [&](std::unique_ptr<BaseScreen> screen) {
-    result.emplace_back(std::move(screen));
+    result.emplace_back(screen->screen_id(), std::move(screen));
   };
 
   if (oobe_ui->display_type() == OobeUI::kOobeDisplay) {
@@ -582,7 +584,7 @@
       base::BindRepeating(&WizardController::OnDemoSetupScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EnableAdbSideloadingScreen>(
-      oobe_ui->GetView<EnableAdbSideloadingScreenHandler>(),
+      oobe_ui->GetView<EnableAdbSideloadingScreenHandler>()->AsWeakPtr(),
       base::BindRepeating(&WizardController::OnEnableAdbSideloadingScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EnableDebuggingScreen>(
diff --git a/chrome/browser/ash/login/wizard_controller.h b/chrome/browser/ash/login/wizard_controller.h
index 9f5f1be..5e2f8c94 100644
--- a/chrome/browser/ash/login/wizard_controller.h
+++ b/chrome/browser/ash/login/wizard_controller.h
@@ -243,7 +243,8 @@
 
  private:
   // Create BaseScreen instances. These are owned by `screen_manager_`.
-  std::vector<std::unique_ptr<BaseScreen>> CreateScreens();
+  std::vector<std::pair<OobeScreenId, std::unique_ptr<BaseScreen>>>
+  CreateScreens();
 
   // Show specific screen.
   void ShowWelcomeScreen();
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc
index 84eafb3..64461cc 100644
--- a/chrome/browser/ash/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -608,7 +608,7 @@
     ExpectBindUnbind(mock_enable_adb_sideloading_screen_view_.get());
     mock_enable_adb_sideloading_screen_ = MockScreenExpectLifecycle(
         std::make_unique<MockEnableAdbSideloadingScreen>(
-            mock_enable_adb_sideloading_screen_view_.get(),
+            mock_enable_adb_sideloading_screen_view_->AsWeakPtr(),
             base::BindRepeating(
                 &WizardController::OnEnableAdbSideloadingScreenExit,
                 base::Unretained(wizard_controller))));
@@ -2453,13 +2453,6 @@
   SkipToScreen(EnableAdbSideloadingScreenView::kScreenId,
                mock_enable_adb_sideloading_screen_);
   CheckCurrentScreen(EnableAdbSideloadingScreenView::kScreenId);
-
-  test::OobeJS().ClickOnPath(
-      {"adb-sideloading", "enable-adb-sideloading-cancel-button"});
-
-  base::RunLoop().RunUntilIdle();
-
-  CheckCurrentScreen(EnableAdbSideloadingScreenView::kScreenId);
   EXPECT_CALL(*mock_enable_adb_sideloading_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
 
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
index b599c47..d843863 100644
--- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -79,12 +79,6 @@
 // A 5-second long 96kb/s Ogg-Vorbis 44.1kHz mono audio file.
 constexpr char kFileAudioOgg[] = "music.ogg";
 
-// A 1-page (8.5" x 11") PDF with some text and metadata.
-constexpr char kFilePdfTall[] = "tall.pdf";
-
-// A small square image PDF created by a camera.
-constexpr char kFilePdfImg[] = "img.pdf";
-
 constexpr char kUnhandledRejectionScript[] =
     "window.dispatchEvent("
     "new CustomEvent('simulate-unhandled-rejection-for-test'));";
@@ -100,10 +94,6 @@
 
 class MediaAppIntegrationTest : public SystemWebAppIntegrationTest {
  public:
-  MediaAppIntegrationTest() {
-    feature_list_.InitAndEnableFeature(ash::features::kMediaAppHandlesPdf);
-  }
-
   void MediaAppLaunchWithFile(bool audio_enabled);
   void MediaAppWithLaunchSystemWebAppAsync(bool audio_enabled);
   void MediaAppEligibleOpenTask(bool audio_enabled);
@@ -115,7 +105,6 @@
   content::WebContents* LaunchWithNoFiles();
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<file_manager::test::FolderInMyFiles> launch_folder_;
 };
 
@@ -425,49 +414,6 @@
   MediaAppWithLaunchSystemWebAppAsync(false);
 }
 
-// Test that the Media App launches a single window for images.
-IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, MediaAppLaunchImageMulti) {
-  WaitForTestSystemAppInstall();
-  web_app::SystemAppLaunchParams image_params;
-  image_params.launch_paths = {TestFile(kFilePng800x600),
-                               TestFile(kFileJpeg640x480)};
-
-  web_app::LaunchSystemWebAppAsync(browser()->profile(),
-                                   web_app::SystemAppType::MEDIA, image_params);
-  web_app::FlushSystemWebAppLaunchesForTesting(browser()->profile());
-
-  const BrowserList* browser_list = BrowserList::GetInstance();
-  EXPECT_EQ(2u, browser_list->size());  // 1 extra for the browser test browser.
-
-  content::TitleWatcher watcher(
-      browser_list->get(1)->tab_strip_model()->GetActiveWebContents(),
-      u"image.png");
-  EXPECT_EQ(u"image.png", watcher.WaitAndGetTitle());
-}
-
-// Test that the Media App launches multiple windows for PDFs.
-IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, MediaAppLaunchPdfMulti) {
-  WaitForTestSystemAppInstall();
-  web_app::SystemAppLaunchParams pdf_params;
-  pdf_params.launch_paths = {TestFile(kFilePdfTall), TestFile(kFilePdfImg)};
-
-  web_app::LaunchSystemWebAppAsync(browser()->profile(),
-                                   web_app::SystemAppType::MEDIA, pdf_params);
-  web_app::FlushSystemWebAppLaunchesForTesting(browser()->profile());
-
-  const BrowserList* browser_list = BrowserList::GetInstance();
-  EXPECT_EQ(3u, browser_list->size());  // 1 extra for the browser test browser.
-
-  content::TitleWatcher watcher1(
-      browser_list->get(1)->tab_strip_model()->GetActiveWebContents(),
-      u"tall.pdf");
-  content::TitleWatcher watcher2(
-      browser_list->get(2)->tab_strip_model()->GetActiveWebContents(),
-      u"img.pdf");
-  EXPECT_EQ(u"tall.pdf", watcher1.WaitAndGetTitle());
-  EXPECT_EQ(u"img.pdf", watcher2.WaitAndGetTitle());
-}
-
 // Test that the Media App appears as a handler for files in the App Service.
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, MediaAppHandlesIntents) {
   WaitForTestSystemAppInstall();
diff --git a/chrome/browser/ash/web_applications/media_app/media_web_app_info.cc b/chrome/browser/ash/web_applications/media_app/media_web_app_info.cc
index efd1a7a..489fc308 100644
--- a/chrome/browser/ash/web_applications/media_app/media_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_web_app_info.cc
@@ -16,7 +16,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
-#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
@@ -61,6 +60,9 @@
     {"image/svg+xml", ".svg,.svgz"},
     {"image/avif", ".avif"},
 
+    // PDF.
+    {"application/pdf", ".pdf"},
+
     // When updating this list, `FOO_EXTENSIONS` in go/bl-launch should be
     // updated as well.
 };
@@ -84,11 +86,6 @@
     // updated as well.
 };
 
-constexpr char kPdfExtension[] = ".pdf";
-constexpr FileHandlerConfig kPdfFileHandlers[] = {
-    {"application/pdf", kPdfExtension},
-};
-
 // Converts a FileHandlerConfig constexpr into the type needed to populate the
 // WebAppInstallInfo's `accept` property.
 std::vector<apps::FileHandler::AcceptEntry> MakeFileHandlerAccept(
@@ -108,16 +105,6 @@
   return result;
 }
 
-// Picks out a single file from a template launch `params`.
-const apps::AppLaunchParams PickFileFromParams(
-    const apps::AppLaunchParams& params,
-    size_t index) {
-  return apps::AppLaunchParams(params.app_id, params.container,
-                               params.disposition, params.launch_source,
-                               params.display_id, {params.launch_files[index]},
-                               params.intent ? params.intent.Clone() : nullptr);
-}
-
 }  // namespace
 
 MediaSystemAppDelegate::MediaSystemAppDelegate(Profile* profile)
@@ -176,21 +163,10 @@
   image_video_handler.action = GURL(ash::kChromeUIMediaAppURL);
   image_video_handler.accept = MakeFileHandlerAccept(kFileHandlers);
   info->file_handlers.push_back(std::move(image_video_handler));
-
   apps::FileHandler audio_handler;
   audio_handler.action = GURL(ash::kChromeUIMediaAppURL);
   audio_handler.accept = MakeFileHandlerAccept(kAudioFileHandlers);
   info->file_handlers.push_back(std::move(audio_handler));
-
-  apps::FileHandler pdf_handler;
-  pdf_handler.action = GURL(ash::kChromeUIMediaAppURL);
-  pdf_handler.accept = MakeFileHandlerAccept(kPdfFileHandlers);
-  // Note setting `apps::FileHandler::LaunchType::kMultipleClients` here has no
-  // effect for system web apps (see comments in
-  // WebAppPublisherHelper::OnFileHandlerDialogCompleted()). The PDF-specifc
-  // behavior to spawn multiple launches occurs in an override of
-  // LaunchAndNavigateSystemWebApp().
-  info->file_handlers.push_back(std::move(pdf_handler));
   return info;
 }
 
@@ -243,25 +219,3 @@
 bool MediaSystemAppDelegate::ShouldHandleFileOpenIntents() const {
   return true;
 }
-
-Browser* MediaSystemAppDelegate::LaunchAndNavigateSystemWebApp(
-    Profile* profile,
-    web_app::WebAppProvider* provider,
-    const GURL& url,
-    const apps::AppLaunchParams& params) const {
-  // For zero/single-file launches, or non-PDF launches, launch a single window.
-  if (params.launch_files.size() < 2 ||
-      !params.launch_files[0].MatchesExtension(kPdfExtension)) {
-    return SystemWebAppDelegate::LaunchAndNavigateSystemWebApp(
-        profile, provider, url, params);
-  }
-
-  // For PDFs, launch all but the last file from scratch. Windows will cascade.
-  for (size_t i = 0; i < params.launch_files.size() - 1; ++i) {
-    web_app::LaunchSystemWebAppImpl(profile, web_app::SystemAppType::MEDIA, url,
-                                    PickFileFromParams(params, i));
-  }
-  return SystemWebAppDelegate::LaunchAndNavigateSystemWebApp(
-      profile, provider, url,
-      PickFileFromParams(params, params.launch_files.size() - 1));
-}
diff --git a/chrome/browser/ash/web_applications/media_app/media_web_app_info.h b/chrome/browser/ash/web_applications/media_app/media_web_app_info.h
index d142bff..81707e7 100644
--- a/chrome/browser/ash/web_applications/media_app/media_web_app_info.h
+++ b/chrome/browser/ash/web_applications/media_app/media_web_app_info.h
@@ -24,11 +24,6 @@
   bool ShouldHandleFileOpenIntents() const override;
   base::FilePath GetLaunchDirectory(
       const apps::AppLaunchParams& params) const override;
-  Browser* LaunchAndNavigateSystemWebApp(
-      Profile* profile,
-      web_app::WebAppProvider* provider,
-      const GURL& url,
-      const apps::AppLaunchParams& params) const override;
 };
 
 // Return a WebAppInstallInfo used to install the app.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3285c93..6abd5095 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -3410,6 +3410,8 @@
     "app_mode/app_session.h",
     "app_mode/chrome_kiosk_app_installer.cc",
     "app_mode/chrome_kiosk_app_installer.h",
+    "app_mode/chrome_kiosk_app_launcher.cc",
+    "app_mode/chrome_kiosk_app_launcher.h",
     "app_mode/chrome_kiosk_external_loader_broker.cc",
     "app_mode/chrome_kiosk_external_loader_broker.h",
     "app_mode/kiosk_app_external_loader.cc",
@@ -4777,6 +4779,7 @@
     "../policy/default_geolocation_policy_handler_unittest.cc",
     "../ui/browser_finder_chromeos_unittest.cc",
     "app_mode/app_session_unittest.cc",
+    "app_mode/chrome_kiosk_app_launcher_unittest.cc",
     "app_mode/kiosk_session_plugin_handler_unittest.cc",
     "extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc",
     "extensions/default_app_order_unittest.cc",
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.cc b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.cc
index 76efacf5..f51fe3e 100644
--- a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.cc
+++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h"
 
-#include "base/metrics/histogram_functions.h"
 #include "base/syslog_logging.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_launcher.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
@@ -23,14 +22,6 @@
 
 namespace ash {
 
-namespace {
-
-void RecordKioskSecondaryAppsInstallResult(bool success) {
-  base::UmaHistogramBoolean("Kiosk.SecondaryApps.InstallSuccessful", success);
-}
-
-}  // namespace
-
 ChromeKioskAppInstaller::AppInstallData::AppInstallData() = default;
 ChromeKioskAppInstaller::AppInstallData::AppInstallData(
     const AppInstallData& other) = default;
@@ -42,12 +33,10 @@
 ChromeKioskAppInstaller::ChromeKioskAppInstaller(
     Profile* profile,
     const AppInstallData& install_data,
-    KioskAppLauncher::Delegate* delegate,
-    bool finalize_only)
+    KioskAppLauncher::Delegate* delegate)
     : profile_(profile),
       primary_app_install_data_(install_data),
-      delegate_(delegate),
-      finalize_only_(finalize_only) {}
+      delegate_(delegate) {}
 
 ChromeKioskAppInstaller::~ChromeKioskAppInstaller() {}
 
@@ -58,11 +47,6 @@
 
   on_ready_callback_ = std::move(callback);
 
-  if (finalize_only_) {
-    FinalizeAppInstall();
-    return;
-  }
-
   extensions::file_util::SetUseSafeInstallation(true);
   ChromeKioskExternalLoaderBroker::Get()->TriggerPrimaryAppInstall(
       primary_app_install_data_);
@@ -175,57 +159,11 @@
 void ChromeKioskAppInstaller::FinalizeAppInstall() {
   DCHECK(!install_complete_);
 
-  const extensions::Extension* primary_app = GetPrimaryAppExtension();
-  // Verify that required apps are installed. While the apps should be
-  // present at this point, crash recovery flow skips app installation steps -
-  // this means that the kiosk app might not yet be downloaded. If that is
-  // the case, bail out from the app launch.
-  if (!primary_app) {
-    ReportInstallFailure(
-        ChromeKioskAppInstaller::InstallResult::kUnableToLaunch);
-    return;
-  }
-  if (!AreSecondaryAppsInstalled()) {
-    ReportInstallFailure(
-        ChromeKioskAppInstaller::InstallResult::kUnableToLaunch);
-    RecordKioskSecondaryAppsInstallResult(false);
-    return;
-  } else {
-    extensions::KioskModeInfo* info =
-        extensions::KioskModeInfo::Get(primary_app);
-    if (!info->secondary_apps.empty()) {
-      RecordKioskSecondaryAppsInstallResult(true);
-    }
-  }
-
-  const bool offline_enabled =
-      extensions::OfflineEnabledInfo::IsOfflineEnabled(primary_app);
-  // If the app is not offline enabled, make sure the network is ready before
-  // launching.
-  if (!offline_enabled && !delegate_->IsNetworkReady()) {
-    ReportInstallFailure(InstallResult::kNetworkMissing);
-    return;
-  }
-
   install_complete_ = true;
 
-  SetSecondaryAppsEnabledState(primary_app);
-  MaybeUpdateAppData();
-
   ReportInstallSuccess();
 }
 
-void ChromeKioskAppInstaller::MaybeUpdateAppData() {
-  // Skip copying meta data from the current installed primary app when
-  // there is a pending update.
-  if (PrimaryAppHasPendingUpdate())
-    return;
-
-  KioskAppManager::Get()->ClearAppData(primary_app_install_data_.id);
-  KioskAppManager::Get()->UpdateAppDataFromProfile(primary_app_install_data_.id,
-                                                   profile_, NULL);
-}
-
 void ChromeKioskAppInstaller::OnFinishCrxInstall(
     const std::string& extension_id,
     bool success) {
@@ -366,44 +304,4 @@
   return false;
 }
 
-void ChromeKioskAppInstaller::SetSecondaryAppsEnabledState(
-    const extensions::Extension* primary_app) {
-  extensions::KioskModeInfo* info = extensions::KioskModeInfo::Get(primary_app);
-  for (const auto& app_info : info->secondary_apps) {
-    // If the enabled on launch is not specified in the manifest, the apps
-    // enabled state should be kept as is.
-    if (!app_info.enabled_on_launch.has_value())
-      continue;
-
-    SetAppEnabledState(app_info.id, app_info.enabled_on_launch.value());
-  }
-}
-
-void ChromeKioskAppInstaller::SetAppEnabledState(
-    const extensions::ExtensionId& id,
-    bool new_enabled_state) {
-  extensions::ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
-
-  // If the app is already enabled, and we want it to be enabled, nothing to do.
-  if (service->IsExtensionEnabled(id) && new_enabled_state) {
-    return;
-  }
-
-  if (new_enabled_state) {
-    // Remove USER_ACTION disable reason - if no other disabled reasons are
-    // present, enable the app.
-    prefs->RemoveDisableReason(id,
-                               extensions::disable_reason::DISABLE_USER_ACTION);
-    if (prefs->GetDisableReasons(id) ==
-        extensions::disable_reason::DISABLE_NONE) {
-      service->EnableExtension(id);
-    }
-  } else {
-    service->DisableExtension(id,
-                              extensions::disable_reason::DISABLE_USER_ACTION);
-  }
-}
-
 }  // namespace ash
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h
index bf923a0..198fd06 100644
--- a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h
+++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h
@@ -21,7 +21,6 @@
   enum class InstallResult {
     kSuccess,
     kUnableToInstall,
-    kUnableToLaunch,
     kNotKioskEnabled,
     kNetworkMissing,
   };
@@ -42,8 +41,7 @@
 
   ChromeKioskAppInstaller(Profile* profile,
                           const AppInstallData& install_data,
-                          KioskAppLauncher::Delegate* delegate,
-                          bool finalize_only);
+                          KioskAppLauncher::Delegate* delegate);
   ChromeKioskAppInstaller(const ChromeKioskAppInstaller&) = delete;
   ChromeKioskAppInstaller& operator=(const ChromeKioskAppInstaller&) = delete;
   ~ChromeKioskAppInstaller() override;
@@ -55,7 +53,6 @@
   void MaybeCheckExtensionUpdate();
   void OnExtensionUpdateCheckFinished(bool update_found);
   void FinalizeAppInstall();
-  void MaybeUpdateAppData();
 
   // extensions::InstallObserver overrides.
   void OnFinishCrxInstall(const std::string& extension_id,
@@ -84,14 +81,9 @@
   bool DidPrimaryOrSecondaryAppFailedToInstall(bool success,
                                                const std::string& id) const;
 
-  void SetSecondaryAppsEnabledState(const extensions::Extension* primary_app);
-  void SetAppEnabledState(const extensions::ExtensionId& id,
-                          bool should_be_enabled);
-
   Profile* const profile_;
   const AppInstallData primary_app_install_data_;
   KioskAppLauncher::Delegate* delegate_;
-  bool finalize_only_;
 
   InstallCallback on_ready_callback_;
 
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.cc b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.cc
new file mode 100644
index 0000000..40ac5e72
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.cc
@@ -0,0 +1,189 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/syslog_logging.h"
+#include "chrome/browser/apps/app_service/app_launch_params.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "extensions/browser/disable_reason.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/common/extension_id.h"
+#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
+#include "extensions/common/manifest_handlers/offline_enabled_info.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+namespace {
+
+void RecordKioskSecondaryAppsInstallResult(bool success) {
+  base::UmaHistogramBoolean("Kiosk.SecondaryApps.InstallSuccessful", success);
+}
+
+}  // namespace
+
+namespace ash {
+
+ChromeKioskAppLauncher::ChromeKioskAppLauncher(Profile* profile,
+                                               const std::string& app_id,
+                                               bool network_available)
+    : profile_(profile),
+      app_id_(app_id),
+      network_available_(network_available) {}
+
+ChromeKioskAppLauncher::~ChromeKioskAppLauncher() {}
+
+void ChromeKioskAppLauncher::LaunchApp(LaunchCallback callback) {
+  on_ready_callback_ = std::move(callback);
+
+  const extensions::Extension* primary_app = GetPrimaryAppExtension();
+  // Verify that required apps are installed. While the apps should be
+  // present at this point, crash recovery flow skips app installation steps -
+  // this means that the kiosk app might not yet be downloaded. If that is
+  // the case, bail out from the app launch.
+  if (!primary_app) {
+    ReportLaunchFailure(LaunchResult::kUnableToLaunch);
+    return;
+  }
+
+  if (!AreSecondaryAppsInstalled()) {
+    ReportLaunchFailure(LaunchResult::kUnableToLaunch);
+    RecordKioskSecondaryAppsInstallResult(false);
+    return;
+  } else {
+    extensions::KioskModeInfo* info =
+        extensions::KioskModeInfo::Get(primary_app);
+    if (!info->secondary_apps.empty()) {
+      RecordKioskSecondaryAppsInstallResult(true);
+    }
+  }
+
+  const bool offline_enabled =
+      extensions::OfflineEnabledInfo::IsOfflineEnabled(primary_app);
+  // If the app is not offline enabled, make sure the network is ready before
+  // launching.
+  if (!offline_enabled && !network_available_) {
+    ReportLaunchFailure(LaunchResult::kNetworkMissing);
+    return;
+  }
+
+  SetSecondaryAppsEnabledState(primary_app);
+  MaybeUpdateAppData();
+
+  const extensions::Extension* extension = GetPrimaryAppExtension();
+  CHECK(extension);
+
+  DCHECK(extensions::KioskModeInfo::IsKioskEnabled(extension));
+
+  SYSLOG(INFO) << "Attempt to launch app.";
+
+  // Always open the app in a window.
+  ::OpenApplication(
+      profile_,
+      apps::AppLaunchParams(
+          extension->id(), apps::mojom::LaunchContainer::kLaunchContainerWindow,
+          WindowOpenDisposition::NEW_WINDOW,
+          apps::mojom::LaunchSource::kFromKiosk));
+
+  ReportLaunchSuccess();
+}
+
+void ChromeKioskAppLauncher::MaybeUpdateAppData() {
+  // Skip copying meta data from the current installed primary app when
+  // there is a pending update.
+  if (PrimaryAppHasPendingUpdate())
+    return;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  KioskAppManager::Get()->ClearAppData(app_id_);
+  KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, nullptr);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
+void ChromeKioskAppLauncher::ReportLaunchSuccess() {
+  std::move(on_ready_callback_)
+      .Run(ChromeKioskAppLauncher::LaunchResult::kSuccess);
+}
+
+void ChromeKioskAppLauncher::ReportLaunchFailure(
+    ChromeKioskAppLauncher::LaunchResult error) {
+  SYSLOG(ERROR) << "App launch failed, error: " << static_cast<int>(error);
+  DCHECK_NE(ChromeKioskAppLauncher::LaunchResult::kSuccess, error);
+
+  std::move(on_ready_callback_).Run(error);
+}
+
+const extensions::Extension* ChromeKioskAppLauncher::GetPrimaryAppExtension()
+    const {
+  return extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+      app_id_);
+}
+
+bool ChromeKioskAppLauncher::AreSecondaryAppsInstalled() const {
+  const extensions::Extension* extension = GetPrimaryAppExtension();
+  DCHECK(extension);
+  const extensions::KioskModeInfo* info =
+      extensions::KioskModeInfo::Get(extension);
+  for (const auto& app : info->secondary_apps) {
+    if (!extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+            app.id)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool ChromeKioskAppLauncher::PrimaryAppHasPendingUpdate() const {
+  return extensions::ExtensionSystem::Get(profile_)
+      ->extension_service()
+      ->GetPendingExtensionUpdate(app_id_);
+}
+
+void ChromeKioskAppLauncher::SetSecondaryAppsEnabledState(
+    const extensions::Extension* primary_app) {
+  const extensions::KioskModeInfo* info =
+      extensions::KioskModeInfo::Get(primary_app);
+  for (const auto& app_info : info->secondary_apps) {
+    // If the enabled on launch is not specified in the manifest, the apps
+    // enabled state should be kept as is.
+    if (!app_info.enabled_on_launch.has_value())
+      continue;
+
+    SetAppEnabledState(app_info.id, app_info.enabled_on_launch.value());
+  }
+}
+
+void ChromeKioskAppLauncher::SetAppEnabledState(
+    const extensions::ExtensionId& id,
+    bool new_enabled_state) {
+  extensions::ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
+
+  // If the app is already enabled, and we want it to be enabled, nothing to do.
+  if (service->IsExtensionEnabled(id) && new_enabled_state) {
+    return;
+  }
+
+  if (new_enabled_state) {
+    // Remove USER_ACTION disable reason - if no other disabled reasons are
+    // present, enable the app.
+    prefs->RemoveDisableReason(id,
+                               extensions::disable_reason::DISABLE_USER_ACTION);
+    if (prefs->GetDisableReasons(id) ==
+        extensions::disable_reason::DISABLE_NONE) {
+      service->EnableExtension(id);
+    }
+  } else {
+    service->DisableExtension(id,
+                              extensions::disable_reason::DISABLE_USER_ACTION);
+  }
+}
+
+}  // namespace ash
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h
new file mode 100644
index 0000000..7141720
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h
@@ -0,0 +1,58 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_APP_MODE_CHROME_KIOSK_APP_LAUNCHER_H_
+#define CHROME_BROWSER_CHROMEOS_APP_MODE_CHROME_KIOSK_APP_LAUNCHER_H_
+
+#include "base/callback.h"
+#include "chrome/browser/profiles/profile.h"
+#include "extensions/common/extension.h"
+
+namespace ash {
+
+class ChromeKioskAppLauncher {
+ public:
+  enum class LaunchResult {
+    kSuccess,
+    kUnableToLaunch,
+    kNetworkMissing,
+  };
+
+  using LaunchCallback = base::OnceCallback<void(LaunchResult result)>;
+
+  ChromeKioskAppLauncher(Profile* profile,
+                         const std::string& app_id,
+                         bool network_available);
+  ChromeKioskAppLauncher(const ChromeKioskAppLauncher&) = delete;
+  ChromeKioskAppLauncher& operator=(const ChromeKioskAppLauncher&) = delete;
+  ~ChromeKioskAppLauncher();
+
+  void LaunchApp(LaunchCallback callback);
+
+ private:
+  void ReportLaunchSuccess();
+  void ReportLaunchFailure(LaunchResult result);
+
+  const extensions::Extension* GetPrimaryAppExtension() const;
+
+  bool PrimaryAppHasPendingUpdate() const;
+
+  // Returns true if all secondary apps have been installed.
+  bool AreSecondaryAppsInstalled() const;
+
+  void MaybeUpdateAppData();
+  void SetSecondaryAppsEnabledState(const extensions::Extension* primary_app);
+  void SetAppEnabledState(const extensions::ExtensionId& id,
+                          bool should_be_enabled);
+
+  Profile* const profile_;
+  std::string app_id_;
+  bool network_available_ = false;
+
+  LaunchCallback on_ready_callback_;
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_CHROMEOS_APP_MODE_CHROME_KIOSK_APP_LAUNCHER_H_
\ No newline at end of file
diff --git a/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc
new file mode 100644
index 0000000..0dfe4a7a
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher_unittest.cc
@@ -0,0 +1,221 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_launcher.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/scoped_observation.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/test_future.h"
+#include "chrome/browser/ash/app_mode/test_kiosk_extension_builder.h"
+#include "chrome/browser/chromeos/app_mode/chrome_kiosk_app_installer.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/common/chrome_switches.h"
+#include "extensions/browser/test_event_router.h"
+#include "extensions/common/api/app_runtime.h"
+
+using base::test::TestFuture;
+using extensions::Manifest;
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using LaunchResult = ash::ChromeKioskAppLauncher::LaunchResult;
+
+namespace ash {
+
+namespace {
+
+constexpr char kTestPrimaryAppId[] = "abcdefghabcdefghabcdefghabcdefgh";
+constexpr char kSecondaryAppId[] = "aaaabbbbaaaabbbbaaaabbbbaaaabbbb";
+constexpr char kExtraSecondaryAppId[] = "aaaaccccaaaaccccaaaaccccaaaacccc";
+
+class AppLaunchTracker : public extensions::TestEventRouter::EventObserver {
+ public:
+  AppLaunchTracker(extensions::TestEventRouter* event_router) {
+    observation_.Observe(event_router);
+  }
+  AppLaunchTracker(const AppLaunchTracker&) = delete;
+  AppLaunchTracker& operator=(const AppLaunchTracker&) = delete;
+
+  std::vector<std::string> launched_apps() const { return launched_apps_; }
+
+  // TestEventRouter::EventObserver:
+  void OnBroadcastEvent(const extensions::Event& event) override {
+    ADD_FAILURE() << "Unexpected broadcast " << event.event_name;
+  }
+
+  void OnDispatchEventToExtension(const std::string& extension_id,
+                                  const extensions::Event& event) override {
+    ASSERT_EQ(event.event_name,
+              extensions::api::app_runtime::OnLaunched::kEventName);
+    ASSERT_TRUE(event.event_args);
+    ASSERT_EQ(1u, event.event_args->GetListDeprecated().size());
+
+    const base::Value& launch_data = event.event_args->GetListDeprecated()[0];
+    const base::Value* is_kiosk_session =
+        launch_data.FindKeyOfType("isKioskSession", base::Value::Type::BOOLEAN);
+    ASSERT_TRUE(is_kiosk_session);
+    EXPECT_TRUE(is_kiosk_session->GetBool());
+
+    launched_apps_.push_back(extension_id);
+  }
+
+ private:
+  const std::string app_id_;
+  base::ScopedObservation<extensions::TestEventRouter,
+                          extensions::TestEventRouter::EventObserver,
+                          &extensions::TestEventRouter::AddEventObserver,
+                          &extensions::TestEventRouter::RemoveEventObserver>
+      observation_{this};
+  std::vector<std::string> launched_apps_;
+};
+}  // namespace
+
+class ChromeKioskAppLauncherTest : public extensions::ExtensionServiceTestBase,
+                                   extensions::TestEventRouter::EventObserver {
+ public:
+  // testing::Test:
+  void SetUp() override {
+    command_line_.GetProcessCommandLine()->AppendSwitch(
+        switches::kForceAppMode);
+    command_line_.GetProcessCommandLine()->AppendSwitch(switches::kAppId);
+
+    extensions::ExtensionServiceTestBase::SetUp();
+    InitializeEmptyExtensionService();
+
+    extensions::TestEventRouter* event_router =
+        extensions::CreateAndUseTestEventRouter(browser_context());
+    app_launch_tracker_ = std::make_unique<AppLaunchTracker>(event_router);
+  }
+
+  void TearDown() override {
+    app_launch_tracker_.reset();
+
+    extensions::ExtensionServiceTestBase::TearDown();
+  }
+
+ protected:
+  void CreateLauncher(bool is_network_ready) {
+    launcher_ = std::make_unique<ChromeKioskAppLauncher>(
+        profile(), kTestPrimaryAppId, is_network_ready);
+  }
+
+  std::unique_ptr<ChromeKioskAppLauncher> launcher_;
+  std::unique_ptr<AppLaunchTracker> app_launch_tracker_;
+
+ private:
+  base::test::ScopedCommandLine command_line_;
+};
+
+TEST_F(ChromeKioskAppLauncherTest, ShouldFailIfPrimaryAppNotInstalled) {
+  CreateLauncher(/*is_network_ready=*/true);
+
+  TestFuture<LaunchResult> future;
+  launcher_->LaunchApp(future.GetCallback());
+
+  ASSERT_THAT(future.Get(), Eq(LaunchResult::kUnableToLaunch));
+  ASSERT_THAT(app_launch_tracker_->launched_apps(), IsEmpty());
+}
+
+TEST_F(ChromeKioskAppLauncherTest, ShouldFailIfSecondaryAppNotInstalled) {
+  TestKioskExtensionBuilder primary_app_builder(Manifest::TYPE_PLATFORM_APP,
+                                                kTestPrimaryAppId);
+  primary_app_builder.set_version("1.0");
+  primary_app_builder.AddSecondaryExtension(kSecondaryAppId);
+  scoped_refptr<const extensions::Extension> primary_app =
+      primary_app_builder.Build();
+  service()->AddExtension(primary_app.get());
+
+  CreateLauncher(/*is_network_ready=*/true);
+
+  TestFuture<LaunchResult> future;
+  launcher_->LaunchApp(future.GetCallback());
+
+  ASSERT_THAT(future.Get(), Eq(LaunchResult::kUnableToLaunch));
+  ASSERT_THAT(app_launch_tracker_->launched_apps(), IsEmpty());
+}
+
+TEST_F(ChromeKioskAppLauncherTest,
+       ShouldReportNetworkMissingIfAppNotOfflineEnabled) {
+  TestKioskExtensionBuilder primary_app_builder(Manifest::TYPE_PLATFORM_APP,
+                                                kTestPrimaryAppId);
+  primary_app_builder.set_version("1.0");
+  primary_app_builder.set_offline_enabled(false);
+  scoped_refptr<const extensions::Extension> primary_app =
+      primary_app_builder.Build();
+  service()->AddExtension(primary_app.get());
+
+  CreateLauncher(/*is_network_ready=*/false);
+
+  TestFuture<LaunchResult> future;
+  launcher_->LaunchApp(future.GetCallback());
+
+  ASSERT_THAT(future.Get(), Eq(LaunchResult::kNetworkMissing));
+  ASSERT_THAT(app_launch_tracker_->launched_apps(), IsEmpty());
+}
+
+TEST_F(ChromeKioskAppLauncherTest, ShouldSucceedIfNetworkAvailable) {
+  TestKioskExtensionBuilder primary_app_builder(Manifest::TYPE_PLATFORM_APP,
+                                                kTestPrimaryAppId);
+  primary_app_builder.set_version("1.0");
+  scoped_refptr<const extensions::Extension> primary_app =
+      primary_app_builder.Build();
+  service()->AddExtension(primary_app.get());
+
+  CreateLauncher(/*is_network_ready=*/true);
+
+  TestFuture<LaunchResult> future;
+  launcher_->LaunchApp(future.GetCallback());
+
+  ASSERT_THAT(future.Get(), Eq(LaunchResult::kSuccess));
+
+  EXPECT_THAT(app_launch_tracker_->launched_apps(),
+              ElementsAre(kTestPrimaryAppId));
+  EXPECT_TRUE(registry()->enabled_extensions().Contains(kTestPrimaryAppId));
+}
+
+TEST_F(ChromeKioskAppLauncherTest, ShouldSucceedWithSecondaryApp) {
+  TestKioskExtensionBuilder primary_app_builder(Manifest::TYPE_PLATFORM_APP,
+                                                kTestPrimaryAppId);
+  primary_app_builder.set_version("1.0");
+  primary_app_builder.AddSecondaryExtension(kSecondaryAppId);
+  primary_app_builder.AddSecondaryExtensionWithEnabledOnLaunch(
+      kExtraSecondaryAppId, false);
+  scoped_refptr<const extensions::Extension> primary_app =
+      primary_app_builder.Build();
+  service()->AddExtension(primary_app.get());
+
+  TestKioskExtensionBuilder secondary_app_builder(Manifest::TYPE_PLATFORM_APP,
+                                                  kSecondaryAppId);
+  secondary_app_builder.set_kiosk_enabled(false);
+  scoped_refptr<const extensions::Extension> secondary_app =
+      secondary_app_builder.Build();
+  service()->AddExtension(secondary_app.get());
+
+  TestKioskExtensionBuilder extra_secondary_app_builder(
+      Manifest::TYPE_PLATFORM_APP, kExtraSecondaryAppId);
+  extra_secondary_app_builder.set_kiosk_enabled(false);
+  scoped_refptr<const extensions::Extension> extra_secondary_app =
+      extra_secondary_app_builder.Build();
+  service()->AddExtension(extra_secondary_app.get());
+
+  CreateLauncher(/*is_network_ready=*/true);
+
+  TestFuture<LaunchResult> future;
+  launcher_->LaunchApp(future.GetCallback());
+
+  ASSERT_THAT(future.Get(), Eq(LaunchResult::kSuccess));
+
+  EXPECT_THAT(app_launch_tracker_->launched_apps(),
+              ElementsAre(kTestPrimaryAppId));
+  EXPECT_TRUE(registry()->enabled_extensions().Contains(kTestPrimaryAppId));
+  EXPECT_TRUE(registry()->enabled_extensions().Contains(kSecondaryAppId));
+  EXPECT_TRUE(registry()->disabled_extensions().Contains(kExtraSecondaryAppId));
+}
+
+}  // namespace ash
diff --git a/chrome/browser/component_updater/registration.cc b/chrome/browser/component_updater/registration.cc
index 6f6ae84..50b2e19 100644
--- a/chrome/browser/component_updater/registration.cc
+++ b/chrome/browser/component_updater/registration.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/component_updater/commerce_heuristics_component_installer.h"
 #include "chrome/browser/component_updater/desktop_screenshot_editor_component_installer.h"
 #include "chrome/browser/component_updater/desktop_sharing_hub_component_installer.h"
-#include "chrome/browser/component_updater/soda_component_installer.h"
 #include "chrome/browser/component_updater/zxcvbn_data_component_installer.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "media/base/media_switches.h"
@@ -90,6 +89,10 @@
 #include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
 #endif  // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
 
+#if BUILDFLAG(IS_LINUX)
+#include "chrome/browser/component_updater/screen_ai_component_installer.h"
+#endif  // BUILDFLAG(IS_LINUX)
+
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
 #endif
@@ -209,6 +212,10 @@
   RegisterAutofillRegexComponent(cus);
 
   RegisterClientSidePhishingComponent(cus);
+
+#if BUILDFLAG(IS_LINUX)
+  RegisterScreenAIComponent(cus, g_browser_process->local_state());
+#endif  // BUILDFLAG(IS_LINUX)
 }
 
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/screen_ai_component_installer.cc b/chrome/browser/component_updater/screen_ai_component_installer.cc
new file mode 100644
index 0000000..96c074c
--- /dev/null
+++ b/chrome/browser/component_updater/screen_ai_component_installer.cc
@@ -0,0 +1,152 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/screen_ai_component_installer.h"
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/crx_file/id_util.h"
+#include "components/services/screen_ai/public/cpp/pref_names.h"
+#include "components/services/screen_ai/public/cpp/utilities.h"
+#include "components/update_client/update_client_errors.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/sha2.h"
+#include "ui/accessibility/accessibility_features.h"
+
+using content::BrowserThread;
+
+namespace {
+
+const int kScreenAICleanUpDelayInDays = 30;
+
+// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
+// The component id is: mfhmdacoffpmifoibamicehhklffanao
+constexpr uint8_t kScreenAIPublicKeySHA256[32] = {
+    0xc5, 0x7c, 0x30, 0x2e, 0x55, 0xfc, 0x85, 0xe8, 0x10, 0xc8, 0x24,
+    0x77, 0xab, 0x55, 0x0d, 0x0e, 0x5a, 0xed, 0x04, 0x7b, 0x1e, 0x16,
+    0x86, 0x7c, 0xf0, 0x42, 0x71, 0x85, 0xe4, 0x31, 0x2d, 0xc5};
+
+static_assert(std::size(kScreenAIPublicKeySHA256) == crypto::kSHA256Length,
+              "Wrong hash length");
+
+constexpr char kScreenAIManifestName[] = "ScreenAI Library";
+
+}  // namespace
+
+namespace component_updater {
+
+ScreenAIComponentInstallerPolicy::ScreenAIComponentInstallerPolicy() = default;
+
+ScreenAIComponentInstallerPolicy::~ScreenAIComponentInstallerPolicy() = default;
+
+bool ScreenAIComponentInstallerPolicy::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  return true;
+}
+
+bool ScreenAIComponentInstallerPolicy::RequiresNetworkEncryption() const {
+  // This component is deployed only to the users of assistive technologies.
+  // Tracking it reveals personal information about the user.
+  return true;
+}
+
+update_client::CrxInstaller::Result
+ScreenAIComponentInstallerPolicy::OnCustomInstall(
+    const base::Value& manifest,
+    const base::FilePath& install_dir) {
+  return update_client::CrxInstaller::Result(update_client::InstallError::NONE);
+}
+
+void ScreenAIComponentInstallerPolicy::OnCustomUninstall() {}
+
+void ScreenAIComponentInstallerPolicy::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    base::Value manifest) {
+  VLOG(1) << "Screen AI Component ready, version " << version.GetString()
+          << " in " << install_dir.value();
+}
+
+bool ScreenAIComponentInstallerPolicy::VerifyInstallation(
+    const base::Value& manifest,
+    const base::FilePath& install_dir) const {
+  // TODO(https://crbug.com/1278249): Consider trying to open and initialize the
+  // library.
+  VLOG(1) << "Verifying Screen AI Library in " << install_dir.value();
+  return screen_ai::GetLibraryFilePath().DirName() == install_dir;
+}
+
+base::FilePath ScreenAIComponentInstallerPolicy::GetRelativeInstallDir() const {
+  return screen_ai::GetRelativeInstallDir();
+}
+
+void ScreenAIComponentInstallerPolicy::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(kScreenAIPublicKeySHA256,
+               kScreenAIPublicKeySHA256 + std::size(kScreenAIPublicKeySHA256));
+}
+
+std::string ScreenAIComponentInstallerPolicy::GetName() const {
+  return kScreenAIManifestName;
+}
+
+update_client::InstallerAttributes
+ScreenAIComponentInstallerPolicy::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
+// static
+void ScreenAIComponentInstallerPolicy::DeleteLibraryOrScheduleDeletionIfNeeded(
+    PrefService* global_prefs) {
+  base::FilePath library_path = screen_ai::GetLibraryFilePath();
+  if (library_path.empty())
+    return;
+
+  base::Time deletion_time =
+      global_prefs->GetTime(prefs::kScreenAIScheduledDeletionTimePrefName);
+
+  // Set deletion time if it is not set yet.
+  if (deletion_time.is_null()) {
+    global_prefs->SetTime(
+        prefs::kScreenAIScheduledDeletionTimePrefName,
+        base::Time::Now() + base::Days(kScreenAICleanUpDelayInDays));
+    return;
+  }
+
+  if (deletion_time <= base::Time::Now()) {
+    // If there are more than one instance of the library, delete them as well.
+    do {
+      base::DeletePathRecursively(library_path.DirName());
+      library_path = screen_ai::GetLibraryFilePath();
+    } while (!library_path.empty());
+    global_prefs->SetTime(prefs::kScreenAIScheduledDeletionTimePrefName,
+                          base::Time());
+  }
+}
+
+void RegisterScreenAIComponent(ComponentUpdateService* cus,
+                               PrefService* global_prefs) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (!features::IsScreenAIEnabled()) {
+    ScreenAIComponentInstallerPolicy::DeleteLibraryOrScheduleDeletionIfNeeded(
+        global_prefs);
+    return;
+  }
+
+  // Remove scheduled time for deletion as feature is enabled.
+  global_prefs->SetTime(prefs::kScreenAIScheduledDeletionTimePrefName,
+                        base::Time());
+
+  auto installer = base::MakeRefCounted<ComponentInstaller>(
+      std::make_unique<ScreenAIComponentInstallerPolicy>());
+  installer->Register(cus, base::OnceClosure());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/screen_ai_component_installer.h b/chrome/browser/component_updater/screen_ai_component_installer.h
new file mode 100644
index 0000000..4b2b7ca
--- /dev/null
+++ b/chrome/browser/component_updater/screen_ai_component_installer.h
@@ -0,0 +1,54 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_SCREEN_AI_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_SCREEN_AI_COMPONENT_INSTALLER_H_
+
+#include <string>
+
+#include "components/component_updater/component_installer.h"
+#include "components/prefs/pref_service.h"
+#include "components/update_client/update_client.h"
+
+namespace component_updater {
+
+class ScreenAIComponentInstallerPolicy : public ComponentInstallerPolicy {
+ public:
+  ScreenAIComponentInstallerPolicy();
+  ScreenAIComponentInstallerPolicy(const ScreenAIComponentInstallerPolicy&) =
+      delete;
+  ScreenAIComponentInstallerPolicy& operator=(
+      const ScreenAIComponentInstallerPolicy&) = delete;
+  ~ScreenAIComponentInstallerPolicy() override;
+
+  static void DeleteLibraryOrScheduleDeletionIfNeeded(
+      PrefService* global_prefs);
+
+ private:
+  // ComponentInstallerPolicy::
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::Value& manifest,
+      const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
+  bool VerifyInstallation(const base::Value& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& install_dir,
+                      base::Value manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+};
+
+// Call once during startup to make the component update service aware of
+// the ScreenAI component.
+void RegisterScreenAIComponent(ComponentUpdateService* cus,
+                               PrefService* global_prefs);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_SCREEN_AI_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index 98e24cb7..bd8cef4 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -479,6 +479,12 @@
   base::RunLoop::QuitCurrentWhenIdleDeprecated();
 }
 
+constexpr char kPublicKey[] =
+    "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+    "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+    "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+    "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+
 // Base class for DevTools tests that test devtools functionality for
 // extensions and content scripts.
 class DevToolsExtensionTest : public DevToolsTest {
@@ -624,6 +630,27 @@
     return LoadExtensionFromPath(dir->UnpackedPath());
   }
 
+  std::string BuildComponentExtension() {
+    extensions::ExtensionService* extension_service =
+        extensions::ExtensionSystem::Get(browser()->profile())
+            ->extension_service();
+    extensions::ComponentLoader* component_loader =
+        extension_service->component_loader();
+    extensions::ExtensionRegistry* extension_registry =
+        extensions::ExtensionRegistry::Get(browser()->profile());
+
+    extensions::TestExtensionDir* extension_dir =
+        BuildExtensionForTest("Component extension", "" /* devtools_page */,
+                              "" /* panel_iframe_src */);
+    std::string manifest = BuildExtensionManifest(
+        "Component extension", "" /* devtools_page */, kPublicKey);
+    component_loader->set_ignore_allowlist_for_testing(true);
+    std::string extension_id =
+        component_loader->Add(manifest, extension_dir->UnpackedPath());
+    EXPECT_TRUE(extension_registry->enabled_extensions().GetByID(extension_id));
+    return extension_id;
+  }
+
  private:
   const Extension* GetExtensionByPath(
       const extensions::ExtensionSet& extensions,
@@ -1649,13 +1676,6 @@
   RunTest("testConsoleContextNames", kPageWithContentScript);
 }
 
-constexpr char kExtensionId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
-constexpr char kPublicKey[] =
-    "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
-    "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
-    "kDuI7caxEGUucpP7GJRRHnm8Sx+"
-    "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
-
 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest, CantInspectChromeScheme) {
   LoadExtension("can_inspect_url");
   RunTest("waitForTestResultsAsMessage",
@@ -1670,30 +1690,32 @@
                     "#devtools://devtools/bundled/devtools_compatibility.js"}));
 }
 
-IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest, CantInspectComponentExtension) {
-  extensions::ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(browser()->profile())
-          ->extension_service();
-  extensions::ComponentLoader* component_loader =
-      extension_service->component_loader();
-  extensions::ExtensionRegistry* extension_registry =
-      extensions::ExtensionRegistry::Get(browser()->profile());
-
-  extensions::TestExtensionDir* extension_dir = BuildExtensionForTest(
-      "Component extension", "" /* devtools_page */, "" /* panel_iframe_src */);
-  std::string manifest = BuildExtensionManifest(
-      "Component extension", "" /* devtools_page */, kPublicKey);
-  component_loader->set_ignore_allowlist_for_testing(true);
-  std::string extension_id =
-      component_loader->Add(manifest, extension_dir->UnpackedPath());
-  ASSERT_TRUE(extension_registry->enabled_extensions().GetByID(extension_id));
-
+IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
+                       CantInspectViewSourceDevtoolsScheme) {
   LoadExtension("can_inspect_url");
   RunTest("waitForTestResultsAsMessage",
-          base::StrCat({kArbitraryPage, "#chrome-extension://", kExtensionId,
+          base::StrCat({kArbitraryPage,
+                        "#view-source:devtools://devtools/bundled/"
+                        "devtools_compatibility.js"}));
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest, CantInspectComponentExtension) {
+  std::string extension_id = BuildComponentExtension();
+  LoadExtension("can_inspect_url");
+  RunTest("waitForTestResultsAsMessage",
+          base::StrCat({kArbitraryPage, "#chrome-extension://", extension_id,
                         "/simple_test_page.html"}));
 }
 
+IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
+                       CantInspectViewSourceComponentExtension) {
+  std::string extension_id = BuildComponentExtension();
+  LoadExtension("can_inspect_url");
+  RunTest("waitForTestResultsAsMessage",
+          base::StrCat({kArbitraryPage, "#view-source:chrome-extension://",
+                        extension_id, "/simple_test_page.html"}));
+}
+
 // Tests that scripts are not duplicated after Scripts Panel switch.
 IN_PROC_BROWSER_TEST_F(DevToolsTest, TestNoScriptDuplicatesOnPanelSwitch) {
   RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
diff --git a/chrome/browser/extensions/api/autofill_private/OWNERS b/chrome/browser/extensions/api/autofill_private/OWNERS
index 6c958ae6..443a569 100644
--- a/chrome/browser/extensions/api/autofill_private/OWNERS
+++ b/chrome/browser/extensions/api/autofill_private/OWNERS
@@ -1,3 +1 @@
 file://chrome/browser/resources/settings/OWNERS
-
-jdoerrie@chromium.org
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
index 9414d4a2..ed6e4e3 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
@@ -128,14 +128,7 @@
   RunTest(base::StringPrintf(kTest, kAssertions));
 }
 
-#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
-// https://crbug.com/1222670
-#define MAYBE_GetPersistentSecret DISABLED_GetPersistentSecret
-#else
-#define MAYBE_GetPersistentSecret GetPersistentSecret
-#endif
-IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
-                       MAYBE_GetPersistentSecret) {
+IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetPersistentSecret) {
   constexpr char kAssertions[] =
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
       "chrome.test.assertNoLastError();"
diff --git a/chrome/browser/extensions/api/passwords_private/OWNERS b/chrome/browser/extensions/api/passwords_private/OWNERS
index d7d0c6aa..eaa48b0 100644
--- a/chrome/browser/extensions/api/passwords_private/OWNERS
+++ b/chrome/browser/extensions/api/passwords_private/OWNERS
@@ -1,4 +1,2 @@
 file://chrome/browser/resources/settings/OWNERS
-
-jdoerrie@chromium.org
 vsemeniuk@google.com
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 32a956c9..b26ed41 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1950,7 +1950,7 @@
   {
     "name": "enable-disco-feed-endpoint",
     "owners": [ "adamta", "sczs" ],
-    "expiry_milestone": 101
+    "expiry_milestone": 106
   },
   {
     "name": "enable-discount-consent-v2",
@@ -1965,12 +1965,12 @@
   {
     "name": "enable-discover-feed-shorter-cache",
     "owners": [ "edchin", "adamta", "sczs" ],
-    "expiry_milestone": 101
+    "expiry_milestone": 106
   },
   {
     "name": "enable-discover-feed-static-resource-serving",
     "owners": [ "adamta", "sczs" ],
-    "expiry_milestone": 101
+    "expiry_milestone": 106
   },
   {
     "name": "enable-dns-proxy",
@@ -2345,11 +2345,6 @@
     "expiry_milestone": 92
   },
   {
-    "name": "enable-manual-password-generation",
-    "owners": [ "kazinova@google.com" ],
-    "expiry_milestone": 96
-  },
-  {
     "name": "enable-media-foundation-clear",
     "owners": [
       "wicarr@microsoft.com"
diff --git a/chrome/browser/lacros/launcher_search/search_controller_lacros.cc b/chrome/browser/lacros/launcher_search/search_controller_lacros.cc
index 7d1f7be0..d10b8fd 100644
--- a/chrome/browser/lacros/launcher_search/search_controller_lacros.cc
+++ b/chrome/browser/lacros/launcher_search/search_controller_lacros.cc
@@ -12,20 +12,9 @@
 #include "chrome/browser/lacros/launcher_search/search_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/lacros/lacros_service.h"
-#include "components/omnibox/browser/autocomplete_classifier.h"
+#include "components/keyed_service/core/service_access_type.h"
 
 namespace crosapi {
-namespace {
-
-int ProviderTypes() {
-  // We use all the default providers except for the document provider, which
-  // suggests Drive files on enterprise devices. This is disabled to avoid
-  // duplication with search results from DriveFS.
-  return AutocompleteClassifier::DefaultOmniboxProviders() &
-         ~AutocompleteProvider::TYPE_DOCUMENT;
-}
-
-}  // namespace
 
 SearchControllerLacros::SearchControllerLacros()
     : profile_(g_browser_process->profile_manager()->GetProfileByPath(
@@ -93,6 +82,8 @@
   if (input.text().empty())
     input.set_focus_type(OmniboxFocusType::ON_FOCUS);
 
+  query_ = query;
+  input_ = input;
   autocomplete_controller_->Start(input);
 }
 
@@ -102,13 +93,12 @@
 
   std::vector<mojom::SearchResultPtr> results;
   for (AutocompleteMatch match : autocomplete_controller_->result()) {
-    if (match.search_terms_args) {
-      match.search_terms_args->request_source = TemplateURLRef::CROS_APP_LIST;
-      autocomplete_controller_->SetMatchDestinationURL(&match);
-    }
+    auto result =
+        match.answer.has_value()
+            ? CreateAnswerResult(match, autocomplete_controller_.get(), input_)
+            : CreateResult(match, autocomplete_controller_.get(), query_,
+                           input_);
 
-    auto result = match.answer.has_value() ? CreateAnswerResult(match)
-                                           : CreateResult(match);
     results.push_back(std::move(result));
   }
 
diff --git a/chrome/browser/lacros/launcher_search/search_controller_lacros.h b/chrome/browser/lacros/launcher_search/search_controller_lacros.h
index 7dce0063..bc5415e 100644
--- a/chrome/browser/lacros/launcher_search/search_controller_lacros.h
+++ b/chrome/browser/lacros/launcher_search/search_controller_lacros.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile_observer.h"
 #include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 #include "components/omnibox/browser/autocomplete_controller.h"
+#include "components/omnibox/browser/autocomplete_input.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -42,6 +43,9 @@
   Profile* profile_;
   std::unique_ptr<AutocompleteController> autocomplete_controller_;
 
+  std::u16string query_;
+  AutocompleteInput input_;
+
   mojo::AssociatedRemote<mojom::SearchResultsPublisher> publisher_;
   mojo::Receiver<mojom::SearchController> receiver_{this};
 
diff --git a/chrome/browser/lacros/launcher_search/search_util.cc b/chrome/browser/lacros/launcher_search/search_util.cc
index f2bc5faf..a19b8e7 100644
--- a/chrome/browser/lacros/launcher_search/search_util.cc
+++ b/chrome/browser/lacros/launcher_search/search_util.cc
@@ -4,37 +4,45 @@
 
 #include "chrome/browser/lacros/launcher_search/search_util.h"
 
+#include "base/callback_helpers.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/omnibox/browser/autocomplete_classifier.h"
+#include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
+#include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/favicon_cache.h"
 #include "components/omnibox/browser/suggestion_answer.h"
+#include "ui/base/page_transition_types.h"
 
 namespace crosapi {
 namespace {
 
-using AnswerType = mojom::SearchResult::AnswerType;
-using OmniboxType = mojom::SearchResult::OmniboxType;
+using mojom::SearchResult;
+using mojom::SearchResultPtr;
 
-AnswerType MatchTypeToAnswerType(const int type) {
+SearchResult::AnswerType MatchTypeToAnswerType(const int type) {
   switch (static_cast<SuggestionAnswer::AnswerType>(type)) {
     case SuggestionAnswer::ANSWER_TYPE_WEATHER:
-      return AnswerType::kWeather;
+      return SearchResult::AnswerType::kWeather;
     case SuggestionAnswer::ANSWER_TYPE_CURRENCY:
-      return AnswerType::kCurrency;
+      return SearchResult::AnswerType::kCurrency;
     case SuggestionAnswer::ANSWER_TYPE_DICTIONARY:
-      return AnswerType::kDictionary;
+      return SearchResult::AnswerType::kDictionary;
     case SuggestionAnswer::ANSWER_TYPE_FINANCE:
-      return AnswerType::kFinance;
+      return SearchResult::AnswerType::kFinance;
     case SuggestionAnswer::ANSWER_TYPE_SUNRISE:
-      return AnswerType::kSunrise;
+      return SearchResult::AnswerType::kSunrise;
     case SuggestionAnswer::ANSWER_TYPE_TRANSLATION:
-      return AnswerType::kTranslation;
+      return SearchResult::AnswerType::kTranslation;
     case SuggestionAnswer::ANSWER_TYPE_WHEN_IS:
-      return AnswerType::kWhenIs;
+      return SearchResult::AnswerType::kWhenIs;
     default:
-      return AnswerType::kDefaultAnswer;
+      return SearchResult::AnswerType::kDefaultAnswer;
   }
 }
 
-OmniboxType MatchTypeToOmniboxType(const AutocompleteMatchType::Type type) {
+SearchResult::OmniboxType MatchTypeToOmniboxType(
+    const AutocompleteMatchType::Type type) {
   switch (type) {
     case AutocompleteMatchType::URL_WHAT_YOU_TYPED:
     case AutocompleteMatchType::HISTORY_URL:
@@ -50,7 +58,7 @@
     case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
     case AutocompleteMatchType::DOCUMENT_SUGGESTION:
     case AutocompleteMatchType::PEDAL_DEPRECATED:
-      return OmniboxType::kDomain;
+      return SearchResult::OmniboxType::kDomain;
 
     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
     case AutocompleteMatchType::SEARCH_SUGGEST:
@@ -62,103 +70,167 @@
     case AutocompleteMatchType::VOICE_SUGGEST:
     case AutocompleteMatchType::CLIPBOARD_TEXT:
     case AutocompleteMatchType::CLIPBOARD_IMAGE:
-      return OmniboxType::kSearch;
+      return SearchResult::OmniboxType::kSearch;
 
     case AutocompleteMatchType::SEARCH_HISTORY:
     case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED:
-      return OmniboxType::kHistory;
+      return SearchResult::OmniboxType::kHistory;
 
     case AutocompleteMatchType::CALCULATOR:
-      return OmniboxType::kCalculator;
+      return SearchResult::OmniboxType::kCalculator;
 
     case AutocompleteMatchType::OPEN_TAB:
-      return OmniboxType::kOpenTab;
+      return SearchResult::OmniboxType::kOpenTab;
 
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::TILE_SUGGESTION:
     case AutocompleteMatchType::TILE_NAVSUGGEST:
     case AutocompleteMatchType::NUM_TYPES:
       // Not reached.
-      return OmniboxType::kDomain;
+      return SearchResult::OmniboxType::kDomain;
   }
 }
 
-// Returns the first text field from the given ImageLine.
-std::u16string GetFirstText(const SuggestionAnswer::ImageLine& line) {
-  return line.text_fields().empty() ? std::u16string()
-                                    : line.text_fields()[0].text();
-}
-
-std::u16string GetAdditionalText(const SuggestionAnswer::ImageLine& line) {
-  return line.additional_text() ? line.additional_text()->text()
-                                : std::u16string();
-}
-
-mojom::SearchResult::TextType GetAdditionalTextType(
-    const SuggestionAnswer::ImageLine& line) {
-  if (!line.additional_text())
-    return mojom::SearchResult::TextType::kUnset;
-
-  switch (line.additional_text()->style()) {
+SearchResult::TextType TextStyleToType(
+    const SuggestionAnswer::TextStyle style) {
+  switch (style) {
     case SuggestionAnswer::TextStyle::POSITIVE:
-      return mojom::SearchResult::TextType::kPositive;
+      return SearchResult::TextType::kPositive;
     case SuggestionAnswer::TextStyle::NEGATIVE:
-      return mojom::SearchResult::TextType::kNegative;
+      return SearchResult::TextType::kNegative;
     default:
-      return mojom::SearchResult::TextType::kUnset;
+      return SearchResult::TextType::kUnset;
   }
 }
 
-mojom::SearchResultPtr CreateBaseResult(const AutocompleteMatch& match) {
-  mojom::SearchResultPtr result = mojom::SearchResult::New();
+SearchResult::TextType ClassesToType(
+    const ACMatchClassifications& text_classes) {
+  // Only retain the URL class, other classes are either ignored. Tag indices
+  // are also ignored since they will apply to the entire text.
+  for (const auto& text_class : text_classes) {
+    if (text_class.style & ACMatchClassification::URL) {
+      return SearchResult::TextType::kUrl;
+    }
+  }
+
+  return SearchResult::TextType::kUnset;
+}
+
+SearchResultPtr CreateBaseResult(AutocompleteMatch& match,
+                                 AutocompleteController* controller,
+                                 const AutocompleteInput& input) {
+  SearchResultPtr result = SearchResult::New();
+
+  if (controller && match.search_terms_args) {
+    match.search_terms_args->request_source = TemplateURLRef::CROS_APP_LIST;
+    controller->SetMatchDestinationURL(&match);
+  }
 
   result->type = mojom::SearchResultType::kOmniboxResult;
   result->relevance = match.relevance;
   result->destination_url = match.destination_url;
+
+  if (controller && match.stripped_destination_url.spec().empty()) {
+    match.ComputeStrippedDestinationURL(
+        input,
+        controller->autocomplete_provider_client()->GetTemplateURLService());
+  }
+  result->stripped_destination_url = match.stripped_destination_url;
+
+  if (ui::PageTransitionCoreTypeIs(
+          match.transition, ui::PageTransition::PAGE_TRANSITION_GENERATED)) {
+    result->page_transition = SearchResult::PageTransition::kGenerated;
+  } else {
+    result->page_transition = SearchResult::PageTransition::kTyped;
+  }
+
   result->is_omnibox_search = AutocompleteMatch::IsSearchType(match.type)
-                                  ? mojom::SearchResult::OptionalBool::kTrue
-                                  : mojom::SearchResult::OptionalBool::kFalse;
+                                  ? SearchResult::OptionalBool::kTrue
+                                  : SearchResult::OptionalBool::kFalse;
   return result;
 }
 
 }  // namespace
 
-mojom::SearchResultPtr CreateAnswerResult(const AutocompleteMatch& match) {
-  mojom::SearchResultPtr result = CreateBaseResult(match);
+int ProviderTypes() {
+  // We use all the default providers except for the document provider, which
+  // suggests Drive files on enterprise devices. This is disabled to avoid
+  // duplication with search results from DriveFS.
+  int providers = AutocompleteClassifier::DefaultOmniboxProviders() &
+                  ~AutocompleteProvider::TYPE_DOCUMENT;
 
-  result->is_answer = mojom::SearchResult::OptionalBool::kTrue;
+  return providers;
+}
+
+SearchResultPtr CreateAnswerResult(AutocompleteMatch& match,
+                                   AutocompleteController* controller,
+                                   const AutocompleteInput& input) {
+  SearchResultPtr result = CreateBaseResult(match, controller, input);
+
+  result->is_answer = SearchResult::OptionalBool::kTrue;
   result->answer_type = MatchTypeToAnswerType(match.answer->type());
 
-  if (result->answer_type == AnswerType::kWeather)
+  if (result->answer_type == SearchResult::AnswerType::kWeather)
     result->image_url = match.answer->image_url();
 
   result->contents = match.contents;
-  result->additional_contents = GetAdditionalText(match.answer->first_line());
 
-  const auto& second_line = match.answer->second_line();
-  result->description = GetFirstText(second_line);
-  result->additional_description = GetAdditionalText(second_line);
-  result->additional_description_type = GetAdditionalTextType(second_line);
+  const auto& first = match.answer->first_line();
+  if (first.additional_text()) {
+    result->additional_contents = first.additional_text()->text();
+    result->additional_contents_type =
+        TextStyleToType(first.additional_text()->style());
+  }
+
+  const auto& second = match.answer->second_line();
+  if (!second.text_fields().empty()) {
+    // Only extract the first text field.
+    result->description = second.text_fields()[0].text();
+    result->description_type = TextStyleToType(second.text_fields()[0].style());
+  }
+  if (second.additional_text()) {
+    result->additional_description = second.additional_text()->text();
+    result->additional_description_type =
+        TextStyleToType(second.additional_text()->style());
+  }
 
   return result;
 }
 
-mojom::SearchResultPtr CreateResult(const AutocompleteMatch& match) {
-  mojom::SearchResultPtr result = CreateBaseResult(match);
+SearchResultPtr CreateResult(AutocompleteMatch& match,
+                             AutocompleteController* controller,
+                             const std::u16string& query,
+                             const AutocompleteInput& input) {
+  SearchResultPtr result = CreateBaseResult(match, controller, input);
 
-  result->is_answer = mojom::SearchResult::OptionalBool::kFalse;
+  result->is_answer = SearchResult::OptionalBool::kFalse;
 
   if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY &&
       !match.image_url.is_empty()) {
-    result->omnibox_type = OmniboxType::kRichImage;
+    result->omnibox_type = SearchResult::OmniboxType::kRichImage;
     result->image_url = match.image_url;
   } else {
-    // TODO(crbug.com/1228687): Implement favicon logic.
+    // This may not be the final type. Favicons and bookmarks take precedence.
     result->omnibox_type = MatchTypeToOmniboxType(match.type);
+
+    // TODO(crbug.com/1228587): Implement favicon and bookmark logic.
   }
 
-  result->contents = match.contents;
-  result->description = match.description;
+  // Calculator results come in two forms:
+  // 1) Answer in |contents|, empty |description|,
+  // 2) Query in |contents|, answer in |description|.
+  // For case 1, we should manually populate the query.
+  if (result->omnibox_type == SearchResult::OmniboxType::kCalculator &&
+      match.description.empty()) {
+    result->contents = query;
+    result->description = match.contents;
+    result->description_type = ClassesToType(match.contents_class);
+  } else {
+    result->contents = match.contents;
+    result->contents_type = ClassesToType(match.contents_class);
+    result->description = match.description;
+    result->description_type = ClassesToType(match.description_class);
+  }
 
   return result;
 }
diff --git a/chrome/browser/lacros/launcher_search/search_util.h b/chrome/browser/lacros/launcher_search/search_util.h
index bb4a788..c7ecd7ec 100644
--- a/chrome/browser/lacros/launcher_search/search_util.h
+++ b/chrome/browser/lacros/launcher_search/search_util.h
@@ -6,15 +6,30 @@
 #define CHROME_BROWSER_LACROS_LAUNCHER_SEARCH_SEARCH_UTIL_H_
 
 #include "chromeos/crosapi/mojom/launcher_search.mojom.h"
+#include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 
+class AutocompleteController;
+
 namespace crosapi {
 
+// TODO(crbug.com/1228587): This code will be shared with ash. Move this file
+// into an appropriate location.
+
+// Returns a bitmask of the AutocompleteProvider types to be used by Launcher
+// search.
+int ProviderTypes();
+
 // Creates an Omnibox answer card result from the AutocompleteMatch.
-mojom::SearchResultPtr CreateAnswerResult(const AutocompleteMatch& match);
+mojom::SearchResultPtr CreateAnswerResult(AutocompleteMatch& match,
+                                          AutocompleteController* controller,
+                                          const AutocompleteInput& input);
 
 // Creates an Omnibox search result from the AutocompleteMatch.
-mojom::SearchResultPtr CreateResult(const AutocompleteMatch& match);
+mojom::SearchResultPtr CreateResult(AutocompleteMatch& match,
+                                    AutocompleteController* controller,
+                                    const std::u16string& query,
+                                    const AutocompleteInput& input);
 
 }  // namespace crosapi
 
diff --git a/chrome/browser/lacros/launcher_search/search_util_unittest.cc b/chrome/browser/lacros/launcher_search/search_util_unittest.cc
index 4a582c6..6105ec6 100644
--- a/chrome/browser/lacros/launcher_search/search_util_unittest.cc
+++ b/chrome/browser/lacros/launcher_search/search_util_unittest.cc
@@ -8,7 +8,9 @@
 
 #include "base/json/json_reader.h"
 #include "base/values.h"
+#include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
+#include "components/omnibox/browser/autocomplete_provider.h"
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -17,6 +19,11 @@
 namespace crosapi {
 namespace {
 
+TEST(SearchUtilTest, ProviderTypes) {
+  const int types = ProviderTypes();
+  EXPECT_FALSE(types & AutocompleteProvider::TYPE_DOCUMENT);
+}
+
 // Tests result conversion for a default answer result.
 TEST(SearchUtilTest, CreateAnswerResult) {
   AutocompleteMatch match;
@@ -39,7 +46,7 @@
   ASSERT_TRUE(SuggestionAnswer::ParseAnswer(value->GetDict(), u"-1", &answer));
   match.answer = answer;
 
-  const auto result = CreateAnswerResult(match);
+  const auto result = CreateAnswerResult(match, nullptr, AutocompleteInput());
   EXPECT_EQ(result->type, mojom::SearchResultType::kOmniboxResult);
   EXPECT_EQ(result->relevance, 1248);
   ASSERT_TRUE(result->destination_url.has_value());
@@ -65,10 +72,16 @@
   match.destination_url = GURL("http://www.example.com/");
   match.type = AutocompleteMatchType::Type::SEARCH_SUGGEST_ENTITY;
   match.image_url = GURL("http://www.example.com/image.jpeg");
+
   match.contents = u"contents";
   match.description = u"description";
+  match.contents_class = {
+      ACMatchClassification(0, ACMatchClassification::Style::URL)};
+  match.description_class = {
+      ACMatchClassification(0, ACMatchClassification::Style::MATCH)};
 
-  const auto result = CreateResult(match);
+  const auto result =
+      CreateResult(match, nullptr, u"query", AutocompleteInput());
   EXPECT_EQ(result->type, mojom::SearchResultType::kOmniboxResult);
   EXPECT_EQ(result->relevance, 300);
   ASSERT_TRUE(result->destination_url.has_value());
@@ -80,10 +93,15 @@
   ASSERT_TRUE(result->image_url.has_value());
   EXPECT_EQ(result->image_url.value(),
             GURL("http://www.example.com/image.jpeg"));
+
   ASSERT_TRUE(result->contents.has_value());
   EXPECT_EQ(result->contents.value(), u"contents");
   ASSERT_TRUE(result->description.has_value());
   EXPECT_EQ(result->description.value(), u"description");
+
+  // The URL text class should be retained, but MATCH should be ignored.
+  EXPECT_EQ(result->contents_type, mojom::SearchResult::TextType::kUrl);
+  EXPECT_EQ(result->description_type, mojom::SearchResult::TextType::kUnset);
 }
 
 }  // namespace
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 06f57a2..686b458 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -84,6 +84,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
+#include "content/public/test/fenced_frame_test_util.h"
 #include "content/public/test/navigation_handle_observer.h"
 #include "content/public/test/prerender_test_util.h"
 #include "content/public/test/test_navigation_observer.h"
@@ -3354,6 +3355,40 @@
   }
 }
 
+class PageLoadMetricsBrowserTestWithFencedFrames
+    : public PageLoadMetricsBrowserTest {
+ public:
+  PageLoadMetricsBrowserTestWithFencedFrames()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
+    https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+    https_server_.AddDefaultHandlers(GetChromeTestDataDir());
+  }
+  ~PageLoadMetricsBrowserTestWithFencedFrames() override = default;
+
+ protected:
+  net::EmbeddedTestServer& https_server() { return https_server_; }
+
+ private:
+  net::EmbeddedTestServer https_server_;
+  content::test::FencedFrameTestHelper helper_;
+};
+
+// Checks if updating fencedframe's src attribute works. This is a regression
+// test to ensure PageLoadMetrics doesn't crash on such navigations.
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestWithFencedFrames,
+                       FencedFrameSrcAttributeNavigation) {
+  ASSERT_TRUE(https_server().Start());
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      https_server().GetURL("c.test", "/fenced_frames/basic_title.html")));
+
+  content::TestNavigationObserver observer(web_contents());
+  EXPECT_TRUE(content::ExecuteScript(
+      web_contents(),
+      "document.querySelector('fencedframe').src = './title2.html';"));
+  observer.WaitForNavigationFinished();
+}
+
 class PageLoadMetricsBrowserTestWithBackForwardCache
     : public PageLoadMetricsBrowserTest {
  public:
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index e5f3e53..be0f0ed3 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -138,6 +138,7 @@
 #include "components/security_interstitials/content/insecure_form_blocking_page.h"
 #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"
 #include "components/segmentation_platform/public/segmentation_platform_service.h"
+#include "components/services/screen_ai/public/cpp/pref_names.h"
 #include "components/sessions/core/session_id_generator.h"
 #include "components/signin/public/base/signin_buildflags.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -1199,6 +1200,10 @@
   registry->RegisterBooleanPref(
       policy::policy_prefs::kSetTimeoutWithout1MsClampEnabled, false);
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  screen_ai::RegisterLocalStatePrefs(registry);
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
   // This is intentionally last.
   RegisterLocalStatePrefsForMigration(registry);
 }
diff --git a/chrome/browser/privacy_budget/identifiability_study_state.cc b/chrome/browser/privacy_budget/identifiability_study_state.cc
index 9d01ed0..2ed188d 100644
--- a/chrome/browser/privacy_budget/identifiability_study_state.cc
+++ b/chrome/browser/privacy_budget/identifiability_study_state.cc
@@ -89,7 +89,7 @@
   if (!CanAddOneMoreActiveSurface())
     return false;
 
-  if (!blink::IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface))
+  if (!blink::IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface))
     return false;
 
   // (surface ∈ seen_surfaces_) but (surface ∉ active_surfaces_) means that
@@ -242,7 +242,7 @@
 namespace {
 // Predicate used in CheckInvariants().
 bool IsSurfaceAllowed(const blink::IdentifiableSurface& value) {
-  return blink::IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(value);
+  return blink::IdentifiabilityStudySettings::Get()->ShouldSampleSurface(value);
 }
 bool IsRepresentativeSurfaceAllowed(const RepresentativeSurface& value) {
   return IsSurfaceAllowed(value.value());
@@ -415,7 +415,7 @@
 
     unique_surfaces.insert(surface);
 
-    if (settings->IsSurfaceAllowed(surface)) {
+    if (settings->ShouldSampleSurface(surface)) {
       container[write_position++] = surface;
     } else {
       dropped_offsets.push_back(read_position);
@@ -568,7 +568,7 @@
 bool IdentifiabilityStudyState::ShouldReportEncounteredSurface(
     uint64_t source_id,
     blink::IdentifiableSurface surface) {
-  if (!blink::IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!blink::IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kMeasuredSurface)) {
     return false;
   }
diff --git a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
index 1255a70..0b71e8c79 100644
--- a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
@@ -508,19 +508,19 @@
   const auto* settings = blink::IdentifiabilityStudySettings::Get();
   EXPECT_TRUE(settings->IsActive());
   // Allowed by default.
-  EXPECT_TRUE(settings->IsTypeAllowed(
+  EXPECT_TRUE(settings->ShouldSampleType(
       blink::IdentifiableSurface::Type::kCanvasReadback));
 
   // Blocked surfaces. See fieldtrial_testing_config.json#IdentifiabilityStudy.
-  EXPECT_FALSE(settings->IsSurfaceAllowed(kBlockedSurface));
+  EXPECT_FALSE(settings->ShouldSampleSurface(kBlockedSurface));
 
   // Some random surface that shouldn't be blocked.
-  EXPECT_TRUE(settings->IsSurfaceAllowed(kAllowedInactiveSurface));
+  EXPECT_TRUE(settings->ShouldSampleSurface(kAllowedInactiveSurface));
 
   // Blocked types
-  EXPECT_FALSE(settings->IsTypeAllowed(
+  EXPECT_FALSE(settings->ShouldSampleType(
       blink::IdentifiableSurface::Type::kLocalFontLookupByFallbackCharacter));
-  EXPECT_FALSE(settings->IsTypeAllowed(
+  EXPECT_FALSE(settings->ShouldSampleType(
       blink::IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo));
 }
 
diff --git a/chrome/browser/privacy_budget/privacy_budget_ukm_entry_filter.cc b/chrome/browser/privacy_budget/privacy_budget_ukm_entry_filter.cc
index 4553fa0..cd69d39 100644
--- a/chrome/browser/privacy_budget/privacy_budget_ukm_entry_filter.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_ukm_entry_filter.cc
@@ -43,7 +43,8 @@
   base::EraseIf(entry->metrics, [&](auto metric) {
     const auto surface =
         blink::IdentifiableSurface::FromMetricHash(metric.first);
-    if (!blink::IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface))
+    if (!blink::IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
+            surface))
       return true;
 
     if (identifiability_study_state_->ShouldReportEncounteredSurface(
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_page.html b/chrome/browser/resources/settings/autofill_page/autofill_page.html
index c7087c7..1f643f46 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_page.html
+++ b/chrome/browser/resources/settings/autofill_page/autofill_page.html
@@ -57,6 +57,15 @@
           <settings-password-check prefs="{{prefs}}"></settings-password-check>
         </settings-subpage>
       </template>
+      <template is="dom-if" if="[[enablePasswordViewPage_]]">
+        <template is="dom-if" route-path="/passwords/view">
+          <settings-subpage page-title="[[credential.urls.shown]]"
+              favicon-site-url="[[credential.urls.link]]">
+            <password-view credential="{{credential}}">
+            </password-view>
+            </settings-subpage>
+        </template>
+      </template>
       <template is="dom-if" route-path="/payments">
         <settings-subpage
             associated-control="[[$$('#paymentManagerButton')]]"
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_page.ts b/chrome/browser/resources/settings/autofill_page/autofill_page.ts
index a38e7e0..68819a10 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_page.ts
+++ b/chrome/browser/resources/settings/autofill_page/autofill_page.ts
@@ -17,11 +17,13 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BaseMixin} from '../base_mixin.js';
+import {loadTimeData} from '../i18n_setup.js';
 import {PrefsMixin} from '../prefs/prefs_mixin.js';
 import {routes} from '../route.js';
 import {Router} from '../router.js';
 
 import {getTemplate} from './autofill_page.html.js';
+import {MultiStorePasswordUiEntry} from './multi_store_password_ui_entry.js';
 import {PasswordCheckMixin} from './password_check_mixin.js';
 import {PasswordManagerImpl} from './password_manager_proxy.js';
 
@@ -64,12 +66,28 @@
         type: String,
         computed: 'computePasswordManagerSubLabel_(compromisedPasswordsCount)',
       },
+
+      enablePasswordViewPage_: {
+        type: Boolean,
+        value() {
+          return loadTimeData.getBoolean('enablePasswordNotes');
+        }
+      },
+
+      // The credential is only used to pass the credential from password-view
+      // to settings-subpage
+      credential: {
+        type: Object,
+        value: null,
+      },
     };
   }
 
   private passwordFilter_: string;
   private focusConfig_: Map<string, string>;
   private passwordManagerSubLabel_: string;
+  private enablePasswordViewPage_: string;
+  credential: MultiStorePasswordUiEntry|null;
 
   /**
    * Shows the manage addresses sub page.
diff --git a/chrome/browser/resources/settings/autofill_page/password_view.html b/chrome/browser/resources/settings/autofill_page/password_view.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/browser/resources/settings/autofill_page/password_view.html
diff --git a/chrome/browser/resources/settings/autofill_page/password_view.ts b/chrome/browser/resources/settings/autofill_page/password_view.ts
new file mode 100644
index 0000000..1b4ca73
--- /dev/null
+++ b/chrome/browser/resources/settings/autofill_page/password_view.ts
@@ -0,0 +1,75 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview 'password-view' is the subpage containing details about the
+ * password such as the URL, the username, the password and the note.
+ */
+
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {routes} from '../route.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../router.js';
+import {MultiStorePasswordUiEntry} from './multi_store_password_ui_entry.js';
+import {getTemplate} from './password_view.html.js';
+
+const PasswordViewElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
+
+export class PasswordViewElement extends PasswordViewElementBase {
+  static get is() {
+    return 'password-view';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      credential: {
+        type: Object,
+        value: null,
+        notify: true,
+      },
+    };
+  }
+
+  credential: MultiStorePasswordUiEntry|null;
+
+  override currentRouteChanged(route: Route) {
+    if (route !== routes.PASSWORD_VIEW) {
+      return;
+    }
+    const queryParameters = Router.getInstance().getQueryParameters();
+
+    const site = queryParameters.get('site');
+    if (!site) {
+      return;
+    }
+
+    const username = queryParameters.get('username');
+    if (!username) {
+      return;
+    }
+
+    // TODO(https://crbug.com/1298027): Update the credential here based on site
+    // and username. The credential below is temporary.
+    this.credential = {
+      urls: {
+        shown: site,
+        link: site,
+      }
+    } as MultiStorePasswordUiEntry;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'password-view': PasswordViewElement;
+  }
+}
+
+customElements.define(PasswordViewElement.is, PasswordViewElement);
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 732fd16..9498144 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -372,6 +372,7 @@
     "settings_page/settings_animated_pages.js",
     "settings_page/settings_section.js",
     "settings_page/settings_subpage.js",
+    "site_favicon.js",
   ]
 
   in_files = [
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index c638b9a..cc65873 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -6,8 +6,9 @@
 import './appearance_page/appearance_fonts_page.js';
 import './autofill_page/autofill_section.js';
 import './autofill_page/password_check.js';
-import './autofill_page/passwords_section.js';
+import './autofill_page/password_view.js';
 import './autofill_page/passwords_device_section.js';
+import './autofill_page/passwords_section.js';
 import './autofill_page/payments_section.js';
 import './clear_browsing_data_dialog/clear_browsing_data_dialog.js';
 import './search_engines_page/search_engines_page.js';
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.html
index 8c9df36..dbeea77 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.html
@@ -1,5 +1,5 @@
 <style include="privacy-guide-fragment-shared"></style>
-<div class="header" focus-element tabindex="-1">
+<div class="header" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/clear_on_exit_graphic_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts
index c415777..dd670ca 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_clear_on_exit_fragment.ts
@@ -35,6 +35,10 @@
       },
     };
   }
+
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.header')!.focus();
+  }
 }
 
 customElements.define(
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
index 06f6fa2..77ec19868 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
@@ -21,7 +21,7 @@
     width: calc(100% - 48px);  /* 48px = 2x :host horizontal padding */
   }
 </style>
-<div class="headline-container" focus-element tabindex="-1">
+<div class="headline-container" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/completion_banner_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
index 5dfa571..932d76f 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
@@ -59,6 +59,10 @@
         (event: UpdateSyncStateEvent) => this.updateWaaLink_(event.signedIn));
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.headline-container')!.focus();
+  }
+
   /**
    * Updates the completion card waa link depending on the signin state.
    */
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html
index 47dff74..a1366e7 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html
@@ -1,5 +1,5 @@
 <style include="privacy-guide-fragment-shared"></style>
-<div class="header" focus-element tabindex="-1">
+<div class="header" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/cookies_graphic_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts
index f38ea417..224fe39 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts
@@ -63,6 +63,10 @@
     this.addEventListener('view-exit-finish', this.onViewExitFinish_);
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.header')!.focus();
+  }
+
   private onViewEnterStart_() {
     this.startStateBlock3PIncognito_ =
         this.getPref('generated.cookie_primary_setting').value ===
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.html
index de7a64e..ebc921e 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.html
@@ -1,5 +1,5 @@
 <style include="privacy-guide-fragment-shared"></style>
-<div class="header" focus-element tabindex="-1">
+<div class="header" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/history_sync_graphic_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
index afc990837..743de00 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
@@ -101,6 +101,10 @@
     this.addEventListener('view-exit-finish', this.onViewExitFinish_);
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.header')!.focus();
+  }
+
   private onViewExitFinish_() {
     const endStateHistorySyncOn = this.syncPrefs_.typedUrlsSynced;
     let state: PrivacyGuideSettingsStates|null = null;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.html
index d50ef34..87f49deb 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.html
@@ -1,5 +1,5 @@
 <style include="privacy-guide-fragment-shared"></style>
-<div class="header" focus-element tabindex="-1">
+<div class="header" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/msbb_graphic_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts
index 8da86df..b202eff 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_msbb_fragment.ts
@@ -53,6 +53,10 @@
     this.addEventListener('view-exit-finish', this.onViewExitFinish_);
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.header')!.focus();
+  }
+
   private onViewEnterStart_() {
     this.startStateMsbbOn_ =
         this.getPref('url_keyed_anonymized_data_collection.enabled').value;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
index 8b14fc7..e2e449cb 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
@@ -417,12 +417,9 @@
       }
 
       // On navigations within privacy guide, put the focus on the newly shown
-      // fragment. Every fragment has a [focus-element] element that is focused
-      // programmatically when the fragment is navigated to.
-      const elementToFocus =
-          assert(this.shadowRoot!.querySelector<HTMLElement>(
-                     '#' + this.privacyGuideStep_)!)
-              .shadowRoot!.querySelector<HTMLElement>('[focus-element]');
+      // fragment.
+      const elementToFocus = assert(this.shadowRoot!.querySelector<HTMLElement>(
+          '#' + this.privacyGuideStep_)!);
       afterNextRender(this, () => elementToFocus!.focus());
     }
   }
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html
index 27933c75..9dec2b2 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html
@@ -1,5 +1,5 @@
 <style include="privacy-guide-fragment-shared"></style>
-<div class="header" focus-element tabindex="-1">
+<div class="header" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/safe_browsing_graphic_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts
index 372fe66eb..c04efdb 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts
@@ -63,6 +63,10 @@
     this.addEventListener('view-exit-finish', this.onViewExitFinish_);
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.header')!.focus();
+  }
+
   private onViewEnterStart_() {
     this.startStateEnhanced_ = this.getPref('generated.safe_browsing').value ===
         SafeBrowsingSetting.ENHANCED;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
index dc2381b..81c55d27 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
@@ -21,7 +21,7 @@
     width: calc(100% - 48px);  /* 48px = 2x :host horizontal padding */
   }
 </style>
-<div class="headline-container" focus-element tabindex="-1">
+<div class="headline-container" tabindex="-1">
   <picture>
     <source
         srcset="./images/privacy_guide/welcome_banner_dark.svg"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
index 7d7fc805..fcfaaa7 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
@@ -28,6 +28,10 @@
     return getTemplate();
   }
 
+  override focus() {
+    this.shadowRoot!.querySelector<HTMLElement>('.headline-container')!.focus();
+  }
+
   private onStartButtonClick_(e: Event) {
     e.stopPropagation();
     this.dispatchEvent(
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.ts b/chrome/browser/resources/settings/privacy_page/security_page.ts
index 78b50b6c..b703a092 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/security_page.ts
@@ -28,6 +28,7 @@
 // </if>
 
 import {PrefsMixin, PrefsMixinInterface} from '../prefs/prefs_mixin.js';
+import {CrSettingsPrefs} from '../prefs/prefs_types.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../router.js';
 
@@ -197,14 +198,16 @@
   override ready() {
     super.ready();
 
-    // Expand initial pref value manually because automatic
-    // expanding is disabled.
-    const prefValue = this.getPref('generated.safe_browsing').value;
-    if (prefValue === SafeBrowsingSetting.ENHANCED) {
-      this.$.safeBrowsingEnhanced.expanded = true;
-    } else if (prefValue === SafeBrowsingSetting.STANDARD) {
-      this.$.safeBrowsingStandard.expanded = true;
-    }
+    CrSettingsPrefs.initialized.then(() => {
+      // Expand initial pref value manually because automatic
+      // expanding is disabled.
+      const prefValue = this.getPref('generated.safe_browsing').value;
+      if (prefValue === SafeBrowsingSetting.ENHANCED) {
+        this.$.safeBrowsingEnhanced.expanded = true;
+      } else if (prefValue === SafeBrowsingSetting.STANDARD) {
+        this.$.safeBrowsingStandard.expanded = true;
+      }
+    });
   }
 
   /**
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index a2da3e27..ae4e4c8d 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -139,6 +139,9 @@
   if (visibility.autofill !== false) {
     r.AUTOFILL = r.BASIC.createSection('/autofill', 'autofill');
     r.PASSWORDS = r.AUTOFILL.createChild('/passwords');
+    if (loadTimeData.getBoolean('enablePasswordNotes')) {
+      r.PASSWORD_VIEW = r.PASSWORDS.createChild('view');
+    }
     r.CHECK_PASSWORDS = r.PASSWORDS.createChild('check');
 
     r.DEVICE_PASSWORDS = r.PASSWORDS.createChild('device');
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni
index d588ae11..71dab73 100644
--- a/chrome/browser/resources/settings/settings.gni
+++ b/chrome/browser/resources/settings/settings.gni
@@ -40,6 +40,7 @@
   "autofill_page/password_move_to_account_dialog.ts",
   "autofill_page/password_remove_confirmation_dialog.ts",
   "autofill_page/password_remove_dialog.ts",
+  "autofill_page/password_view.ts",
   "autofill_page/passwords_device_section.ts",
   "autofill_page/passwords_export_dialog.ts",
   "autofill_page/passwords_list_handler.ts",
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index a2b1e381..22f36ee 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -35,9 +35,13 @@
 
       #title-icon {
         height: 36px;
+        width: 36px;
+      }
+
+      #title-icon,
+      #favicon {
         margin-inline-end: 12px;
         margin-inline-start: 2px;
-        width: 36px;
       }
 
       #closeButton {
@@ -70,6 +74,10 @@
       <template is="dom-if" if="[[titleIcon]]">
         <img id="title-icon" src="[[titleIcon]]" aria-hidden="true">
       </template>
+      <template is="dom-if" if="[[faviconSiteUrl]]">
+        <site-favicon id="favicon" url="[[faviconSiteUrl]]" aria-hidden="true">
+        </site-favicon>
+      </template>
       <h1 class="cr-title-text">[[pageTitle]]</h1>
       <slot name="subpage-title-extra"></slot>
       <template is="dom-if" if="[[learnMoreUrl]]">
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.ts b/chrome/browser/resources/settings/settings_page/settings_subpage.ts
index 56a379cc..bfc2b9c 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.ts
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.ts
@@ -14,6 +14,7 @@
 import '//resources/cr_elements/shared_style_css.m.js';
 import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
 import '../settings_shared_css.js';
+import '../site_favicon.js';
 
 import {CrSearchFieldElement} from '//resources/cr_elements/cr_search_field/cr_search_field.js';
 import {FindShortcutMixin, FindShortcutMixinInterface} from '//resources/cr_elements/find_shortcut_mixin.js';
@@ -54,8 +55,12 @@
     return {
       pageTitle: String,
 
+      /** Setting this will display the icon at the given URL. */
       titleIcon: String,
 
+      /** Setting this will display the favicon of the website. */
+      faviconSiteUrl: String,
+
       learnMoreUrl: String,
 
       /** Setting a |searchLabel| will enable search. */
@@ -118,6 +123,7 @@
 
   pageTitle: string;
   titleIcon: string;
+  faviconSiteUrl: string;
   learnMoreUrl: string;
   searchLabel: string;
   searchTerm: string;
diff --git a/chrome/browser/resources/settings/settings_routes.ts b/chrome/browser/resources/settings/settings_routes.ts
index 2ba49e1..9ba653f 100644
--- a/chrome/browser/resources/settings/settings_routes.ts
+++ b/chrome/browser/resources/settings/settings_routes.ts
@@ -32,6 +32,7 @@
   MANAGE_PROFILE: Route,
   ON_STARTUP: Route,
   PASSWORDS: Route,
+  PASSWORD_VIEW: Route,
   DEVICE_PASSWORDS: Route,
   PAYMENTS: Route,
   PEOPLE: Route,
diff --git a/chrome/browser/resources/support_tool/spinner_page.html b/chrome/browser/resources/support_tool/spinner_page.html
index 491c456..26970a90 100644
--- a/chrome/browser/resources/support_tool/spinner_page.html
+++ b/chrome/browser/resources/support_tool/spinner_page.html
@@ -2,9 +2,17 @@
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file. -->
 
-<style include="support-tool-shared"></style>
+<style include="support-tool-shared">
+  paper-spinner-lite {
+    display: flex;
+    margin: 0 auto;
+    margin-top: 30px;
+  }
+</style>
 
 <h2>Collecting diagnostic data</h2>
+<paper-spinner-lite active>
+</paper-spinner-lite>
 <div class="navigation-buttons">
   <cr-button id="cancelButton" on-click="onCancelClick_">Cancel</cr-button>
 </div>
diff --git a/chrome/browser/resources/support_tool/spinner_page.ts b/chrome/browser/resources/support_tool/spinner_page.ts
index 1ef4197..c7b363ef 100644
--- a/chrome/browser/resources/support_tool/spinner_page.ts
+++ b/chrome/browser/resources/support_tool/spinner_page.ts
@@ -4,6 +4,7 @@
 
 import './support_tool_shared_css.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
 
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {BrowserProxy, BrowserProxyImpl} from './browser_proxy.js';
diff --git a/chrome/browser/touch_to_fill/android/OWNERS b/chrome/browser/touch_to_fill/android/OWNERS
index e6e4ee91..39d587a 100644
--- a/chrome/browser/touch_to_fill/android/OWNERS
+++ b/chrome/browser/touch_to_fill/android/OWNERS
@@ -1,3 +1,2 @@
-jdoerrie@chromium.org
 fhorschig@chromium.org
 bsazonov@chromium.org
diff --git a/chrome/browser/ui/intent_picker_tab_helper.cc b/chrome/browser/ui/intent_picker_tab_helper.cc
index 70fb7296..d23a90a 100644
--- a/chrome/browser/ui/intent_picker_tab_helper.cc
+++ b/chrome/browser/ui/intent_picker_tab_helper.cc
@@ -11,7 +11,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h"
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_prefs.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_features.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_helpers.h"
 #include "chrome/browser/profiles/profile.h"
@@ -190,10 +190,11 @@
     last_shown_origin_ = origin;
     Profile* profile =
         Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-    auto chip_state = IntentPickerAutoDisplayService::Get(profile)
-                          ->GetChipStateAndIncrementCounter(url);
+    auto chip_state =
+        IntentPickerAutoDisplayPrefs ::GetChipStateAndIncrementCounter(profile,
+                                                                       url);
     should_show_collapsed_chip_ =
-        chip_state == IntentPickerAutoDisplayService::ChipState::kCollapsed;
+        chip_state == IntentPickerAutoDisplayPrefs::ChipState::kCollapsed;
   }
 }
 
diff --git a/chrome/browser/ui/passwords/settings/OWNERS b/chrome/browser/ui/passwords/settings/OWNERS
deleted file mode 100644
index 1071f77..0000000
--- a/chrome/browser/ui/passwords/settings/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-jdoerrie@chromium.org
diff --git a/chrome/browser/ui/webui/chromeos/login/active_directory_login_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/active_directory_login_screen_handler.cc
index 54b48811..7964ebe0 100644
--- a/chrome/browser/ui/webui/chromeos/login/active_directory_login_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/active_directory_login_screen_handler.cc
@@ -22,7 +22,8 @@
 
 ActiveDirectoryLoginScreenHandler::ActiveDirectoryLoginScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.ActiveDirectoryLoginScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.ActiveDirectoryLoginScreen.userActed");
 }
 
 ActiveDirectoryLoginScreenHandler::~ActiveDirectoryLoginScreenHandler() {
@@ -75,12 +76,12 @@
 void ActiveDirectoryLoginScreenHandler::Bind(
     ActiveDirectoryLoginScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ActiveDirectoryLoginScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void ActiveDirectoryLoginScreenHandler::Reset() {
diff --git a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
index fc30bb2..b5bdf17f 100644
--- a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
@@ -23,7 +23,7 @@
 ActiveDirectoryPasswordChangeScreenHandler::
     ActiveDirectoryPasswordChangeScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path(
+  set_user_acted_method_path_deprecated(
       "login.ActiveDirectoryPasswordChangeScreen.userActed");
 }
 
@@ -55,12 +55,12 @@
 void ActiveDirectoryPasswordChangeScreenHandler::Bind(
     ActiveDirectoryPasswordChangeScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ActiveDirectoryPasswordChangeScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void ActiveDirectoryPasswordChangeScreenHandler::ShowSignInError(
diff --git a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
index a75d05f..6d41c2a 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
@@ -33,7 +33,7 @@
 
 AppDownloadingScreenHandler::AppDownloadingScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.AppDownloadingScreen.userActed");
+  set_user_acted_method_path_deprecated("login.AppDownloadingScreen.userActed");
 }
 
 AppDownloadingScreenHandler::~AppDownloadingScreenHandler() {
@@ -58,7 +58,7 @@
 
 void AppDownloadingScreenHandler::Bind(AppDownloadingScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void AppDownloadingScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index 8834351..ac0f91f 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -52,7 +52,8 @@
     : BaseScreenHandler(kScreenId),
       is_child_account_(
           user_manager::UserManager::Get()->IsLoggedInAsChildUser()) {
-  set_user_acted_method_path("login.ArcTermsOfServiceScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.ArcTermsOfServiceScreen.userActed");
 }
 
 ArcTermsOfServiceScreenHandler::~ArcTermsOfServiceScreenHandler() {
@@ -295,7 +296,7 @@
 }
 
 void ArcTermsOfServiceScreenHandler::Bind(ArcTermsOfServiceScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void ArcTermsOfServiceScreenHandler::StartNetworkAndTimeZoneObserving() {
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
index a1cf157..3378d8b 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -63,7 +63,8 @@
 
 AssistantOptInFlowScreenHandler::AssistantOptInFlowScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.AssistantOptInFlowScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.AssistantOptInFlowScreen.userActed");
 }
 
 AssistantOptInFlowScreenHandler::~AssistantOptInFlowScreenHandler() {
@@ -203,7 +204,7 @@
 }
 
 void AssistantOptInFlowScreenHandler::Bind(AssistantOptInFlowScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
   if (page_is_ready())
     Initialize();
@@ -211,7 +212,7 @@
 
 void AssistantOptInFlowScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void AssistantOptInFlowScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
index 6d629c1..7cfaa12 100644
--- a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
@@ -4,8 +4,12 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
+#include "base/check_op.h"
+#include "base/strings/strcat.h"
 #include "chrome/browser/ash/login/oobe_screen.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
+#include "chrome/browser/ash/login/ui/login_display_host.h"
+#include "chrome/browser/ash/login/wizard_controller.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_webui_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 
@@ -14,14 +18,22 @@
 BaseScreenHandler::BaseScreenHandler(OobeScreenId oobe_screen)
     : oobe_screen_(oobe_screen) {
   DCHECK_NE(oobe_screen_.name, OobeScreen::SCREEN_UNKNOWN.name);
+  if (!oobe_screen_.external_api_prefix.empty()) {
+    user_acted_method_path_ = base::StrCat(
+        {"login.", oobe_screen_.external_api_prefix, ".userActed"});
+  }
 }
 
 BaseScreenHandler::~BaseScreenHandler() = default;
 
-void BaseScreenHandler::SetBaseScreen(BaseScreen* base_screen) {
-  if (base_screen_ == base_screen)
-    return;
+void BaseScreenHandler::SetBaseScreenDeprecated(BaseScreen* base_screen) {
+#if DCHECK_IS_ON()
   base_screen_ = base_screen;
+  if (!base_screen) {
+    // TODO(rsorokin): Insert check if LDH is finalizing here.
+    return;
+  }
+#endif
 }
 
 void BaseScreenHandler::ShowInWebUI(absl::optional<base::Value::Dict> data) {
@@ -40,8 +52,22 @@
 }
 
 void BaseScreenHandler::HandleUserAction(const std::string& action_id) {
-  if (base_screen_)
-    base_screen_->HandleUserAction(action_id);
+  if (!ash::LoginDisplayHost::default_host())
+    return;
+
+#if DCHECK_IS_ON()
+  if (base_screen_) {
+    DCHECK_EQ(
+        ash::LoginDisplayHost::default_host()->GetWizardController()->GetScreen(
+            oobe_screen_),
+        base_screen_);
+  }
+#endif
+
+  ash::LoginDisplayHost::default_host()
+      ->GetWizardController()
+      ->GetScreen(oobe_screen_)
+      ->HandleUserAction(action_id);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
index 5dc69b54..2710c86 100644
--- a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
@@ -27,7 +27,8 @@
 
   OobeScreenId oobe_screen() const { return oobe_screen_; }
 
-  void SetBaseScreen(BaseScreen* base_screen);
+  // DEPRECATED: To be removed.
+  void SetBaseScreenDeprecated(BaseScreen* base_screen);
 
   // BaseWebUIHandler:
   void RegisterMessages() override;
@@ -44,7 +45,9 @@
   //
   // If this is not called then userActed-style callbacks will not be available
   // for the screen.
-  void set_user_acted_method_path(const std::string& user_acted_method_path) {
+  // DEPRECATED: Use 'StaticOobeScreenId::external_api_prefix' instead.
+  void set_user_acted_method_path_deprecated(
+      const std::string& user_acted_method_path) {
     user_acted_method_path_ = user_acted_method_path;
   }
 
@@ -58,7 +61,9 @@
   // OobeScreen that this handler corresponds to.
   const OobeScreenId oobe_screen_;
 
+#if DCHECK_IS_ON()
   BaseScreen* base_screen_ = nullptr;
+#endif
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
index c19fa7e3..4803054 100644
--- a/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/consolidated_consent_screen_handler.cc
@@ -22,7 +22,8 @@
 
 ConsolidatedConsentScreenHandler::ConsolidatedConsentScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.ConsolidatedConsentScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.ConsolidatedConsentScreen.userActed");
 }
 
 ConsolidatedConsentScreenHandler::~ConsolidatedConsentScreenHandler() {
@@ -165,12 +166,12 @@
 
 void ConsolidatedConsentScreenHandler::Bind(ConsolidatedConsentScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ConsolidatedConsentScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void ConsolidatedConsentScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.cc
index d2bc981..10ca380b 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.cc
@@ -17,7 +17,8 @@
 
 DemoPreferencesScreenHandler::DemoPreferencesScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.DemoPreferencesScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.DemoPreferencesScreen.userActed");
 }
 
 DemoPreferencesScreenHandler::~DemoPreferencesScreenHandler() {
@@ -33,7 +34,7 @@
 
 void DemoPreferencesScreenHandler::Bind(DemoPreferencesScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void DemoPreferencesScreenHandler::SetInputMethodId(
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc
index 3f319f0..b7a34014 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.cc
@@ -21,7 +21,7 @@
 
 DemoSetupScreenHandler::DemoSetupScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.DemoSetupScreen.userActed");
+  set_user_acted_method_path_deprecated("login.DemoSetupScreen.userActed");
 }
 
 DemoSetupScreenHandler::~DemoSetupScreenHandler() {
@@ -37,7 +37,7 @@
 
 void DemoSetupScreenHandler::Bind(DemoSetupScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void DemoSetupScreenHandler::OnSetupFailed(
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.cc
index 77bc3f7..5936f92 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.cc
@@ -16,17 +16,11 @@
 
 namespace chromeos {
 
-constexpr StaticOobeScreenId EnableAdbSideloadingScreenView::kScreenId;
-
 EnableAdbSideloadingScreenHandler::EnableAdbSideloadingScreenHandler()
-    : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.EnableAdbSideloadingScreen.userActed");
-}
+    : BaseScreenHandler(kScreenId) {}
 
-EnableAdbSideloadingScreenHandler::~EnableAdbSideloadingScreenHandler() {
-  if (screen_)
-    screen_->OnViewDestroyed(this);
-}
+EnableAdbSideloadingScreenHandler::~EnableAdbSideloadingScreenHandler() =
+    default;
 
 void EnableAdbSideloadingScreenHandler::Show() {
   if (!page_is_ready()) {
@@ -40,13 +34,11 @@
 
 void EnableAdbSideloadingScreenHandler::Bind(
     EnableAdbSideloadingScreen* screen) {
-  screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void EnableAdbSideloadingScreenHandler::Unbind() {
-  screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void EnableAdbSideloadingScreenHandler::SetScreenState(UIState value) {
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
index 0f857a2c..6d56b83e 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_adb_sideloading_screen_handler.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_ADB_SIDELOADING_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ENABLE_ADB_SIDELOADING_SCREEN_HANDLER_H_
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 
 namespace ash {
@@ -14,9 +15,11 @@
 namespace chromeos {
 
 // Interface between enable adb sideloading screen and its representation.
-class EnableAdbSideloadingScreenView {
+class EnableAdbSideloadingScreenView
+    : public base::SupportsWeakPtr<EnableAdbSideloadingScreenView> {
  public:
-  constexpr static StaticOobeScreenId kScreenId{"adb-sideloading"};
+  inline constexpr static StaticOobeScreenId kScreenId{
+      "adb-sideloading", "EnableAdbSideloadingScreen"};
 
   // The constants need to be synced with oobe_adb_sideloading_screen.js.
   enum class UIState {
@@ -24,7 +27,7 @@
     UI_STATE_SETUP = 2,
   };
 
-  virtual ~EnableAdbSideloadingScreenView() {}
+  virtual ~EnableAdbSideloadingScreenView() = default;
 
   virtual void Show() = 0;
   virtual void Hide() = 0;
@@ -61,8 +64,6 @@
   void Initialize() override;
 
  private:
-  ash::EnableAdbSideloadingScreen* screen_ = nullptr;
-
   // Keeps whether screen should be shown right after initialization.
   bool show_on_init_ = false;
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
index 7ab8448..5385921 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
@@ -23,7 +23,8 @@
 
 EnableDebuggingScreenHandler::EnableDebuggingScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.EnableDebuggingScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.EnableDebuggingScreen.userActed");
 }
 
 EnableDebuggingScreenHandler::~EnableDebuggingScreenHandler() {
@@ -45,7 +46,7 @@
 
 void EnableDebuggingScreenHandler::SetDelegate(EnableDebuggingScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
   if (page_is_ready())
     Initialize();
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
index 83c277c..d059b58 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.cc
@@ -17,7 +17,8 @@
 
 EncryptionMigrationScreenHandler::EncryptionMigrationScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.EncryptionMigrationScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.EncryptionMigrationScreen.userActed");
 }
 
 EncryptionMigrationScreenHandler::~EncryptionMigrationScreenHandler() {
@@ -40,7 +41,7 @@
 void EncryptionMigrationScreenHandler::SetDelegate(
     EncryptionMigrationScreen* delegate) {
   delegate_ = delegate;
-  BaseScreenHandler::SetBaseScreen(delegate);
+  BaseScreenHandler::SetBaseScreenDeprecated(delegate);
   if (page_is_ready())
     Initialize();
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 6bba99a..d79eed7c2 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -196,7 +196,8 @@
   DCHECK(network_state_informer_.get());
   DCHECK(error_screen_);
   network_state_informer_->AddObserver(this);
-  set_user_acted_method_path("login.OAuthEnrollmentScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.OAuthEnrollmentScreen.userActed");
 }
 
 EnrollmentScreenHandler::~EnrollmentScreenHandler() {
@@ -253,12 +254,12 @@
 
 void EnrollmentScreenHandler::Bind(ash::EnrollmentScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void EnrollmentScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void EnrollmentScreenHandler::ShowSigninScreen() {
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index b54966d..6793487 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -18,7 +18,7 @@
 constexpr StaticOobeScreenId ErrorScreenView::kScreenId;
 
 ErrorScreenHandler::ErrorScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.ErrorMessageScreen.userActed");
+  set_user_acted_method_path_deprecated("login.ErrorMessageScreen.userActed");
 }
 
 ErrorScreenHandler::~ErrorScreenHandler() {
@@ -46,12 +46,12 @@
 
 void ErrorScreenHandler::Bind(ErrorScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ErrorScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void ErrorScreenHandler::ShowOobeScreen(OobeScreenId screen) {
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
index 46fa4f33..32b8980 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
@@ -31,7 +31,7 @@
 constexpr StaticOobeScreenId EulaView::kScreenId;
 
 EulaScreenHandler::EulaScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.EulaScreen.userActed");
+  set_user_acted_method_path_deprecated("login.EulaScreen.userActed");
 }
 
 EulaScreenHandler::~EulaScreenHandler() {
@@ -52,14 +52,14 @@
 
 void EulaScreenHandler::Bind(EulaScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
   if (page_is_ready())
     Initialize();
 }
 
 void EulaScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 std::string EulaScreenHandler::GetEulaOnlineUrl() {
diff --git a/chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.cc
index 69062d0e..fbe4939 100644
--- a/chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.cc
@@ -16,7 +16,8 @@
 
 FamilyLinkNoticeScreenHandler::FamilyLinkNoticeScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.FamilyLinkNoticeScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.FamilyLinkNoticeScreen.userActed");
 }
 
 FamilyLinkNoticeScreenHandler::~FamilyLinkNoticeScreenHandler() {
@@ -48,12 +49,12 @@
 
 void FamilyLinkNoticeScreenHandler::Bind(FamilyLinkNoticeScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void FamilyLinkNoticeScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void FamilyLinkNoticeScreenHandler::SetIsNewGaiaAccount(bool value) {
diff --git a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
index 178ce80..1937488 100644
--- a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.cc
@@ -18,7 +18,8 @@
 
 FingerprintSetupScreenHandler::FingerprintSetupScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.FingerprintSetupScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.FingerprintSetupScreen.userActed");
 }
 
 FingerprintSetupScreenHandler::~FingerprintSetupScreenHandler() = default;
@@ -132,7 +133,7 @@
 
 void FingerprintSetupScreenHandler::Bind(FingerprintSetupScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void FingerprintSetupScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_password_changed_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_password_changed_screen_handler.cc
index 6c164719..aee0a079 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_password_changed_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_password_changed_screen_handler.cc
@@ -19,7 +19,8 @@
 
 GaiaPasswordChangedScreenHandler::GaiaPasswordChangedScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.GaiaPasswordChangedScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.GaiaPasswordChangedScreen.userActed");
 }
 
 GaiaPasswordChangedScreenHandler::~GaiaPasswordChangedScreenHandler() {
@@ -59,12 +60,12 @@
 
 void GaiaPasswordChangedScreenHandler::Bind(GaiaPasswordChangedScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void GaiaPasswordChangedScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void GaiaPasswordChangedScreenHandler::HandleMigrateUserData(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 2e2bb6c..5e74efa 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -326,7 +326,7 @@
       network_state_informer_(network_state_informer),
       core_oobe_view_(core_oobe_view) {
   DCHECK(network_state_informer_.get());
-  set_user_acted_method_path("login.GaiaSigninScreen.userActed");
+  set_user_acted_method_path_deprecated("login.GaiaSigninScreen.userActed");
 }
 
 GaiaScreenHandler::~GaiaScreenHandler() {
@@ -1171,11 +1171,11 @@
 }
 
 void GaiaScreenHandler::Bind(GaiaScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void GaiaScreenHandler::Unbind() {
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void GaiaScreenHandler::SetGaiaPath(GaiaScreenHandler::GaiaPath gaia_path) {
diff --git a/chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.cc
index 47ae442..3e1b4cdf 100644
--- a/chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.cc
@@ -14,7 +14,8 @@
 
 GestureNavigationScreenHandler::GestureNavigationScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.GestureNavigationScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.GestureNavigationScreen.userActed");
 }
 
 GestureNavigationScreenHandler::~GestureNavigationScreenHandler() = default;
@@ -30,7 +31,7 @@
 
 void GestureNavigationScreenHandler::Bind(GestureNavigationScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void GestureNavigationScreenHandler::Hide() {}
diff --git a/chrome/browser/ui/webui/chromeos/login/guest_tos_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/guest_tos_screen_handler.cc
index ad49756b7..33aaaf8f 100644
--- a/chrome/browser/ui/webui/chromeos/login/guest_tos_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/guest_tos_screen_handler.cc
@@ -14,7 +14,7 @@
 constexpr StaticOobeScreenId GuestTosScreenView::kScreenId;
 
 GuestTosScreenHandler::GuestTosScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.GuestTosScreen.userActed");
+  set_user_acted_method_path_deprecated("login.GuestTosScreen.userActed");
 }
 
 GuestTosScreenHandler::~GuestTosScreenHandler() {
@@ -63,12 +63,12 @@
 
 void GuestTosScreenHandler::Bind(GuestTosScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void GuestTosScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void GuestTosScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/login/hardware_data_collection_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/hardware_data_collection_screen_handler.cc
index ac8a0ecd..b3ffef8a 100644
--- a/chrome/browser/ui/webui/chromeos/login/hardware_data_collection_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/hardware_data_collection_screen_handler.cc
@@ -18,7 +18,8 @@
 
 HWDataCollectionScreenHandler::HWDataCollectionScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.HWDataCollectionScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.HWDataCollectionScreen.userActed");
 }
 
 HWDataCollectionScreenHandler::~HWDataCollectionScreenHandler() {
@@ -40,12 +41,12 @@
 
 void HWDataCollectionScreenHandler::Bind(ash::HWDataCollectionScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void HWDataCollectionScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void HWDataCollectionScreenHandler::ShowHWDataUsageLearnMore() {
diff --git a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
index f402b0d..7f9704f 100644
--- a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
@@ -23,7 +23,7 @@
 
 HIDDetectionScreenHandler::HIDDetectionScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.HIDDetectionScreen.userActed");
+  set_user_acted_method_path_deprecated("login.HIDDetectionScreen.userActed");
 }
 
 HIDDetectionScreenHandler::~HIDDetectionScreenHandler() {
@@ -45,14 +45,14 @@
 
 void HIDDetectionScreenHandler::Bind(HIDDetectionScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
   if (page_is_ready())
     Initialize();
 }
 
 void HIDDetectionScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void HIDDetectionScreenHandler::SetKeyboardState(const std::string& value) {
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
index 84641fd..e1b10d4 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
@@ -21,7 +21,7 @@
 
 KioskEnableScreenHandler::KioskEnableScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.KioskEnableScreen.userActed");
+  set_user_acted_method_path_deprecated("login.KioskEnableScreen.userActed");
 }
 
 KioskEnableScreenHandler::~KioskEnableScreenHandler() {
@@ -38,7 +38,7 @@
 }
 
 void KioskEnableScreenHandler::SetScreen(KioskEnableScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
   if (page_is_ready() && screen_)
     Initialize();
diff --git a/chrome/browser/ui/webui/chromeos/login/lacros_data_migration_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/lacros_data_migration_screen_handler.cc
index 583c23d..b5b1c0a 100644
--- a/chrome/browser/ui/webui/chromeos/login/lacros_data_migration_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/lacros_data_migration_screen_handler.cc
@@ -16,7 +16,8 @@
 
 LacrosDataMigrationScreenHandler::LacrosDataMigrationScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.LacrosDataMigrationScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.LacrosDataMigrationScreen.userActed");
 }
 
 LacrosDataMigrationScreenHandler::~LacrosDataMigrationScreenHandler() {
@@ -49,12 +50,12 @@
 }
 
 void LacrosDataMigrationScreenHandler::Bind(LacrosDataMigrationScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
 }
 
 void LacrosDataMigrationScreenHandler::Unbind() {
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
   screen_ = nullptr;
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.cc
index 5a440e95..af089917 100644
--- a/chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/locale_switch_screen_handler.cc
@@ -25,12 +25,12 @@
 }
 
 void LocaleSwitchScreenHandler::Bind(LocaleSwitchScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
 }
 
 void LocaleSwitchScreenHandler::Unbind() {
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
   screen_ = nullptr;
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/management_transition_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/management_transition_screen_handler.cc
index 02d2ada3..b8fd425 100644
--- a/chrome/browser/ui/webui/chromeos/login/management_transition_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/management_transition_screen_handler.cc
@@ -72,7 +72,7 @@
 
 void ManagementTransitionScreenHandler::Bind(
     ManagementTransitionScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
   if (page_is_ready())
     Initialize();
@@ -80,7 +80,7 @@
 
 void ManagementTransitionScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
   timer_.Stop();
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
index 57d871a..fbbc579d 100644
--- a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.cc
@@ -72,7 +72,7 @@
 
 void MarketingOptInScreenHandler::Bind(MarketingOptInScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void MarketingOptInScreenHandler::Show(bool opt_in_visible,
diff --git a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.cc
index 2ea1207..2c605f7 100644
--- a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.cc
@@ -16,7 +16,8 @@
 
 MultiDeviceSetupScreenHandler::MultiDeviceSetupScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.MultiDeviceSetupScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.MultiDeviceSetupScreen.userActed");
 }
 
 MultiDeviceSetupScreenHandler::~MultiDeviceSetupScreenHandler() = default;
@@ -27,7 +28,7 @@
 }
 
 void MultiDeviceSetupScreenHandler::Bind(MultiDeviceSetupScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void MultiDeviceSetupScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
index 87434d0..cceb929 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -22,7 +22,7 @@
 constexpr StaticOobeScreenId NetworkScreenView::kScreenId;
 
 NetworkScreenHandler::NetworkScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.NetworkScreen.userActed");
+  set_user_acted_method_path_deprecated("login.NetworkScreen.userActed");
 }
 
 NetworkScreenHandler::~NetworkScreenHandler() {
@@ -59,12 +59,12 @@
 
 void NetworkScreenHandler::Bind(NetworkScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void NetworkScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void NetworkScreenHandler::ShowError(const std::u16string& message) {
diff --git a/chrome/browser/ui/webui/chromeos/login/offline_login_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/offline_login_screen_handler.cc
index 1e53df7..348009e 100644
--- a/chrome/browser/ui/webui/chromeos/login/offline_login_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/offline_login_screen_handler.cc
@@ -17,7 +17,7 @@
 
 OfflineLoginScreenHandler::OfflineLoginScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.OfflineLoginScreen.userActed");
+  set_user_acted_method_path_deprecated("login.OfflineLoginScreen.userActed");
 }
 
 OfflineLoginScreenHandler::~OfflineLoginScreenHandler() {
@@ -72,12 +72,12 @@
 
 void OfflineLoginScreenHandler::Bind(OfflineLoginScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void OfflineLoginScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void OfflineLoginScreenHandler::Reset() {
diff --git a/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc
index 9dee85a..bd971066 100644
--- a/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/os_install_screen_handler.cc
@@ -30,7 +30,7 @@
 
 OsInstallScreenHandler::OsInstallScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.OsInstallScreen.userActed");
+  set_user_acted_method_path_deprecated("login.OsInstallScreen.userActed");
 }
 
 OsInstallScreenHandler::~OsInstallScreenHandler() {
@@ -102,12 +102,12 @@
 
 void OsInstallScreenHandler::Bind(ash::OsInstallScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void OsInstallScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void OsInstallScreenHandler::ShowStep(const char* step) {
diff --git a/chrome/browser/ui/webui/chromeos/login/os_trial_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/os_trial_screen_handler.cc
index 8c5b483..444f923 100644
--- a/chrome/browser/ui/webui/chromeos/login/os_trial_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/os_trial_screen_handler.cc
@@ -16,7 +16,7 @@
 constexpr StaticOobeScreenId OsTrialScreenView::kScreenId;
 
 OsTrialScreenHandler::OsTrialScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.OsTrialScreen.userActed");
+  set_user_acted_method_path_deprecated("login.OsTrialScreen.userActed");
 }
 
 OsTrialScreenHandler::~OsTrialScreenHandler() {
@@ -48,12 +48,12 @@
 
 void OsTrialScreenHandler::Bind(ash::OsTrialScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void OsTrialScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.cc
index a70dd22..913ac2d 100644
--- a/chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/packaged_license_screen_handler.cc
@@ -14,7 +14,8 @@
 
 PackagedLicenseScreenHandler::PackagedLicenseScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.PackagedLicenseScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.PackagedLicenseScreen.userActed");
 }
 
 PackagedLicenseScreenHandler::~PackagedLicenseScreenHandler() {}
@@ -31,12 +32,12 @@
 
 void PackagedLicenseScreenHandler::Bind(PackagedLicenseScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void PackagedLicenseScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void PackagedLicenseScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc
index fdbedfcee..ed01d84c 100644
--- a/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/parental_handoff_screen_handler.cc
@@ -23,7 +23,8 @@
 
 ParentalHandoffScreenHandler::ParentalHandoffScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.ParentalHandoffScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.ParentalHandoffScreen.userActed");
 }
 
 ParentalHandoffScreenHandler::~ParentalHandoffScreenHandler() {
@@ -52,12 +53,12 @@
 
 void ParentalHandoffScreenHandler::Bind(ParentalHandoffScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ParentalHandoffScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.cc
index 1d9d3b6..6b58d3b 100644
--- a/chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/pin_setup_screen_handler.cc
@@ -16,7 +16,7 @@
 constexpr StaticOobeScreenId PinSetupScreenView::kScreenId;
 
 PinSetupScreenHandler::PinSetupScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.PinSetupScreen.userActed");
+  set_user_acted_method_path_deprecated("login.PinSetupScreen.userActed");
 }
 
 PinSetupScreenHandler::~PinSetupScreenHandler() {}
@@ -81,7 +81,7 @@
 
 void PinSetupScreenHandler::Bind(PinSetupScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void PinSetupScreenHandler::Hide() {}
diff --git a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc
index 706479c0f..bdcea069 100644
--- a/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/quick_start_screen_handler.cc
@@ -13,7 +13,7 @@
 
 QuickStartScreenHandler::QuickStartScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.QuickStartScreen.userActed");
+  set_user_acted_method_path_deprecated("login.QuickStartScreen.userActed");
 }
 
 QuickStartScreenHandler::~QuickStartScreenHandler() {
@@ -32,14 +32,14 @@
 
 void QuickStartScreenHandler::Bind(QuickStartScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
   if (page_is_ready())
     Initialize();
 }
 
 void QuickStartScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 std::vector<base::Value> ToValue(const ash::quick_start::ShapeList& list) {
diff --git a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
index cf91ef9a..17c2ece 100644
--- a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
@@ -102,7 +102,7 @@
 
 void RecommendAppsScreenHandler::Bind(RecommendAppsScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void RecommendAppsScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
index 787cc37..b984f06 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
@@ -23,7 +23,7 @@
 constexpr StaticOobeScreenId ResetView::kScreenId;
 
 ResetScreenHandler::ResetScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.ResetScreen.userActed");
+  set_user_acted_method_path_deprecated("login.ResetScreen.userActed");
 }
 
 ResetScreenHandler::~ResetScreenHandler() {
@@ -33,12 +33,12 @@
 
 void ResetScreenHandler::Bind(ResetScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void ResetScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void ResetScreenHandler::Show() {
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.cc
index f40bc8a..fa7e2ad 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_fatal_error_screen_handler.cc
@@ -20,7 +20,8 @@
 
 SignInFatalErrorScreenHandler::SignInFatalErrorScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.SignInFatalErrorScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.SignInFatalErrorScreen.userActed");
 }
 
 SignInFatalErrorScreenHandler::~SignInFatalErrorScreenHandler() {
@@ -58,12 +59,12 @@
 
 void SignInFatalErrorScreenHandler::Bind(SignInFatalErrorScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void SignInFatalErrorScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/smart_privacy_protection_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/smart_privacy_protection_screen_handler.cc
index 6e41000..bc73650 100644
--- a/chrome/browser/ui/webui/chromeos/login/smart_privacy_protection_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/smart_privacy_protection_screen_handler.cc
@@ -16,7 +16,8 @@
 
 SmartPrivacyProtectionScreenHandler::SmartPrivacyProtectionScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.SmartPrivacyProtectionScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.SmartPrivacyProtectionScreen.userActed");
 }
 
 SmartPrivacyProtectionScreenHandler::~SmartPrivacyProtectionScreenHandler() {
@@ -39,12 +40,12 @@
 void SmartPrivacyProtectionScreenHandler::Bind(
     ash::SmartPrivacyProtectionScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void SmartPrivacyProtectionScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void SmartPrivacyProtectionScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
index d2d6708..8728ad0 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
@@ -55,7 +55,7 @@
 // TODO(https://crbug.com/1229582): Remove SplitSettings from names in this file
 SyncConsentScreenHandler::SyncConsentScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.SyncConsentScreen.userActed");
+  set_user_acted_method_path_deprecated("login.SyncConsentScreen.userActed");
 }
 
 SyncConsentScreenHandler::~SyncConsentScreenHandler() = default;
@@ -170,7 +170,7 @@
 
 void SyncConsentScreenHandler::Bind(SyncConsentScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
 }
 
 void SyncConsentScreenHandler::Show(bool is_arc_restricted) {
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
index 32a2a12..deb3630 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
@@ -34,7 +34,7 @@
 
 TermsOfServiceScreenHandler::TermsOfServiceScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.TermsOfServiceScreen.userActed");
+  set_user_acted_method_path_deprecated("login.TermsOfServiceScreen.userActed");
 }
 
 TermsOfServiceScreenHandler::~TermsOfServiceScreenHandler() {
@@ -60,7 +60,7 @@
 }
 
 void TermsOfServiceScreenHandler::SetScreen(TermsOfServiceScreen* screen) {
-  BaseScreenHandler::SetBaseScreen(screen);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen);
   screen_ = screen;
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/tpm_error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/tpm_error_screen_handler.cc
index b51af2e9..19d3e07f 100644
--- a/chrome/browser/ui/webui/chromeos/login/tpm_error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/tpm_error_screen_handler.cc
@@ -21,7 +21,8 @@
 constexpr StaticOobeScreenId TpmErrorView::kScreenId;
 
 TpmErrorScreenHandler::TpmErrorScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.TPMErrorMessageScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.TPMErrorMessageScreen.userActed");
 }
 
 TpmErrorScreenHandler::~TpmErrorScreenHandler() {
@@ -73,12 +74,12 @@
 
 void TpmErrorScreenHandler::Bind(TpmErrorScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void TpmErrorScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
index c081316..bd73b4fa 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
@@ -22,7 +22,7 @@
 
 UpdateRequiredScreenHandler::UpdateRequiredScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.UpdateRequiredScreen.userActed");
+  set_user_acted_method_path_deprecated("login.UpdateRequiredScreen.userActed");
 }
 
 UpdateRequiredScreenHandler::~UpdateRequiredScreenHandler() {
@@ -111,12 +111,12 @@
 
 void UpdateRequiredScreenHandler::Bind(UpdateRequiredScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void UpdateRequiredScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void UpdateRequiredScreenHandler::SetIsConnected(bool connected) {
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
index 70c990b..d22fc8b 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -43,7 +43,7 @@
 }  // namespace
 
 UpdateScreenHandler::UpdateScreenHandler() : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.UpdateScreen.userActed");
+  set_user_acted_method_path_deprecated("login.UpdateScreen.userActed");
 }
 
 UpdateScreenHandler::~UpdateScreenHandler() {
@@ -63,12 +63,12 @@
 
 void UpdateScreenHandler::Bind(UpdateScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void UpdateScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void UpdateScreenHandler::SetUpdateState(UpdateView::UIState value) {
diff --git a/chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.cc
index ae6bfe5..45e1206 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.cc
@@ -19,7 +19,7 @@
 
 UserCreationScreenHandler::UserCreationScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.UserCreationScreen.userActed");
+  set_user_acted_method_path_deprecated("login.UserCreationScreen.userActed");
 }
 
 UserCreationScreenHandler::~UserCreationScreenHandler() {
@@ -71,12 +71,12 @@
 
 void UserCreationScreenHandler::Bind(UserCreationScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void UserCreationScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void UserCreationScreenHandler::SetIsBackButtonVisible(bool value) {
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
index 268b5aa..8eb3862 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
@@ -56,7 +56,7 @@
 
 WelcomeScreenHandler::WelcomeScreenHandler(CoreOobeView* core_oobe_view)
     : BaseScreenHandler(kScreenId), core_oobe_view_(core_oobe_view) {
-  set_user_acted_method_path("login.WelcomeScreen.userActed");
+  set_user_acted_method_path_deprecated("login.WelcomeScreen.userActed");
   DCHECK(core_oobe_view_);
 
   AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
@@ -98,12 +98,12 @@
 
 void WelcomeScreenHandler::Bind(WelcomeScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void WelcomeScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void WelcomeScreenHandler::ReloadLocalizedContent() {
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
index 7f0a864d..0912cd09 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
@@ -15,7 +15,8 @@
 
 WrongHWIDScreenHandler::WrongHWIDScreenHandler()
     : BaseScreenHandler(kScreenId) {
-  set_user_acted_method_path("login.WrongHWIDMessageScreen.userActed");
+  set_user_acted_method_path_deprecated(
+      "login.WrongHWIDMessageScreen.userActed");
 }
 
 WrongHWIDScreenHandler::~WrongHWIDScreenHandler() {
@@ -36,12 +37,12 @@
 
 void WrongHWIDScreenHandler::Bind(WrongHWIDScreen* screen) {
   screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+  BaseScreenHandler::SetBaseScreenDeprecated(screen_);
 }
 
 void WrongHWIDScreenHandler::Unbind() {
   screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+  BaseScreenHandler::SetBaseScreenDeprecated(nullptr);
 }
 
 void WrongHWIDScreenHandler::DeclareLocalizedValues(
diff --git a/chrome/browser/web_applications/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/web_app_data_retriever_unittest.cc
index ce2158d..66b21af6 100644
--- a/chrome/browser/web_applications/web_app_data_retriever_unittest.cc
+++ b/chrome/browser/web_applications/web_app_data_retriever_unittest.cc
@@ -59,7 +59,7 @@
 
   // Set |web_app_info| to respond on |GetWebAppInstallInfo|.
   void SetWebAppInstallInfo(const WebAppInstallInfo& web_app_info) {
-    web_app_info_ = web_app_info;
+    web_app_info_ = WebAppInstallInfo(web_app_info);
   }
 
   void GetWebPageMetadata(GetWebPageMetadataCallback callback) override {
diff --git a/chrome/browser/web_applications/web_app_install_info.cc b/chrome/browser/web_applications/web_app_install_info.cc
index 46520fd..f3fb17f 100644
--- a/chrome/browser/web_applications/web_app_install_info.cc
+++ b/chrome/browser/web_applications/web_app_install_info.cc
@@ -217,6 +217,10 @@
 
 WebAppInstallInfo::WebAppInstallInfo(const WebAppInstallInfo& other) = default;
 
+WebAppInstallInfo::WebAppInstallInfo(WebAppInstallInfo&&) = default;
+
+WebAppInstallInfo& WebAppInstallInfo::operator=(WebAppInstallInfo&&) = default;
+
 WebAppInstallInfo::WebAppInstallInfo(
     const webapps::mojom::WebPageMetadata& metadata)
     : title(metadata.application_name),
@@ -244,6 +248,10 @@
 
 WebAppInstallInfo::~WebAppInstallInfo() = default;
 
+WebAppInstallInfo WebAppInstallInfo::Clone() const {
+  return WebAppInstallInfo(*this);
+}
+
 bool operator==(const IconSizes& icon_sizes1, const IconSizes& icon_sizes2) {
   return std::tie(icon_sizes1.any, icon_sizes1.maskable,
                   icon_sizes1.monochrome) == std::tie(icon_sizes2.any,
diff --git a/chrome/browser/web_applications/web_app_install_info.h b/chrome/browser/web_applications/web_app_install_info.h
index 7eca50fa..9ce8528d 100644
--- a/chrome/browser/web_applications/web_app_install_info.h
+++ b/chrome/browser/web_applications/web_app_install_info.h
@@ -174,10 +174,22 @@
   };
 
   WebAppInstallInfo();
+
+  // TODO(b/227755254): Delete copy constructors and migrate to move assignment.
   WebAppInstallInfo(const WebAppInstallInfo& other);
+
+  // Deleted to prevent accidental copying. Use Clone() to deep copy explicitly.
+  WebAppInstallInfo& operator=(const WebAppInstallInfo&) = delete;
+
+  WebAppInstallInfo(WebAppInstallInfo&&);
+  WebAppInstallInfo& operator=(WebAppInstallInfo&&);
+
   explicit WebAppInstallInfo(const webapps::mojom::WebPageMetadata& metadata);
   ~WebAppInstallInfo();
 
+  // Creates a deep copy of this struct.
+  WebAppInstallInfo Clone() const;
+
   // Id specified in the manifest.
   absl::optional<std::string> manifest_id;
 
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 2c13022a..c9daa8c 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/web_applications/web_app_url_loader.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/chrome_features.h"
+#include "components/webapps/browser/install_result_code.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
@@ -481,7 +482,12 @@
 
   if (only_retrieve_web_application_info_) {
     DCHECK(retrieve_info_callback_);
-    std::move(retrieve_info_callback_).Run(std::move(web_application_info_));
+    if (web_application_info_) {
+      std::move(retrieve_info_callback_).Run(std::move(*web_application_info_));
+      web_application_info_ = absl::nullopt;
+    } else {
+      std::move(retrieve_info_callback_).Run(code);
+    }
     return;
   }
 
@@ -909,7 +915,10 @@
   }
 
   if (only_retrieve_web_application_info_) {
-    web_application_info_ = std::move(web_app_info);
+    if (web_app_info) {
+      web_application_info_ = std::move(*web_app_info);
+      web_app_info.reset();
+    }
     CallInstallCallback(AppId(),
                         webapps::InstallResultCode::kSuccessNewInstall);
     return;
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h
index 16ea198..fd1a3f4 100644
--- a/chrome/browser/web_applications/web_app_install_task.h
+++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -52,8 +52,10 @@
 // WebAppInstallTask is an implementation detail of WebAppInstallManager.
 class WebAppInstallTask : content::WebContentsObserver {
  public:
+  using WebAppInstallInfoOrErrorCode =
+      absl::variant<WebAppInstallInfo, webapps::InstallResultCode>;
   using RetrieveWebAppInstallInfoWithIconsCallback =
-      base::OnceCallback<void(std::unique_ptr<WebAppInstallInfo>)>;
+      base::OnceCallback<void(WebAppInstallInfoOrErrorCode)>;
 
   using WebAppInstallFlow = WebAppInstallManager::WebAppInstallFlow;
 
@@ -320,7 +322,7 @@
   webapps::WebappInstallSource install_source_ = kNoInstallSource;
 
   std::unique_ptr<WebAppDataRetriever> data_retriever_;
-  std::unique_ptr<WebAppInstallInfo> web_application_info_;
+  absl::optional<WebAppInstallInfo> web_application_info_;
   std::unique_ptr<content::WebContents> web_contents_;
 
   raw_ptr<WebAppInstallManager> install_manager_;
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 9949e46..ce29490c 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -297,15 +297,15 @@
     return result;
   }
 
-  std::unique_ptr<WebAppInstallInfo> LoadAndRetrieveWebAppInstallInfoWithIcons(
-      const GURL& url) {
-    std::unique_ptr<WebAppInstallInfo> result;
+  WebAppInstallTask::WebAppInstallInfoOrErrorCode
+  LoadAndRetrieveWebAppInstallInfoWithIcons(const GURL& url) {
+    WebAppInstallTask::WebAppInstallInfoOrErrorCode result;
     base::RunLoop run_loop;
     install_task_->LoadAndRetrieveWebAppInstallInfoWithIcons(
         url, &url_loader(),
         base::BindLambdaForTesting(
-            [&](std::unique_ptr<WebAppInstallInfo> web_app_info) {
-              result = std::move(web_app_info);
+            [&](WebAppInstallTask::WebAppInstallInfoOrErrorCode info_or_error) {
+              result = std::move(info_or_error);
               run_loop.Quit();
             }));
     run_loop.Run();
@@ -1325,9 +1325,11 @@
     url_loader().SetNextLoadUrlResult(
         url, WebAppUrlLoader::Result::kRedirectedUrlLoaded);
 
-    std::unique_ptr<WebAppInstallInfo> result =
+    WebAppInstallTask::WebAppInstallInfoOrErrorCode result =
         LoadAndRetrieveWebAppInstallInfoWithIcons(url);
-    EXPECT_FALSE(result);
+    ASSERT_TRUE(absl::holds_alternative<webapps::InstallResultCode>(result));
+    EXPECT_EQ(absl::get<webapps::InstallResultCode>(result),
+              webapps::InstallResultCode::kInstallURLRedirected);
   }
   ResetInstallTask();
   {
@@ -1335,9 +1337,11 @@
     url_loader().SetNextLoadUrlResult(
         url, WebAppUrlLoader::Result::kFailedPageTookTooLong);
 
-    std::unique_ptr<WebAppInstallInfo> result =
+    WebAppInstallTask::WebAppInstallInfoOrErrorCode result =
         LoadAndRetrieveWebAppInstallInfoWithIcons(url);
-    EXPECT_FALSE(result);
+    ASSERT_TRUE(absl::holds_alternative<webapps::InstallResultCode>(result));
+    EXPECT_EQ(absl::get<webapps::InstallResultCode>(result),
+              webapps::InstallResultCode::kInstallURLLoadTimeOut);
   }
   ResetInstallTask();
   {
@@ -1345,12 +1349,13 @@
     CreateRendererAppInfo(url, name, description);
     url_loader().SetNextLoadUrlResult(url, WebAppUrlLoader::Result::kUrlLoaded);
 
-    std::unique_ptr<WebAppInstallInfo> result =
+    WebAppInstallTask::WebAppInstallInfoOrErrorCode result =
         LoadAndRetrieveWebAppInstallInfoWithIcons(url);
-    EXPECT_TRUE(result);
-    EXPECT_EQ(result->start_url, start_url);
-    EXPECT_TRUE(result->manifest_icons.empty());
-    EXPECT_FALSE(result->icon_bitmaps.any.empty());
+    ASSERT_TRUE(absl::holds_alternative<WebAppInstallInfo>(result));
+    const auto& info = absl::get<WebAppInstallInfo>(result);
+    EXPECT_EQ(info.start_url, start_url);
+    EXPECT_TRUE(info.manifest_icons.empty());
+    EXPECT_FALSE(info.icon_bitmaps.any.empty());
   }
   ResetInstallTask();
   {
@@ -1364,12 +1369,10 @@
         profile(), &install_manager(), install_finalizer_.get(),
         std::move(data_retriever), &registrar());
 
-    std::unique_ptr<WebAppInstallInfo> info;
     task->LoadAndRetrieveWebAppInstallInfoWithIcons(
         url, &url_loader(),
         base::BindLambdaForTesting(
-            [&](std::unique_ptr<WebAppInstallInfo> app_info) {
-              info = std::move(app_info);
+            [&](WebAppInstallTask::WebAppInstallInfoOrErrorCode info_or_error) {
               run_loop.Quit();
             }));
     task.reset();
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 432c517..24aee52 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1648998144-eb2a9520d68471dcbd0fb7ac41d3477513f4ffe3.profdata
+chrome-linux-main-1649073454-c72d87b8bef6a7660f7eff5a855708aaacb573da.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 50a00e97..ad57d84 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1648998144-5fc2e83170c5ba943784576e696bd8fd878c06dc.profdata
+chrome-mac-arm-main-1649073454-ccd9e5582ad7ba69df033384b38e114bd4e69d97.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 0aae658..15c14cb 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1648998144-0cbc92fbff4e13aa632c2d034e446dc9ae7c07df.profdata
+chrome-mac-main-1649073454-e5bb226b88583e8fc6bf486c6b8470b842752de9.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index f38c7fba..f14ba2a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1649037892-4267dccb6975dbf05236b585a1142feefb84379d.profdata
+chrome-win32-main-1649073454-ce721983cbeade42cc7b939d1b8c1cee60afa0ab.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index c2c88e1..c3ff7f1 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1649037892-0ff63f7405e999cff5db9ba73b26ce4f77532cf7.profdata
+chrome-win64-main-1649073454-e996e02972d839612a037c7139d8e135757a24f8.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d578de3..d3e548dc 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6823,7 +6823,7 @@
       "../browser/apps/app_service/app_service_test.h",
       "../browser/apps/app_service/launch_utils_unittest.cc",
       "../browser/apps/app_service/publishers/publisher_unittest.cc",
-      "../browser/apps/intent_helper/intent_picker_auto_display_service_unittest.cc",
+      "../browser/apps/intent_helper/intent_picker_auto_display_prefs_unittest.cc",
       "../browser/apps/intent_helper/intent_picker_internal_unittest.cc",
       "../browser/apps/intent_helper/page_transition_util_unittest.cc",
       "../browser/devtools/devtools_file_system_indexer_unittest.cc",
diff --git a/chrome/test/data/devtools/extensions/can_inspect_url/devtools.js b/chrome/test/data/devtools/extensions/can_inspect_url/devtools.js
index 3cc81eb..9e516deea 100644
--- a/chrome/test/data/devtools/extensions/can_inspect_url/devtools.js
+++ b/chrome/test/data/devtools/extensions/can_inspect_url/devtools.js
@@ -19,7 +19,12 @@
         });
   });
   const inspectedTabId = chrome.devtools.inspectedWindow.tabId;
-  chrome.tabs.update(inspectedTabId, {url: newPageURL});
+  chrome.debugger.attach(
+      {tabId: inspectedTabId}, '1.3',
+      () => chrome.debugger.sendCommand(
+          {tabId: inspectedTabId}, 'Page.navigate', {url: newPageURL}));
+
+  // chrome.tabs.update(inspectedTabId, {url: newPageURL});
   await new Promise(
       resolve => chrome.tabs.onUpdated.addListener((tabId, changedProps) => {
         if (inspectedTabId !== tabId || changedProps.url !== newPageURL)
diff --git a/chrome/test/data/devtools/extensions/can_inspect_url/manifest.json b/chrome/test/data/devtools/extensions/can_inspect_url/manifest.json
index a19d595..14409d6 100644
--- a/chrome/test/data/devtools/extensions/can_inspect_url/manifest.json
+++ b/chrome/test/data/devtools/extensions/can_inspect_url/manifest.json
@@ -4,5 +4,5 @@
    "version": "0.1",
    "manifest_version": 2,
    "devtools_page": "devtools.html",
-   "permissions": ["tabs"]
+   "permissions": ["tabs", "debugger"]
 }
diff --git a/chrome/test/data/fenced_frames/basic_title.html b/chrome/test/data/fenced_frames/basic_title.html
new file mode 100644
index 0000000..9769f98b
--- /dev/null
+++ b/chrome/test/data/fenced_frames/basic_title.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <fencedframe src="title1.html"></fencedframe>
+</body>
+</html>
diff --git a/chrome/test/data/fenced_frames/basic_title.html.mock-http-headers b/chrome/test/data/fenced_frames/basic_title.html.mock-http-headers
new file mode 100644
index 0000000..263e89c4
--- /dev/null
+++ b/chrome/test/data/fenced_frames/basic_title.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/autofill_page_test.ts b/chrome/test/data/webui/settings/autofill_page_test.ts
index e30af1c7..6fa41ada 100644
--- a/chrome/test/data/webui/settings/autofill_page_test.ts
+++ b/chrome/test/data/webui/settings/autofill_page_test.ts
@@ -3,14 +3,18 @@
 // found in the LICENSE file.
 
 // clang-format off
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {DomIf, flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {AutofillManagerImpl, PasswordsSectionElement, PaymentsManagerImpl, SettingsAutofillSectionElement, SettingsPaymentsSectionElement} from 'chrome://settings/lazy_load.js';
+import {buildRouter, Router, routes} from 'chrome://settings/settings.js';
 import {CrSettingsPrefs, MultiStoreExceptionEntry, MultiStorePasswordUiEntry, OpenWindowProxyImpl, PasswordManagerImpl, SettingsAutofillPageElement, SettingsPluralStringProxyImpl, SettingsPrefsElement} from 'chrome://settings/settings.js';
-import {assertDeepEquals, assertEquals, assertNotEquals} from 'chrome://webui-test/chai_assert.js';
+import {SettingsRoutes} from 'chrome://settings/settings_routes.js';
+import {assertDeepEquals, assertEquals, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {FakeSettingsPrivate} from './fake_settings_private.js';
-import {AutofillManagerExpectations, createAddressEntry, createCreditCardEntry, createExceptionEntry, createPasswordEntry, PaymentsManagerExpectations, TestAutofillManager, TestPaymentsManager} from './passwords_and_autofill_fake_data.js';
+import {AutofillManagerExpectations, createAddressEntry, createCreditCardEntry, createExceptionEntry, createMultiStorePasswordEntry, createPasswordEntry, PaymentsManagerExpectations, TestAutofillManager, TestPaymentsManager} from './passwords_and_autofill_fake_data.js';
 import {makeCompromisedCredential} from './passwords_and_autofill_fake_data.js';
 import {TestOpenWindowProxy} from './test_open_window_proxy.js';
 import {PasswordManagerExpectations,TestPasswordManagerProxy} from './test_password_manager_proxy.js';
@@ -357,4 +361,24 @@
             .querySelector<HTMLElement>(
                 '#passwordManagerSubLabel')!.innerText.trim());
   });
+
+  test('Credential urls is used in the subpage header', async function() {
+    const SHOWN_URL = 'www.google.com';
+    loadTimeData.overrideValues({enablePasswordNotes: true});
+    Router.resetInstanceForTesting(buildRouter());
+    routes.PASSWORD_VIEW =
+        (Router.getInstance().getRoutes() as SettingsRoutes).PASSWORD_VIEW;
+    const autofillSection = createAutofillPageSection();
+    autofillSection.credential =
+        createMultiStorePasswordEntry({url: SHOWN_URL, deviceId: 1});
+
+    Router.getInstance().navigateTo(routes.PASSWORD_VIEW);
+    await flushTasks();
+    const subpage =
+        autofillSection.shadowRoot!.querySelector('settings-subpage');
+
+    assertTrue(!!subpage);
+    assertEquals(`http://${SHOWN_URL}/login`, subpage.faviconSiteUrl);
+    assertEquals(SHOWN_URL, subpage.pageTitle);
+  });
 });
diff --git a/chrome/test/data/webui/settings/settings_subpage_test.ts b/chrome/test/data/webui/settings/settings_subpage_test.ts
index da5f88111..c2f7d71d 100644
--- a/chrome/test/data/webui/settings/settings_subpage_test.ts
+++ b/chrome/test/data/webui/settings/settings_subpage_test.ts
@@ -82,6 +82,23 @@
     assertEquals('ltr', icon!.getAttribute('dir'));
   });
 
+  test('favicon', function() {
+    const subpage = document.createElement('settings-subpage');
+    document.body.appendChild(subpage);
+    flush();
+
+    // No favicon is shown when the URL is not given.
+    assertFalse(!!subpage.shadowRoot!.querySelector('site-favicon'));
+
+    subpage.faviconSiteUrl = 'https://www.chromium.org';
+    flush();
+
+    // Favicon is shown when the URL is specified.
+    const favicon = subpage.shadowRoot!.querySelector('site-favicon');
+    assertTrue(!!favicon);
+    assertEquals(subpage.faviconSiteUrl, favicon.url);
+  });
+
   test('clear search (event)', function() {
     const subpage = document.createElement('settings-subpage');
     // Having a searchLabel will create the cr-search-field.
diff --git a/chromeos/crosapi/mojom/launcher_search.mojom b/chromeos/crosapi/mojom/launcher_search.mojom
index 31dafdc..42d65ea 100644
--- a/chromeos/crosapi/mojom/launcher_search.mojom
+++ b/chromeos/crosapi/mojom/launcher_search.mojom
@@ -36,7 +36,7 @@
 };
 
 // Struct represents search result.
-// Next min ID: 15
+// Next min ID: 19
 [Stable]
 struct SearchResult {
   // Type of the result. Used to distinguish between different types of result.
@@ -45,6 +45,12 @@
   double relevance@1;
   // Destination URL of the result. Used for opening the result.
   url.mojom.Url? destination_url@2;
+  // Stripped destination URL of the result. This is computed from
+  // |destination_url| by performing processing such as stripping off "www.",
+  // converting https protocol to http, and stripping excess query parameters.
+  // The stripped URL is used for unique identification and not as an actual
+  // URL.
+  [MinVersion=2] url.mojom.Url? stripped_destination_url@14;
 
   // The following fields represent additional information about search
   // results. These are optional and will be filled depending on the result.
@@ -62,6 +68,9 @@
   // This defaults to kUnset.
   AnswerType answer_type@6;
 
+  // The page transition type of this result. Used for opening a result.
+  [MinVersion=2] PageTransition page_transition@15;
+
   // The image url of the result, if any. Used to download the result image.
   url.mojom.Url? image_url@7;
   // Favicon of the result.
@@ -69,13 +78,19 @@
 
   // The contents of the result. Used to display the result.
   mojo_base.mojom.String16? contents@9;
+  // Text type of the contents, if any.
+  [MinVersion=2] TextType contents_type@16;
   // Additional contents for the result. Used to display the result.
   mojo_base.mojom.String16? additional_contents@10;
+  // Text type of the additional contents, if any.
+  [MinVersion=2] TextType additional_contents_type@17;
   // Description of the result. Used to display the result.
   mojo_base.mojom.String16? description@11;
+  // Text type of the description, if any.
+  [MinVersion=2] TextType description_type@18;
   // Additional description for the result. Used to display the result.
   mojo_base.mojom.String16? additional_description@12;
-  // Text type of the additional description, if any. Defaults to kUnset.
+  // Text type of the additional description, if any.
   TextType additional_description_type@13;
 
   [Stable, Extensible]
@@ -119,6 +134,15 @@
     [Default] kUnset = 0,
     kPositive = 1,
     kNegative = 2,
+    [MinVersion=2] kUrl = 3,
+  };
+
+  // Enum representing the page transition types.
+  [Stable, Extensible]
+  enum PageTransition {
+    [Default] kUnset = 0,
+    kTyped = 1,
+    kGenerated = 2,
   };
 };
 
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 2f4ac48..d7b2894 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -172,6 +172,14 @@
   # https://crbug.com/1310619
   "policy.AutoOpenAllowedForURLs.lacros",
 
+  # Flaky on chromeos-eve-chrome. b/226284050.
+  "crostini.UninstallInvalidApp.bullseye_stable",
+  "crostini.Xattrs.bullseye_stable",
+  "crostini.SSHFSMount.bullseye_stable",
+  "crostini.GPUEnabled.gpu_bullseye_stable",
+  "crostini.Basic.bullseye_stable",
+  "crostini.CrashReporter.bullseye_stable",
+
   # https://crbug.com/1307671
   "policy.SafeBrowsingProtectionLevel",
 
@@ -226,6 +234,9 @@
   # https://crbug.com/1312121
   "policy.DefaultJavaScriptSetting",
   "policy.CookiesBlockedForUrls",
+
+  # https://crbug.com/1312965
+  "policy.AllowDinosaurEasterEggEnrolled",
 ]
 
 # To disable a specific test in lacros_all_tast_tests, add it the following
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index d30c5f6b..5184b3be 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -15,10 +15,13 @@
 
 namespace autofill {
 
-AutofillField::AutofillField() = default;
+AutofillField::AutofillField() {
+  local_type_predictions_.fill(NO_SERVER_DATA);
+}
 
-AutofillField::AutofillField(FieldSignature field_signature)
-    : field_signature_(field_signature) {}
+AutofillField::AutofillField(FieldSignature field_signature) : AutofillField() {
+  field_signature_ = field_signature;
+}
 
 AutofillField::AutofillField(const FormFieldData& field)
     : FormFieldData(field),
@@ -26,6 +29,7 @@
       parseable_label_(field.label) {
   field_signature_ =
       CalculateFieldSignatureByNameAndType(name, form_control_type);
+  local_type_predictions_.fill(NO_SERVER_DATA);
 }
 
 AutofillField::~AutofillField() = default;
@@ -37,6 +41,13 @@
   return field;
 }
 
+ServerFieldType AutofillField::heuristic_type() const {
+  ServerFieldType type = get_prediction(PredictionSource::kDefaultHeuristics);
+  // `NO_SERVER_DATA` would mean that there is no heuristic type. Client code
+  // presumes there is a prediction, therefore we coalesce to `UNKNOWN_TYPE`.
+  return type > 0 ? type : UNKNOWN_TYPE;
+}
+
 ServerFieldType AutofillField::server_type() const {
   return server_predictions_.empty()
              ? NO_SERVER_DATA
@@ -52,12 +63,12 @@
 void AutofillField::set_heuristic_type(ServerFieldType type) {
   if (type >= 0 && type < MAX_VALID_FIELD_TYPE &&
       type != FIELD_WITH_DEFAULT_VALUE) {
-    heuristic_type_ = type;
+    set_prediction(PredictionSource::kDefaultHeuristics, type);
   } else {
     NOTREACHED();
     // This case should not be reachable; but since this has potential
     // implications on data uploaded to the server, better safe than sorry.
-    heuristic_type_ = UNKNOWN_TYPE;
+    set_prediction(PredictionSource::kDefaultHeuristics, UNKNOWN_TYPE);
   }
   overall_type_ = AutofillType(NO_SERVER_DATA);
 }
@@ -129,9 +140,9 @@
         server_type() == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) {
       return AutofillType(server_type());
     }
-    if (heuristic_type_ == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
-        heuristic_type_ == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) {
-      return AutofillType(heuristic_type_);
+    if (heuristic_type() == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
+        heuristic_type() == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) {
+      return AutofillType(heuristic_type());
     }
   }
 
@@ -159,20 +170,20 @@
     // it might be better to fix this server-side.
     // See http://crbug.com/429236 for background.
     bool believe_server = !(server_type() == NAME_FULL &&
-                            heuristic_type_ == CREDIT_CARD_NAME_FULL) &&
+                            heuristic_type() == CREDIT_CARD_NAME_FULL) &&
                           !(server_type() == CREDIT_CARD_NAME_FULL &&
-                            heuristic_type_ == NAME_FULL) &&
+                            heuristic_type() == NAME_FULL) &&
                           !(server_type() == NAME_FIRST &&
-                            heuristic_type_ == CREDIT_CARD_NAME_FIRST) &&
+                            heuristic_type() == CREDIT_CARD_NAME_FIRST) &&
                           !(server_type() == NAME_LAST &&
-                            heuristic_type_ == CREDIT_CARD_NAME_LAST);
+                            heuristic_type() == CREDIT_CARD_NAME_LAST);
 
     // Either way, retain a preference for the the CVC heuristic over the
     // server's password predictions (http://crbug.com/469007)
     believe_server =
         believe_server && !(AutofillType(server_type()).group() ==
                                 FieldTypeGroup::kPasswordField &&
-                            heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
+                            heuristic_type() == CREDIT_CARD_VERIFICATION_CODE);
 
     // For new name tokens the heuristic predictions get precedence over the
     // server predictions.
@@ -181,8 +192,8 @@
         believe_server &&
         !(base::FeatureList::IsEnabled(
               features::kAutofillEnableSupportForMoreStructureInNames) &&
-          (heuristic_type_ == NAME_LAST_SECOND ||
-           heuristic_type_ == NAME_LAST_FIRST));
+          (heuristic_type() == NAME_LAST_SECOND ||
+           heuristic_type() == NAME_LAST_FIRST));
 
     // For new address tokens the heuristic predictions get precedence over the
     // server predictions.
@@ -191,17 +202,17 @@
         believe_server &&
         !(base::FeatureList::IsEnabled(
               features::kAutofillEnableSupportForMoreStructureInAddresses) &&
-          (heuristic_type_ == ADDRESS_HOME_STREET_NAME ||
-           heuristic_type_ == ADDRESS_HOME_HOUSE_NUMBER));
+          (heuristic_type() == ADDRESS_HOME_STREET_NAME ||
+           heuristic_type() == ADDRESS_HOME_HOUSE_NUMBER));
 
     believe_server =
-        believe_server && !(heuristic_type_ == MERCHANT_PROMO_CODE);
+        believe_server && !(heuristic_type() == MERCHANT_PROMO_CODE);
 
     if (believe_server)
       return AutofillType(server_type());
   }
 
-  return AutofillType(heuristic_type_);
+  return AutofillType(heuristic_type());
 }
 
 AutofillType AutofillField::Type() const {
@@ -263,7 +274,7 @@
 
 bool AutofillField::IsCreditCardPrediction() const {
   return AutofillType(server_type()).group() == FieldTypeGroup::kCreditCard ||
-         AutofillType(heuristic_type_).group() == FieldTypeGroup::kCreditCard;
+         AutofillType(heuristic_type()).group() == FieldTypeGroup::kCreditCard;
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h
index 98da439..fdfd0c1b 100644
--- a/components/autofill/core/browser/autofill_field.h
+++ b/components/autofill/core/browser/autofill_field.h
@@ -37,6 +37,11 @@
     PHONE_SUFFIX = 2,
   };
 
+  enum class PredictionSource {
+    kDefaultHeuristics,
+    kMaxValue = kDefaultHeuristics
+  };
+
   AutofillField();
   explicit AutofillField(const FormFieldData& field);
 
@@ -51,8 +56,11 @@
   static std::unique_ptr<AutofillField> CreateForPasswordManagerUpload(
       FieldSignature field_signature);
 
-  ServerFieldType heuristic_type() const { return heuristic_type_; }
+  ServerFieldType heuristic_type() const;
   ServerFieldType server_type() const;
+  ServerFieldType get_prediction(PredictionSource s) const {
+    return local_type_predictions_[static_cast<size_t>(s)];
+  }
   bool server_type_prediction_is_override() const;
   const std::vector<
       AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction>&
@@ -81,6 +89,9 @@
   void set_server_predictions(
       std::vector<AutofillQueryResponse::FormSuggestion::FieldSuggestion::
                       FieldPrediction> predictions);
+  void set_prediction(PredictionSource s, ServerFieldType t) {
+    local_type_predictions_[static_cast<size_t>(s)] = t;
+  }
 
   void set_may_use_prefilled_placeholder(bool may_use_prefilled_placeholder) {
     may_use_prefilled_placeholder_ = may_use_prefilled_placeholder;
@@ -248,8 +259,12 @@
   // Corresponds to the requirements determined by the Autofill server.
   absl::optional<PasswordRequirementsSpec> password_requirements_;
 
-  // The type of the field, as determined by the local heuristics.
-  ServerFieldType heuristic_type_ = UNKNOWN_TYPE;
+  // Predictions which where calculated on the client. This is initialized to
+  // `NO_SERVER_DATA`, which means "NO_DATA", i.e. no classification was
+  // attempted.
+  std::array<ServerFieldType,
+             static_cast<size_t>(PredictionSource::kMaxValue) + 1>
+      local_type_predictions_;
 
   // The type of the field. Overrides all other types (html_type_,
   // heuristic_type_).
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index f3f4258..162c32f 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -136,6 +136,7 @@
   registry->RegisterBooleanPref(
       RandomizedEncoder::kUrlKeyedAnonymizedDataCollectionEnabled, false);
   registry->RegisterBooleanPref(::prefs::kMixedFormsWarningsEnabled, true);
+  registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
   return PrefServiceForTesting(registry.get());
 }
 
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index 4ca1e3b..b68fbe8 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -196,37 +196,6 @@
   }
 }
 
-absl::optional<AutofillMetrics::CreditCardSeamlessFillMetric> GetSeamlessness(
-    const ServerFieldTypeSet& filled_types) {
-  bool name = filled_types.contains(CREDIT_CARD_NAME_FULL) ||
-              (filled_types.contains(CREDIT_CARD_NAME_FIRST) &&
-               filled_types.contains(CREDIT_CARD_NAME_LAST));
-  bool number = filled_types.contains(CREDIT_CARD_NUMBER);
-  bool exp = filled_types.contains(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR) ||
-             filled_types.contains(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) ||
-             (filled_types.contains(CREDIT_CARD_EXP_MONTH) &&
-              (filled_types.contains(CREDIT_CARD_EXP_2_DIGIT_YEAR) ||
-               filled_types.contains(CREDIT_CARD_EXP_4_DIGIT_YEAR)));
-  bool cvc = filled_types.contains(CREDIT_CARD_VERIFICATION_CODE);
-
-  using M = AutofillMetrics::CreditCardSeamlessFillMetric;
-  if (!name && !number && !exp && !cvc) {
-    return absl::nullopt;
-  } else if (name && number && exp && cvc) {
-    return M::kFullFill;
-  } else if (!name && number && exp && cvc) {
-    return M::kOptionalNameMissing;
-  } else if (name && number && exp && !cvc) {
-    return M::kOptionalCvcMissing;
-  } else if (!name && number && exp && !cvc) {
-    return M::kOptionalNameAndCvcMissing;
-  } else if (name && number && !exp && cvc) {
-    return M::kFullFillButExpDateMissing;
-  } else {
-    return M::kPartialFill;
-  }
-}
-
 }  // namespace
 
 // First, translates |field_type| to the corresponding logical |group| from
@@ -2494,10 +2463,96 @@
       num_frames);
 }
 
+AutofillMetrics::CreditCardSeamlessness::CreditCardSeamlessness(
+    const ServerFieldTypeSet& filled_types)
+    : name_(filled_types.contains(CREDIT_CARD_NAME_FULL) ||
+            (filled_types.contains(CREDIT_CARD_NAME_FIRST) &&
+             filled_types.contains(CREDIT_CARD_NAME_LAST))),
+      number_(filled_types.contains(CREDIT_CARD_NUMBER)),
+      exp_(filled_types.contains(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR) ||
+           filled_types.contains(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) ||
+           (filled_types.contains(CREDIT_CARD_EXP_MONTH) &&
+            (filled_types.contains(CREDIT_CARD_EXP_2_DIGIT_YEAR) ||
+             filled_types.contains(CREDIT_CARD_EXP_4_DIGIT_YEAR)))),
+      cvc_(filled_types.contains(CREDIT_CARD_VERIFICATION_CODE)) {}
+
+AutofillMetrics::CreditCardSeamlessness::Metric
+AutofillMetrics::CreditCardSeamlessness::QualitativeUmaMetric() const {
+  DCHECK(is_valid());
+  if (name_ && number_ && exp_ && cvc_) {
+    return Metric::kFullFill;
+  } else if (!name_ && number_ && exp_ && cvc_) {
+    return Metric::kOptionalNameMissing;
+  } else if (name_ && number_ && exp_ && !cvc_) {
+    return Metric::kOptionalCvcMissing;
+  } else if (!name_ && number_ && exp_ && !cvc_) {
+    return Metric::kOptionalNameAndCvcMissing;
+  } else if (name_ && number_ && !exp_ && cvc_) {
+    return Metric::kFullFillButExpDateMissing;
+  } else {
+    return Metric::kPartialFill;
+  }
+}
+
+FormEvent
+AutofillMetrics::CreditCardSeamlessness::QualitativeFillableFormEvent() const {
+  DCHECK(is_valid());
+  switch (QualitativeUmaMetric()) {
+    case Metric::kFullFill:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_FULL_FILL;
+    case Metric::kOptionalNameMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_NAME_MISSING;
+    case Metric::kFullFillButExpDateMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_FULL_FILL_BUT_EXPDATE_MISSING;
+    case Metric::kOptionalNameAndCvcMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_NAME_AND_CVC_MISSING;
+    case Metric::kOptionalCvcMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_CVC_MISSING;
+    case Metric::kPartialFill:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_PARTIAL_FILL;
+  }
+  NOTREACHED();
+  return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_PARTIAL_FILL;
+}
+
+FormEvent AutofillMetrics::CreditCardSeamlessness::QualitativeFillFormEvent()
+    const {
+  DCHECK(is_valid());
+  switch (QualitativeUmaMetric()) {
+    case Metric::kFullFill:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_FULL_FILL;
+    case Metric::kOptionalNameMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_NAME_MISSING;
+    case Metric::kFullFillButExpDateMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_FULL_FILL_BUT_EXPDATE_MISSING;
+    case Metric::kOptionalNameAndCvcMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_NAME_AND_CVC_MISSING;
+    case Metric::kOptionalCvcMissing:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_CVC_MISSING;
+    case Metric::kPartialFill:
+      return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_PARTIAL_FILL;
+  }
+  NOTREACHED();
+  return FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_PARTIAL_FILL;
+}
+
+uint8_t AutofillMetrics::CreditCardSeamlessness::BitmaskUmaMetric() const {
+  DCHECK(is_valid());
+  uint8_t bitmask = (name_ << 3) | (number_ << 2) | (exp_ << 1) | (cvc_ << 0);
+  DCHECK_GE(bitmask, 1);
+  DCHECK_LE(bitmask, BitmaskExclusiveMax());
+  return bitmask;
+}
+
 // static
-absl::optional<AutofillMetrics::CreditCardSeamlessFillMetric>
+AutofillMetrics::CreditCardSeamlessness
 AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(
     const LogCreditCardSeamlessnessParam& p) {
+  std::string suffix =
+      base::StringPrintf("%s.AtFillTime%sSecurityPolicy",
+                         p.only_newly_filled_fields ? "Fills" : "Fillable",
+                         p.only_after_security_policy ? "After" : "Before");
+
   ServerFieldTypeSet autofilled_types;
   for (const auto& field : p.form) {
     FieldGlobalId id = field->global_id();
@@ -2507,33 +2562,30 @@
       continue;
     autofilled_types.insert(field->Type().GetStorableType());
   }
-  absl::optional<CreditCardSeamlessFillMetric> metric =
-      GetSeamlessness(autofilled_types);
 
-  std::string suffix =
-      base::StringPrintf("%s.AtFillTime%sSecurityPolicy",
-                         p.only_newly_filled_fields ? "Fills" : "Fillable",
-                         p.only_after_security_policy ? "After" : "Before");
-  if (metric) {
+  CreditCardSeamlessness seamlessness(autofilled_types);
+  if (seamlessness.is_valid()) {
+    base::UmaHistogramExactLinear(
+        "Autofill.CreditCard.Seamless" + suffix + ".Bitmask",
+        seamlessness.BitmaskUmaMetric(), seamlessness.BitmaskExclusiveMax());
     base::UmaHistogramEnumeration("Autofill.CreditCard.Seamless" + suffix,
-                                  *metric);
+                                  seamlessness.QualitativeUmaMetric());
   }
-  base::UmaHistogramBoolean("Autofill.CreditCard.Number" + suffix,
-                            autofilled_types.contains(CREDIT_CARD_NUMBER));
-  return metric;
+  return seamlessness;
 }
 
 // static
 void AutofillMetrics::LogCreditCardSeamlessnessAtSubmissionTime(
     const ServerFieldTypeSet& autofilled_types) {
-  absl::optional<CreditCardSeamlessFillMetric> metric =
-      GetSeamlessness(autofilled_types);
-  if (metric) {
+  CreditCardSeamlessness seamlessness(autofilled_types);
+  if (seamlessness.is_valid()) {
+    base::UmaHistogramExactLinear(
+        "Autofill.CreditCard.SeamlessFills.AtSubmissionTime.Bitmask",
+        seamlessness.BitmaskUmaMetric(), seamlessness.BitmaskExclusiveMax());
     base::UmaHistogramEnumeration(
-        "Autofill.CreditCard.SeamlessFills.AtSubmissionTime", *metric);
+        "Autofill.CreditCard.SeamlessFills.AtSubmissionTime",
+        seamlessness.QualitativeUmaMetric());
   }
-  base::UmaHistogramBoolean("Autofill.CreditCard.NumberFills.AtSubmissionTime",
-                            autofilled_types.contains(CREDIT_CARD_NUMBER));
 }
 
 // static
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h
index c17bd46..518b9b78 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -1174,34 +1174,45 @@
     kMaxValue = kOtpMismatchError,
   };
 
-  // Emits a value that indicates which fields of a credit card form were
-  // filled:
-  //
-  // +-------------------------------------------------------------+
-  // |                            | Name | Number | Exp Date | CVC |
-  // |----------------------------+------+--------+----------+-----|
-  // | kFullFill                  |  X   |   X    |    X     |  X  |
-  // +----------------------------+------+--------+----------+-----+
-  // | kOptionalNameMissing       |      |   X    |    X     |  X  |
-  // +----------------------------+------+--------+----------+-----+
-  // | kOptionalCvcMissing        |  X   |   X    |    X     |     |
-  // +----------------------------+------+--------+----------+-----+
-  // | kOptionalNameAndCvcMissing |      |   X    |    X     |     |
-  // +----------------------------+------+--------+----------+-----+
-  // | kFullFillButExpDateMissing |  X   |   X    |          |  X  |
-  // +----------------------------+------+--------+----------+-----+
-  // | kPartialFill               |           otherwise            |
-  // +-------------------------------------------------------------+
-  //
-  // Keep consistent with FORM_EVENT_CREDIT_CARD_SEAMLESSNESS_*.
-  enum class CreditCardSeamlessFillMetric {
-    kFullFill = 0,
-    kOptionalNameMissing = 1,
-    kOptionalCvcMissing = 2,
-    kOptionalNameAndCvcMissing = 3,
-    kFullFillButExpDateMissing = 4,
-    kPartialFill = 5,
-    kMaxValue = kPartialFill,
+  // Utility class for determining the seamlessness of a credit card fill.
+  class CreditCardSeamlessness {
+   public:
+    // A qualitative representation of a fill seamlessness.
+    //
+    // Keep consistent with FORM_EVENT_CREDIT_CARD_SEAMLESSNESS_*.
+    //
+    // The different meaning of the categories is as follows:
+    enum class Metric {                // | Name | Number | Exp Date | CVC |
+      kFullFill = 0,                   // |  X   |   X    |    X     |  X  |
+      kOptionalNameMissing = 1,        // |      |   X    |    X     |  X  |
+      kOptionalCvcMissing = 2,         // |  X   |   X    |    X     |     |
+      kOptionalNameAndCvcMissing = 3,  // |      |   X    |    X     |     |
+      kFullFillButExpDateMissing = 4,  // |  X   |   X    |          |  X  |
+      kPartialFill = 5,                // |           otherwise            |
+      kMaxValue = kPartialFill,
+    };
+
+    explicit CreditCardSeamlessness(const ServerFieldTypeSet& filled_types);
+
+    explicit operator bool() const { return is_valid(); }
+    bool is_valid() const { return name_ || number_ || exp_ || cvc_; }
+
+    // Returns the metric for UMA logging or the corresponding FormEvent value
+    // for UKM logging.
+    Metric QualitativeUmaMetric() const;
+    FormEvent QualitativeFillableFormEvent() const;
+    FormEvent QualitativeFillFormEvent() const;
+
+    // Returns the bitmask for UMA logging.
+    uint8_t BitmaskUmaMetric() const;
+
+    static uint8_t BitmaskExclusiveMax() { return true << 4; }
+
+   private:
+    bool name_ = false;
+    bool number_ = false;
+    bool exp_ = false;
+    bool cvc_ = false;
   };
 
   // These values are persisted to logs. Entries should not be renumbered and
@@ -1801,14 +1812,10 @@
   // Logs one variant of Autofill.CreditCard.Seamless{Fillable,Fills}.
   // AtFillTime{Before,After}SecurityPolicy metrics, depending on the parameter
   // `p`. Returns the emitted metric, if any.
-  //
-  // In addition, logs Autofill.CreditCard.Number{Fillable,Fills}.
-  // AtFillTime{Before,After}SecurityPolicy.
-  static absl::optional<CreditCardSeamlessFillMetric>
-  LogCreditCardSeamlessnessAtFillTime(const LogCreditCardSeamlessnessParam& p);
+  static CreditCardSeamlessness LogCreditCardSeamlessnessAtFillTime(
+      const LogCreditCardSeamlessnessParam& p);
 
-  // Logs Autofill.CreditCard.SeamlessFills.AtSubmissionTime and
-  // Autofill.CreditCard.NumberFills.AtSubmissionTime.
+  // Logs Autofill.CreditCard.SeamlessFills.AtSubmissionTime.
   static void LogCreditCardSeamlessnessAtSubmissionTime(
       const ServerFieldTypeSet& autofilled_types);
 
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 93aab5a7..c41cd77 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -12749,7 +12749,7 @@
 }
 
 // Base class for cross-frame filling metrics, in particular for
-// Autofill.CreditCard.SeamlessFills.* and Autofill.CreditCard.NumberFills.*.
+// Autofill.CreditCard.SeamlessFills.*.
 class AutofillMetricsCrossFrameFormTest : public AutofillMetricsTest {
  public:
   struct CreditCardAndCvc {
@@ -12882,7 +12882,7 @@
 };
 
 // Tests that Autofill.CreditCard.SeamlessFills.* is not emitted for manual
-// fills and that Autofill.CreditCard.NumberFills.AtSubmissionTime emits false.
+// fills.
 TEST_F(AutofillMetricsCrossFrameFormTest,
        DoNotLogCreditCardSeamlessFillsMetricIfNotAutofilled) {
   base::HistogramTester histogram_tester;
@@ -12901,35 +12901,37 @@
   CommitMetrics();
 
   histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.NumberFills.AtFillTimeBeforeSecurityPolicy", 0);
-  histogram_tester.ExpectTotalCount(
       "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy", 0);
-
   histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.NumberFills.AtFillTimeAfterSecurityPolicy", 0);
+      "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy."
+      "Bitmask",
+      0);
+
   histogram_tester.ExpectTotalCount(
       "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy", 0);
-
   histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.NumberFillable.AtFillTimeBeforeSecurityPolicy", 0);
+      "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy.Bitmask",
+      0);
+
   histogram_tester.ExpectTotalCount(
       "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy", 0);
-
   histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.NumberFillable.AtFillTimeAfterSecurityPolicy", 0);
+      "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy."
+      "Bitmask",
+      0);
+
   histogram_tester.ExpectTotalCount(
       "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy", 0);
-
-  ExpectBuckets<bool>(histogram_tester,
-                      "Autofill.CreditCard.NumberFills.AtSubmissionTime",
-                      {{false, 1}, {true, 0}});
+  histogram_tester.ExpectTotalCount(
+      "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy."
+      "Bitmask",
+      0);
 }
 
-// Tests that Autofill.CreditCard.SeamlessFills.* and
-// Autofill.CreditCard.NumberFills.* are emitted.
+// Tests that Autofill.CreditCard.SeamlessFills.* are emitted.
 TEST_F(AutofillMetricsCrossFrameFormTest,
        LogCreditCardSeamlessFillsMetricIfAutofilledWithoutCvc) {
-  using SFM = AutofillMetrics::CreditCardSeamlessFillMetric;
+  using Metric = AutofillMetrics::CreditCardSeamlessness::Metric;
   base::HistogramTester histogram_tester;
   SeeForm();
 
@@ -12959,48 +12961,52 @@
   SubmitForm();
   CommitMetrics();
 
-  ExpectBuckets<bool>(
-      histogram_tester,
-      "Autofill.CreditCard.NumberFillable.AtFillTimeBeforeSecurityPolicy",
-      {{false, 0}, {true, 2}});
-  ExpectBuckets<SFM>(
+  ExpectBuckets<Metric>(
       histogram_tester,
       "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy",
-      {{SFM::kFullFill, 2}});
-
-  ExpectBuckets<bool>(
+      {{Metric::kFullFill, 2}});
+  ExpectBuckets<int>(
       histogram_tester,
-      "Autofill.CreditCard.NumberFills.AtFillTimeBeforeSecurityPolicy",
-      {{false, 0}, {true, 2}});
-  ExpectBuckets<SFM>(
+      "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy."
+      "Bitmask",
+      {{/*cardholder*/ 8 | /*number*/ 4 | /*exp*/ 2 | /*cvc*/ 1, 2}});
+
+  ExpectBuckets<Metric>(
       histogram_tester,
       "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy",
-      {{SFM::kOptionalCvcMissing, 1}, {SFM::kPartialFill, 1}});
-
-  ExpectBuckets<bool>(
+      {{Metric::kOptionalCvcMissing, 1}, {Metric::kPartialFill, 1}});
+  ExpectBuckets<int>(
       histogram_tester,
-      "Autofill.CreditCard.NumberFillable.AtFillTimeAfterSecurityPolicy",
-      {{false, 1}, {true, 1}});
-  ExpectBuckets<SFM>(
+      "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy."
+      "Bitmask",
+      {{/*cardholder*/ 8 | /*number*/ 4 | /*exp*/ 2, 1}, {/*number*/ 4, 1}});
+
+  ExpectBuckets<Metric>(
       histogram_tester,
       "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy",
-      {{SFM::kPartialFill, 2}});
-
-  ExpectBuckets<bool>(
+      {{Metric::kPartialFill, 2}});
+  ExpectBuckets<int>(
       histogram_tester,
-      "Autofill.CreditCard.NumberFills.AtFillTimeAfterSecurityPolicy",
-      {{false, 1}, {true, 1}});
-  ExpectBuckets<SFM>(
+      "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy."
+      "Bitmask",
+      {{/*cardholder*/ 8 | /*exp*/ 2, 1}, {/*number*/ 4 | /*cvc*/ 1, 1}});
+
+  ExpectBuckets<Metric>(
       histogram_tester,
       "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy",
-      {{SFM::kPartialFill, 2}});
+      {{Metric::kPartialFill, 2}});
+  ExpectBuckets<int>(
+      histogram_tester,
+      "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy.Bitmask",
+      {{/*cardholder*/ 8 | /*exp*/ 2, 1}, {/*number*/ 4, 1}});
 
-  ExpectBuckets<bool>(histogram_tester,
-                      "Autofill.CreditCard.NumberFills.AtSubmissionTime",
-                      {{false, 0}, {true, 1}});
-  ExpectBuckets<SFM>(histogram_tester,
-                     "Autofill.CreditCard.SeamlessFills.AtSubmissionTime",
-                     {{SFM::kOptionalCvcMissing, 1}});
+  ExpectBuckets<Metric>(histogram_tester,
+                        "Autofill.CreditCard.SeamlessFills.AtSubmissionTime",
+                        {{Metric::kOptionalCvcMissing, 1}});
+  ExpectBuckets<int>(
+      histogram_tester,
+      "Autofill.CreditCard.SeamlessFills.AtSubmissionTime.Bitmask",
+      {{/*cardholder*/ 8 | /*number*/ 4 | /*exp*/ 2, 1}});
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
index 1a70efe..6e0f785 100644
--- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -126,9 +126,8 @@
 
     param.only_newly_filled_fields = false;
     param.only_after_security_policy = false;
-    absl::optional<AutofillMetrics::CreditCardSeamlessFillMetric>
-        fillable_seamlessness =
-            AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(param);
+    if (auto s = AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(param))
+      Log(s.QualitativeFillableFormEvent(), form);
 
     param.only_newly_filled_fields = false;
     param.only_after_security_policy = true;
@@ -140,62 +139,8 @@
 
     param.only_newly_filled_fields = true;
     param.only_after_security_policy = true;
-    absl::optional<AutofillMetrics::CreditCardSeamlessFillMetric>
-        fill_seamlessness =
-            AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(param);
-
-    if (fillable_seamlessness) {
-      switch (*fillable_seamlessness) {
-        using M = AutofillMetrics::CreditCardSeamlessFillMetric;
-        case M::kFullFill:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_FULL_FILL, form);
-          break;
-        case M::kOptionalNameMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_NAME_MISSING,
-              form);
-          break;
-        case M::kFullFillButExpDateMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_FULL_FILL_BUT_EXPDATE_MISSING,
-              form);
-          break;
-        case M::kOptionalNameAndCvcMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_NAME_AND_CVC_MISSING,
-              form);
-          break;
-        case M::kOptionalCvcMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_CVC_MISSING,
-              form);
-          break;
-        case M::kPartialFill:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_PARTIAL_FILL, form);
-          break;
-      }
-    }
-    if (fill_seamlessness) {
-      switch (*fill_seamlessness) {
-        using M = AutofillMetrics::CreditCardSeamlessFillMetric;
-        case M::kFullFill:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_FULL_FILL, form);
-          break;
-        case M::kOptionalNameMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_NAME_MISSING, form);
-          break;
-        case M::kFullFillButExpDateMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_FULL_FILL_BUT_EXPDATE_MISSING,
-              form);
-          break;
-        case M::kOptionalNameAndCvcMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_NAME_AND_CVC_MISSING,
-              form);
-          break;
-        case M::kOptionalCvcMissing:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_OPTIONAL_CVC_MISSING, form);
-          break;
-        case M::kPartialFill:
-          Log(FORM_EVENT_CREDIT_CARD_SEAMLESS_FILL_PARTIAL_FILL, form);
-          break;
-      }
-    }
+    if (auto s = AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(param))
+      Log(s.QualitativeFillFormEvent(), form);
 
     // In a multi-frame form, a cross-origin field is only filled if
     // shared-autofill is enabled in the field's frame. If Autofill was
diff --git a/components/autofill/core/browser/metrics/form_events/form_events.h b/components/autofill/core/browser/metrics/form_events/form_events.h
index 9a88b52..05a68e1c 100644
--- a/components/autofill/core/browser/metrics/form_events/form_events.h
+++ b/components/autofill/core/browser/metrics/form_events/form_events.h
@@ -127,7 +127,7 @@
   // which a frame can allow a child-frame to be autofilled across origin.
   FORM_EVENT_CREDIT_CARD_MISSING_SHARED_AUTOFILL = 49,
 
-  // See AutofillMetrics::CreditCardSeamlessFillMetric for details.
+  // See AutofillMetrics::CreditCardSeamlessness::Metric for details.
   FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_FULL_FILL = 50,
   FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_NAME_MISSING = 51,
   FORM_EVENT_CREDIT_CARD_SEAMLESS_FILLABLE_OPTIONAL_CVC_MISSING = 52,
diff --git a/components/autofill/core/common/autofill_prefs.cc b/components/autofill/core/common/autofill_prefs.cc
index 2fa47fb..fb4dd6c5 100644
--- a/components/autofill/core/common/autofill_prefs.cc
+++ b/components/autofill/core/common/autofill_prefs.cc
@@ -179,8 +179,6 @@
   // Deprecated prefs registered for migration.
   registry->RegisterBooleanPref(kAutofillJapanCityFieldMigratedDeprecated,
                                 false);
-  // Deprecated in profile prefs.
-  registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
 }
 
 void MigrateDeprecatedAutofillPrefs(PrefService* prefs) {
@@ -214,11 +212,6 @@
 
   // Added 10/2019.
   prefs->ClearPref(kAutofillJapanCityFieldMigratedDeprecated);
-
-  // Added 11/2020
-  // TODO(crbug.com/1147852): Remove deprecated kAutofillStatesDataDir from
-  // autofill profile prefs.
-  prefs->ClearPref(kAutofillStatesDataDir);
 }
 
 bool IsAutocompleteEnabled(const PrefService* prefs) {
diff --git a/components/autofill_assistant/browser/actions/save_generated_password_action.cc b/components/autofill_assistant/browser/actions/save_generated_password_action.cc
index 0f490eaf..772bce7 100644
--- a/components/autofill_assistant/browser/actions/save_generated_password_action.cc
+++ b/components/autofill_assistant/browser/actions/save_generated_password_action.cc
@@ -50,13 +50,13 @@
     return;
   }
 
-  if (!delegate_->GetWebsiteLoginManager()->ReadyToCommitGeneratedPassword()) {
+  if (!delegate_->GetWebsiteLoginManager()->ReadyToSaveGeneratedPassword()) {
     VLOG(1) << "SaveGeneratedPasswordAction: no generated password to save.";
     EndAction(ClientStatus(PRECONDITION_FAILED));
     return;
   }
 
-  delegate_->GetWebsiteLoginManager()->CommitGeneratedPassword();
+  delegate_->GetWebsiteLoginManager()->SaveGeneratedPassword();
 
   delegate_->GetPasswordChangeSuccessTracker()->OnChangePasswordFlowCompleted(
       delegate_->GetUserData()->selected_login_->origin,
diff --git a/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc b/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
index dcc79c4e..ef69b05 100644
--- a/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
@@ -68,7 +68,7 @@
   user_data_.SetAdditionalValue(kMemoryKeyForGeneratedPassword,
                                 SimpleValue(std::string(kGeneratedPassword)));
 
-  ON_CALL(mock_website_login_manager_, ReadyToCommitGeneratedPassword)
+  ON_CALL(mock_website_login_manager_, ReadyToSaveGeneratedPassword)
       .WillByDefault(Return(true));
 
   SaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
@@ -77,7 +77,7 @@
       callback_,
       Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
 
-  EXPECT_CALL(mock_website_login_manager_, CommitGeneratedPassword);
+  EXPECT_CALL(mock_website_login_manager_, SaveGeneratedPassword);
   EXPECT_CALL(
       mock_password_change_success_tracker_,
       OnChangePasswordFlowCompleted(GURL(kOrigin), kUsername,
@@ -107,7 +107,7 @@
   user_data_.SetAdditionalValue(kMemoryKeyForGeneratedPassword,
                                 SimpleValue(std::string(kGeneratedPassword)));
 
-  ON_CALL(mock_website_login_manager_, ReadyToCommitGeneratedPassword)
+  ON_CALL(mock_website_login_manager_, ReadyToSaveGeneratedPassword)
       .WillByDefault(Return(false));
 
   SaveGeneratedPasswordAction action(&mock_action_delegate_, proto_);
@@ -115,9 +115,9 @@
   EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
                                               PRECONDITION_FAILED))));
 
-  EXPECT_CALL(mock_website_login_manager_, ReadyToCommitGeneratedPassword)
+  EXPECT_CALL(mock_website_login_manager_, ReadyToSaveGeneratedPassword)
       .Times(1);
-  EXPECT_CALL(mock_website_login_manager_, CommitGeneratedPassword).Times(0);
+  EXPECT_CALL(mock_website_login_manager_, SaveGeneratedPassword).Times(0);
 
   action.ProcessAction(callback_.Get());
 }
diff --git a/components/autofill_assistant/browser/actions/save_submitted_password_action.cc b/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
index c8205d6..ba92174 100644
--- a/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
+++ b/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
@@ -27,7 +27,7 @@
   callback_ = std::move(callback);
 
   // If no password form has been submitted, fail.
-  if (!delegate_->GetWebsiteLoginManager()->ReadyToCommitSubmittedPassword()) {
+  if (!delegate_->GetWebsiteLoginManager()->ReadyToSaveSubmittedPassword()) {
     VLOG(1) << "SaveSubmittedPasswordAction: no submitted password to save.";
     EndAction(ClientStatus(PRECONDITION_FAILED));
     return;
diff --git a/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc b/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
index 23d933b4..71e9791a 100644
--- a/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
@@ -55,7 +55,7 @@
 TEST_F(SaveSubmittedPasswordActionTest, SaveSubmittedPasswordSuccess) {
   user_data_.selected_login_.emplace(GURL(kOrigin), kUsername);
 
-  EXPECT_CALL(mock_website_login_manager_, ReadyToCommitSubmittedPassword)
+  EXPECT_CALL(mock_website_login_manager_, ReadyToSaveSubmittedPassword)
       .WillOnce(Return(true));
   EXPECT_CALL(mock_website_login_manager_, SubmittedPasswordIsSame)
       .WillOnce(Return(false));
@@ -79,7 +79,7 @@
 TEST_F(SaveSubmittedPasswordActionTest, AttemptToSaveSameSubmittedPassword) {
   user_data_.selected_login_.emplace(GURL(kOrigin), kUsername);
 
-  EXPECT_CALL(mock_website_login_manager_, ReadyToCommitSubmittedPassword)
+  EXPECT_CALL(mock_website_login_manager_, ReadyToSaveSubmittedPassword)
       .WillOnce(Return(true));
   EXPECT_CALL(mock_website_login_manager_, SubmittedPasswordIsSame)
       .WillOnce(Return(true));
@@ -101,8 +101,8 @@
 }
 
 TEST_F(SaveSubmittedPasswordActionTest,
-       ReadyToCommitSubmittedPasswordPreconditionFails) {
-  EXPECT_CALL(mock_website_login_manager_, ReadyToCommitSubmittedPassword)
+       ReadyToSaveSubmittedPasswordPreconditionFails) {
+  EXPECT_CALL(mock_website_login_manager_, ReadyToSaveSubmittedPassword)
       .WillOnce(Return(false));
   EXPECT_CALL(mock_website_login_manager_, SaveSubmittedPassword).Times(0);
   EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index a6ab2cd1..83908b4 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -114,17 +114,17 @@
         .WillByDefault(Return(&fake_script_executor_ui_delegate_));
 
     // Fetching scripts succeeds for all URLs, but return nothing.
-    ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+    ON_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
         .WillByDefault(RunOnceCallback<2>(
             net::HTTP_OK, "", ServiceRequestSender::ResponseInfo{}));
 
     // Scripts run, but have no actions.
-    ON_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _))
+    ON_CALL(*mock_service_, GetActions)
         .WillByDefault(RunOnceCallback<5>(
             net::HTTP_OK, "", ServiceRequestSender::ResponseInfo{}));
 
-    ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
-        .WillByDefault(RunOnceCallback<5>(
+    ON_CALL(*mock_service_, GetNextActions)
+        .WillByDefault(RunOnceCallback<6>(
             net::HTTP_OK, "", ServiceRequestSender::ResponseInfo{}));
 
     ON_CALL(*mock_web_controller_, FindElement(_, _, _))
@@ -168,7 +168,7 @@
   void SetupScripts(SupportsScriptResponseProto scripts) {
     std::string scripts_str;
     scripts.SerializeToString(&scripts_str);
-    EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+    EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
         .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str,
                                      ServiceRequestSender::ResponseInfo{}));
   }
@@ -177,7 +177,7 @@
                              ActionsResponseProto actions_response) {
     std::string actions_response_str;
     actions_response.SerializeToString(&actions_response_str);
-    EXPECT_CALL(*mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
+    EXPECT_CALL(*mock_service_, GetActions(StrEq(path), _, _, _, _, _))
         .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                      ServiceRequestSender::ResponseInfo{}));
   }
@@ -221,7 +221,7 @@
     std::string response_str;
     response.SerializeToString(&response_str);
 
-    EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+    EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
         .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                      ServiceRequestSender::ResponseInfo{}));
   }
@@ -231,7 +231,7 @@
     std::string response_str;
     response.SerializeToString(&response_str);
 
-    EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+    EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
         .WillRepeatedly(RunOnceCallback<2>(
             net::HTTP_OK, response_str, ServiceRequestSender::ResponseInfo{}));
   }
@@ -348,12 +348,12 @@
                         Field(&DirectAction::optional_arguments,
                               ElementsAre("arg0", "arg1"))))));
 
-  EXPECT_CALL(*mock_service_, OnGetActions("action", _, _, _, _, _))
-      .WillOnce(Invoke([](const std::string& script_path, const GURL& url,
-                          const TriggerContext& trigger_context,
-                          const std::string& global_payload,
-                          const std::string& script_payload,
-                          ServiceRequestSender::ResponseCallback& callback) {
+  EXPECT_CALL(*mock_service_, GetActions("action", _, _, _, _, _))
+      .WillOnce([](const std::string& script_path, const GURL& url,
+                   const TriggerContext& trigger_context,
+                   const std::string& global_payload,
+                   const std::string& script_payload,
+                   ServiceRequestSender::ResponseCallback callback) {
         EXPECT_THAT(trigger_context.GetScriptParameters().ToProto(),
                     testing::UnorderedElementsAreArray(
                         base::flat_map<std::string, std::string>(
@@ -361,7 +361,7 @@
         EXPECT_TRUE(trigger_context.GetDirectAction());
 
         std::move(callback).Run(true, "", ServiceRequestSender::ResponseInfo{});
-      }));
+      });
 
   TriggerContext::Options options;
   options.is_direct_action = true;
@@ -523,7 +523,7 @@
   actions_response.add_actions()->mutable_stop();
   std::string actions_response_str;
   actions_response.SerializeToString(&actions_response_str);
-  EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetActions(StrEq("stop"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -548,7 +548,7 @@
   actions_response.add_actions()->mutable_stop();
   std::string actions_response_str;
   actions_response.SerializeToString(&actions_response_str);
-  EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetActions(StrEq("stop"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -571,7 +571,7 @@
   actions_response.add_actions()->mutable_stop()->set_close_cct(true);
   std::string actions_response_str;
   actions_response.SerializeToString(&actions_response_str);
-  EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetActions(StrEq("stop"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -593,11 +593,11 @@
   script_response.SerializeToString(&scripts_str);
 
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(Eq(GURL("http://a.example.com/path1")), _, _))
+              GetScriptsForUrl(Eq(GURL("http://a.example.com/path1")), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str,
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(Eq(GURL("http://b.example.com/path1")), _, _))
+              GetScriptsForUrl(Eq(GURL("http://b.example.com/path1")), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -633,7 +633,7 @@
 
 TEST_F(ControllerTest, InitialUrlLoads) {
   GURL initialUrl("http://a.example.com/path");
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
+  EXPECT_CALL(*mock_service_, GetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -714,7 +714,7 @@
   std::string on_timeout_error_str;
   on_timeout_error.SerializeToString(&on_timeout_error_str);
   EXPECT_CALL(*mock_service_,
-              OnGetActions(StrEq("on_timeout_error"), _, _, _, _, _))
+              GetActions(StrEq("on_timeout_error"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, on_timeout_error_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -747,7 +747,7 @@
   std::string on_timeout_error_str;
   on_timeout_error.SerializeToString(&on_timeout_error_str);
   EXPECT_CALL(*mock_service_,
-              OnGetActions(StrEq("on_timeout_error"), _, _, _, _, _))
+              GetActions(StrEq("on_timeout_error"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, on_timeout_error_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -912,10 +912,10 @@
   SetupActionsForScript("script", actions_response);
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   Start("http://a.example.com/path");
@@ -948,10 +948,10 @@
   SetupActionsForScript("script", actions_response);
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   Start("http://a.example.com/path");
@@ -1018,12 +1018,12 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://b.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://b.example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1219,7 +1219,7 @@
 
   // Running the script fails, due to a backend issue. The error message should
   // be shown.
-  EXPECT_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1251,7 +1251,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1262,7 +1262,7 @@
   EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
   ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
 
-  EXPECT_CALL(*mock_service_, OnGetActions(StrEq("runnable"), _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetActions(StrEq("runnable"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1282,13 +1282,12 @@
 
 TEST_F(ControllerTest, TrackReportsFirstSetOfScripts) {
   ServiceRequestSender::ResponseCallback get_scripts_callback;
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
-      .WillOnce(
-          Invoke([&get_scripts_callback](
-                     const GURL& url, const TriggerContext& trigger_context,
-                     ServiceRequestSender::ResponseCallback& callback) {
-            get_scripts_callback = std::move(callback);
-          }));
+  EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
+      .WillOnce([&get_scripts_callback](
+                    const GURL& url, const TriggerContext& trigger_context,
+                    ServiceRequestSender::ResponseCallback callback) {
+        get_scripts_callback = std::move(callback);
+      });
 
   SetLastCommittedUrl(GURL("http://example.com/"));
   bool first_check_done = false;
@@ -1434,14 +1433,14 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://b.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://b.example.com/"), _, _))
       .Times(0);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://c.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://c.example.com/"), _, _))
       .Times(0);
 
   Start("http://example.com/");
@@ -1480,7 +1479,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://a.example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1531,7 +1530,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://a.example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1571,7 +1570,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1603,7 +1602,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1914,7 +1913,7 @@
   std::string response_str;
   script_response.SerializeToString(&response_str);
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
+              GetScriptsForUrl(GURL("http://a.example.com/"), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1999,7 +1998,7 @@
 TEST_F(ControllerTest, StartPasswordChangeFlow) {
   const GURL initialUrl("http://example.com/password");
   const std::string username = "test_username";
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
+  EXPECT_CALL(*mock_service_, GetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(mock_password_change_success_tracker_,
@@ -2044,10 +2043,10 @@
   SetupActionsForScript("script", actions_response);
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(*mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   Start("http://a.example.com/path");
@@ -2146,7 +2145,7 @@
 
 TEST_F(ControllerTest, OnGetScriptsFailedWillShutdown) {
   EXPECT_CALL(mock_observer_, OnStart(_));
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+  EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
       .WillOnce(RunOnceCallback<2>(net::HTTP_NOT_FOUND, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(
diff --git a/components/autofill_assistant/browser/empty_website_login_manager_impl.cc b/components/autofill_assistant/browser/empty_website_login_manager_impl.cc
index cb3efcb..b52a1f9b 100644
--- a/components/autofill_assistant/browser/empty_website_login_manager_impl.cc
+++ b/components/autofill_assistant/browser/empty_website_login_manager_impl.cc
@@ -63,15 +63,15 @@
   std::move(callback).Run();
 }
 
-bool EmptyWebsiteLoginManagerImpl::ReadyToCommitGeneratedPassword() {
+bool EmptyWebsiteLoginManagerImpl::ReadyToSaveGeneratedPassword() {
   return false;
 }
 
-void EmptyWebsiteLoginManagerImpl::CommitGeneratedPassword() {}
+void EmptyWebsiteLoginManagerImpl::SaveGeneratedPassword() {}
 
 void EmptyWebsiteLoginManagerImpl::ResetPendingCredentials() {}
 
-bool EmptyWebsiteLoginManagerImpl::ReadyToCommitSubmittedPassword() {
+bool EmptyWebsiteLoginManagerImpl::ReadyToSaveSubmittedPassword() {
   return false;
 }
 
diff --git a/components/autofill_assistant/browser/empty_website_login_manager_impl.h b/components/autofill_assistant/browser/empty_website_login_manager_impl.h
index 3f5f7dbb..6352f6f 100644
--- a/components/autofill_assistant/browser/empty_website_login_manager_impl.h
+++ b/components/autofill_assistant/browser/empty_website_login_manager_impl.h
@@ -47,10 +47,10 @@
                                 const std::string& password,
                                 const autofill::FormData& form_data,
                                 base::OnceCallback<void()> callback) override;
-  bool ReadyToCommitGeneratedPassword() override;
-  void CommitGeneratedPassword() override;
+  bool ReadyToSaveGeneratedPassword() override;
+  void SaveGeneratedPassword() override;
   void ResetPendingCredentials() override;
-  bool ReadyToCommitSubmittedPassword() override;
+  bool ReadyToSaveSubmittedPassword() override;
   bool SubmittedPasswordIsSame() override;
   bool SaveSubmittedPassword() override;
 };
diff --git a/components/autofill_assistant/browser/mock_website_login_manager.h b/components/autofill_assistant/browser/mock_website_login_manager.h
index 9cc20bd7..46136a5 100644
--- a/components/autofill_assistant/browser/mock_website_login_manager.h
+++ b/components/autofill_assistant/browser/mock_website_login_manager.h
@@ -69,13 +69,13 @@
   MOCK_METHOD2(OnDeletePasswordForLogin,
                void(const Login& login, base::OnceCallback<void(bool)>&));
 
-  MOCK_METHOD(bool, ReadyToCommitGeneratedPassword, (), (override));
+  MOCK_METHOD(bool, ReadyToSaveGeneratedPassword, (), (override));
 
-  MOCK_METHOD(void, CommitGeneratedPassword, (), (override));
+  MOCK_METHOD(void, SaveGeneratedPassword, (), (override));
 
   MOCK_METHOD(void, ResetPendingCredentials, (), (override));
 
-  MOCK_METHOD(bool, ReadyToCommitSubmittedPassword, (), (override));
+  MOCK_METHOD(bool, ReadyToSaveSubmittedPassword, (), (override));
 
   MOCK_METHOD(bool, SubmittedPasswordIsSame, (), (override));
 
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc
index 760c11c..e6086274 100644
--- a/components/autofill_assistant/browser/protocol_utils.cc
+++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -201,6 +201,7 @@
     const std::string& script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
     const RoundtripTimingStats& timing_stats,
+    const RoundtripNetworkStats& network_stats,
     const ClientContextProto& client_context) {
   ScriptActionRequestProto request_proto;
   request_proto.set_global_payload(global_payload);
@@ -211,6 +212,7 @@
     next_request->add_processed_actions()->MergeFrom(processed_action);
   }
   *next_request->mutable_timing_stats() = timing_stats;
+  *next_request->mutable_network_stats() = network_stats;
   *request_proto.mutable_client_context() = client_context;
   std::string serialized_request_proto;
   bool success = request_proto.SerializeToString(&serialized_request_proto);
@@ -966,4 +968,26 @@
   return serialized_request_proto;
 }
 
+// static
+RoundtripNetworkStats ProtocolUtils::ComputeNetworkStats(
+    const std::string& response,
+    const ServiceRequestSender::ResponseInfo& response_info,
+    const std::vector<std::unique_ptr<Action>>& actions) {
+  RoundtripNetworkStats stats;
+  stats.set_roundtrip_decoded_body_size_bytes(response.size());
+  stats.set_roundtrip_encoded_body_size_bytes(
+      response_info.encoded_body_length);
+  for (const auto& action : actions) {
+    RoundtripNetworkStats::ActionNetworkStats* action_stats =
+        stats.add_action_stats();
+    action_stats->set_action_info_case(
+        static_cast<int>(action->proto().action_info_case()));
+
+    std::string serialized_action;
+    action->proto().SerializeToString(&serialized_action);
+    action_stats->set_decoded_size_bytes(serialized_action.size());
+  }
+  return stats;
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/protocol_utils.h b/components/autofill_assistant/browser/protocol_utils.h
index 963d25f8..f3f885f 100644
--- a/components/autofill_assistant/browser/protocol_utils.h
+++ b/components/autofill_assistant/browser/protocol_utils.h
@@ -15,6 +15,7 @@
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/script_parameters.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
 #include "components/autofill_assistant/browser/trigger_scripts/trigger_script.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -64,6 +65,7 @@
       const std::string& script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       const RoundtripTimingStats& timing_stats,
+      const RoundtripNetworkStats& network_stats,
       const ClientContextProto& client_context);
 
   // Create request to get the available trigger scripts for |url|.
@@ -131,6 +133,13 @@
       absl::optional<int>* trigger_condition_timeout_ms,
       absl::optional<std::unique_ptr<ScriptParameters>>* script_parameters);
 
+  // Computes network stats for a roundtrip that returned |response| and
+  // |response_info|, which were successfully parsed into |actions|.
+  static RoundtripNetworkStats ComputeNetworkStats(
+      const std::string& response,
+      const ServiceRequestSender::ResponseInfo& response_info,
+      const std::vector<std::unique_ptr<Action>>& actions);
+
  private:
   // Checks that the |trigger_condition| is well-formed (e.g. does not contain
   // regexes that cannot be compiled).
diff --git a/components/autofill_assistant/browser/protocol_utils_unittest.cc b/components/autofill_assistant/browser/protocol_utils_unittest.cc
index a44417e..7ce0b5d 100644
--- a/components/autofill_assistant/browser/protocol_utils_unittest.cc
+++ b/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -48,19 +48,6 @@
   ClientContextProto client_context_proto_;
 };
 
-void AssertClientContext(const ClientContextProto& context) {
-  EXPECT_EQ("1,2,3", context.experiment_ids());
-  EXPECT_TRUE(context.is_cct());
-  EXPECT_EQ("v", context.chrome().chrome_version());
-  EXPECT_EQ(1, context.device_context().version().sdk_int());
-  EXPECT_EQ("ma", context.device_context().manufacturer());
-  EXPECT_EQ("mo", context.device_context().model());
-  EXPECT_FALSE(context.is_onboarding_shown());
-  EXPECT_FALSE(context.is_direct_action());
-  EXPECT_THAT(context.accounts_matching_status(),
-              Eq(ClientContextProto::UNKNOWN));
-}
-
 TEST_F(ProtocolUtilsTest, ScriptMissingPath) {
   SupportedScriptProto script;
   std::vector<std::unique_ptr<Script>> scripts;
@@ -128,7 +115,7 @@
   EXPECT_THAT(initial.script_parameters(),
               UnorderedElementsAreArray(parameters.ToProto()));
 
-  AssertClientContext(request.client_context());
+  EXPECT_EQ(request.client_context(), client_context_proto_);
   EXPECT_EQ("global_payload", request.global_payload());
   EXPECT_EQ("script_payload", request.script_payload());
   EXPECT_EQ("bundle/path", initial.script_store_config().bundle_path());
@@ -139,12 +126,24 @@
   ScriptActionRequestProto request;
   std::vector<ProcessedActionProto> processed_actions;
   processed_actions.emplace_back(ProcessedActionProto());
+
+  RoundtripNetworkStats network_stats;
+  network_stats.set_roundtrip_encoded_body_size_bytes(12345);
+  network_stats.set_roundtrip_decoded_body_size_bytes(23456);
+  auto* action_stats = network_stats.add_action_stats();
+  action_stats->set_action_info_case(5);
+  action_stats->set_decoded_size_bytes(35);
+  action_stats = network_stats.add_action_stats();
+  action_stats->set_action_info_case(7);
+  action_stats->set_decoded_size_bytes(15);
+
   EXPECT_TRUE(
       request.ParseFromString(ProtocolUtils::CreateNextScriptActionsRequest(
           "global_payload", "script_payload", processed_actions,
-          RoundtripTimingStats(), client_context_proto_)));
+          RoundtripTimingStats(), network_stats, client_context_proto_)));
 
-  AssertClientContext(request.client_context());
+  EXPECT_EQ(request.client_context(), client_context_proto_);
+  EXPECT_EQ(request.next_request().network_stats(), network_stats);
   EXPECT_EQ(1, request.next_request().processed_actions().size());
 }
 
@@ -154,7 +153,7 @@
   EXPECT_TRUE(request.ParseFromString(ProtocolUtils::CreateGetScriptsRequest(
       GURL("http://example.com/"), client_context_proto_, parameters)));
 
-  AssertClientContext(request.client_context());
+  EXPECT_EQ(request.client_context(), client_context_proto_);
   EXPECT_THAT(request.script_parameters(),
               UnorderedElementsAreArray(parameters.ToProto()));
   EXPECT_EQ("http://example.com/", request.url());
@@ -344,7 +343,7 @@
       request.ParseFromString(ProtocolUtils::CreateGetTriggerScriptsRequest(
           GURL("http://example.com/"), client_context_proto_, parameters)));
 
-  AssertClientContext(request.client_context());
+  EXPECT_EQ(request.client_context(), client_context_proto_);
   EXPECT_THAT(request.script_parameters(),
               UnorderedElementsAreArray(
                   ScriptParameters(base::flat_map<std::string, std::string>{
@@ -629,4 +628,40 @@
               ElementsAre("VISA", "MASTERCARD"));
 }
 
+TEST_F(ProtocolUtilsTest, ComputeNetworkStats) {
+  ActionProto tell_action;
+  tell_action.mutable_tell()->set_message("Hello world!");
+  std::string serialized_tell_action;
+  tell_action.SerializeToString(&serialized_tell_action);
+
+  ActionProto stop_action;
+  stop_action.mutable_stop()->set_close_cct(false);
+  std::string serialized_stop_action;
+  stop_action.SerializeToString(&serialized_stop_action);
+
+  std::vector<std::unique_ptr<Action>> actions;
+  actions.push_back(ProtocolUtils::ParseAction(/* delegate = */ nullptr,
+                                               serialized_tell_action));
+  actions.push_back(ProtocolUtils::ParseAction(/* delegate = */ nullptr,
+                                               serialized_stop_action));
+
+  ServiceRequestSender::ResponseInfo response_info;
+  response_info.encoded_body_length = 20;
+
+  RoundtripNetworkStats expected_stats;
+  expected_stats.set_roundtrip_encoded_body_size_bytes(20);
+  expected_stats.set_roundtrip_decoded_body_size_bytes(28);
+  auto* action_stats = expected_stats.add_action_stats();
+  action_stats->set_action_info_case(11);  // == tell
+  action_stats->set_decoded_size_bytes(serialized_tell_action.size());
+  action_stats = expected_stats.add_action_stats();
+  action_stats->set_action_info_case(35);  // == stop
+  action_stats->set_decoded_size_bytes(serialized_stop_action.size());
+
+  EXPECT_EQ(ProtocolUtils::ComputeNetworkStats(
+                /* response = */ "This string is 28 bytes long", response_info,
+                actions),
+            expected_stats);
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index e125b25..5a1e674 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -822,8 +822,8 @@
   // Doesn't trigger when the script is completed.
   roundtrip_timing_stats_.set_roundtrip_time_ms(
       roundtrip_duration.InMilliseconds());
-  bool success =
-      http_status == net::HTTP_OK && ProcessNextActionResponse(response);
+  bool success = http_status == net::HTTP_OK &&
+                 ProcessNextActionResponse(response, response_info);
   if (should_stop_script_) {
     // The last action forced the script to stop. Sending the result of the
     // action is considered best effort in this situation. Report a successful
@@ -858,7 +858,9 @@
   RunCallback(true);
 }
 
-bool ScriptExecutor::ProcessNextActionResponse(const std::string& response) {
+bool ScriptExecutor::ProcessNextActionResponse(
+    const std::string& response,
+    const ServiceRequestSender::ResponseInfo& response_info) {
   processed_actions_.clear();
   actions_.clear();
 
@@ -871,6 +873,8 @@
     return false;
   }
 
+  roundtrip_network_stats_ =
+      ProtocolUtils::ComputeNetworkStats(response, response_info, actions_);
   ReportPayloadsToListener();
   if (should_update_scripts) {
     ReportScriptsUpdateToListener(std::move(scripts));
@@ -965,7 +969,7 @@
       TriggerContext(
           {delegate_->GetTriggerContext(), additional_context_.get()}),
       last_global_payload_, last_script_payload_, processed_actions_,
-      roundtrip_timing_stats_,
+      roundtrip_timing_stats_, roundtrip_network_stats_,
       base::BindOnce(&ScriptExecutor::OnGetActions,
                      weak_ptr_factory_.GetWeakPtr(), get_next_actions_start));
 }
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 0b598723..3b171f0 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -273,7 +273,9 @@
                     int http_status,
                     const std::string& response,
                     const ServiceRequestSender::ResponseInfo& response_info);
-  bool ProcessNextActionResponse(const std::string& response);
+  bool ProcessNextActionResponse(
+      const std::string& response,
+      const ServiceRequestSender::ResponseInfo& response_info);
   void ReportPayloadsToListener();
   void ReportScriptsUpdateToListener(
       std::vector<std::unique_ptr<Script>> scripts);
@@ -392,6 +394,7 @@
 
   base::TimeTicks batch_start_time_;
   RoundtripTimingStats roundtrip_timing_stats_;
+  RoundtripNetworkStats roundtrip_network_stats_;
 
   bool connection_warning_already_shown_ = false;
   bool website_warning_already_shown_ = false;
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index fcdf8f8..7b080c0 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -116,7 +116,7 @@
         ToSelectorProto(element);
     wait_action->set_allow_interrupt(true);
     interruptible.add_actions()->mutable_tell()->set_message(path);
-    EXPECT_CALL(mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
+    EXPECT_CALL(mock_service_, GetActions(StrEq(path), _, _, _, _, _))
         .WillRepeatedly(
             RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                ServiceRequestSender::ResponseInfo{}));
@@ -128,7 +128,7 @@
 
     ActionsResponseProto interrupt_actions;
     InitInterruptActions(&interrupt_actions, path);
-    EXPECT_CALL(mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
+    EXPECT_CALL(mock_service_, GetActions(StrEq(path), _, _, _, _, _))
         .WillRepeatedly(
             RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions),
                                ServiceRequestSender::ResponseInfo{}));
@@ -178,7 +178,7 @@
 };
 
 TEST_F(ScriptExecutorTest, GetActionsFails) {
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
@@ -195,12 +195,12 @@
       std::make_unique<ScriptParameters>(
           base::flat_map<std::string, std::string>{{"param", "value"}}),
       options));
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
-      .WillOnce(Invoke([](const std::string& script_path, const GURL& url,
-                          const TriggerContext& trigger_context,
-                          const std::string& global_payload,
-                          const std::string& script_payload,
-                          ServiceRequestSender::ResponseCallback& callback) {
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
+      .WillOnce([](const std::string& script_path, const GURL& url,
+                   const TriggerContext& trigger_context,
+                   const std::string& global_payload,
+                   const std::string& script_payload,
+                   ServiceRequestSender::ResponseCallback callback) {
         // |trigger_context| includes data passed to
         // ScriptExecutor constructor as well as data from the
         // delegate's TriggerContext.
@@ -215,7 +215,7 @@
 
         std::move(callback).Run(net::HTTP_OK, "",
                                 ServiceRequestSender::ResponseInfo{});
-      }));
+      });
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -226,15 +226,15 @@
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_js_click();  // Invalid.
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
@@ -252,7 +252,7 @@
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
   initial_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
                                    Serialize(initial_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
@@ -261,14 +261,14 @@
   next_actions_response.add_actions()->mutable_tell()->set_message("3");
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           SaveArg<3>(&processed_actions1_capture),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions2_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -293,7 +293,7 @@
       ClientSettingsProto::SlowWarningSettings::REPLACE;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
@@ -301,12 +301,12 @@
 
   ActionsResponseProto next_actions_response;
   next_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -328,7 +328,7 @@
       ClientSettingsProto::SlowWarningSettings::CONCATENATE;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
@@ -336,12 +336,12 @@
 
   ActionsResponseProto next_actions_response;
   next_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -365,7 +365,7 @@
       ClientSettingsProto::SlowWarningSettings::REPLACE;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
@@ -373,12 +373,12 @@
 
   ActionsResponseProto next_actions_response;
   next_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -401,7 +401,7 @@
       ClientSettingsProto::SlowWarningSettings::REPLACE;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
@@ -409,12 +409,12 @@
 
   ActionsResponseProto next_actions_response;
   next_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -433,7 +433,7 @@
   client_settings->max_consecutive_slow_roundtrips = 2;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
@@ -441,15 +441,15 @@
 
   ActionsResponseProto next_actions_response;
   next_actions_response.add_actions()->mutable_tell()->set_message("2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(DoAll(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(DoAll(RunOnceCallback<6>(net::HTTP_OK,
                                          Serialize(initial_actions_response),
                                          ServiceRequestSender::ResponseInfo{})))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(initial_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -465,19 +465,19 @@
   client_settings->max_consecutive_slow_roundtrips = 2;
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
           RunOnceCallback<5>(net::HTTP_OK, Serialize(initial_actions_response),
                              ServiceRequestSender::ResponseInfo{})));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(initial_actions_response),
                                    ServiceRequestSender::ResponseInfo{}))
       .WillOnce(
           DoAll(Delay(&task_environment_, 600),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -505,7 +505,7 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(
           DoAll(Delay(&task_environment_, 600),
                 RunOnceCallback<5>(net::HTTP_OK, Serialize(tell1_waitfordom),
@@ -524,14 +524,14 @@
   tell2.add_actions()->mutable_tell()->set_message("2");
   ActionsResponseProto tell3;
   tell3.add_actions()->mutable_tell()->set_message("3");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(Delay(&task_environment_, 600),
-                      RunOnceCallback<5>(net::HTTP_OK, Serialize(tell2),
+                      RunOnceCallback<6>(net::HTTP_OK, Serialize(tell2),
                                          ServiceRequestSender::ResponseInfo{})))
       .WillOnce(DoAll(Delay(&task_environment_, 600),
-                      RunOnceCallback<5>(net::HTTP_OK, Serialize(tell3),
+                      RunOnceCallback<6>(net::HTTP_OK, Serialize(tell3),
                                          ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -553,7 +553,7 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -577,7 +577,7 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -608,7 +608,7 @@
   *second_wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element2");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -625,8 +625,8 @@
       .WillOnce(DoAll(Delay(&task_environment_, 2000),
                       RunOnceCallback<2>(
                           ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(next_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   executor_->Run(&user_data_, executor_callback_.Get());
@@ -660,7 +660,7 @@
   ActionsResponseProto tell3;
   tell3.add_actions()->mutable_tell()->set_message("3");
 
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(
           DoAll(Delay(&task_environment_, 600),
                 RunOnceCallback<5>(net::HTTP_OK, Serialize(tell1),
@@ -675,15 +675,15 @@
         std::move(callback).Run(OkClientStatus(),
                                 std::make_unique<ElementFinder::Result>());
       }));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(Delay(&task_environment_, 600),
-                RunOnceCallback<5>(net::HTTP_OK, Serialize(tell2_waitfordom),
+                RunOnceCallback<6>(net::HTTP_OK, Serialize(tell2_waitfordom),
                                    ServiceRequestSender::ResponseInfo{})))
       .WillOnce(DoAll(Delay(&task_environment_, 600),
-                      RunOnceCallback<5>(net::HTTP_OK, Serialize(tell3),
+                      RunOnceCallback<6>(net::HTTP_OK, Serialize(tell3),
                                          ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -721,7 +721,7 @@
   ActionsResponseProto tell3;
   tell3.add_actions()->mutable_tell()->set_message("3");
 
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(
           DoAll(Delay(&task_environment_, 600),
                 RunOnceCallback<5>(net::HTTP_OK, Serialize(tell1),
@@ -736,15 +736,15 @@
         std::move(callback).Run(OkClientStatus(),
                                 std::make_unique<ElementFinder::Result>());
       }));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           Delay(&task_environment_, 600),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(tell2_and_waitfordom),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(tell2_and_waitfordom),
                              ServiceRequestSender::ResponseInfo{})))
       .WillOnce(DoAll(Delay(&task_environment_, 600),
-                      RunOnceCallback<5>(net::HTTP_OK, Serialize(tell3),
+                      RunOnceCallback<6>(net::HTTP_OK, Serialize(tell3),
                                          ServiceRequestSender::ResponseInfo{})))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -762,15 +762,15 @@
   ActionsResponseProto actions_response;
   actions_response.add_actions();  // action definition missing
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -784,12 +784,12 @@
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_stop();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
@@ -803,15 +803,15 @@
   actions_response.add_actions()->mutable_stop();
   actions_response.add_actions()->mutable_tell()->set_message("should not run");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
@@ -832,7 +832,7 @@
   initial_actions_response.add_actions()->mutable_tell()->set_message(
       "never run");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
                                    Serialize(initial_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
@@ -842,14 +842,14 @@
       "will run after error");
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(
           SaveArg<3>(&processed_actions1_capture),
-          RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response),
+          RunOnceCallback<6>(net::HTTP_OK, Serialize(next_actions_response),
                              ServiceRequestSender::ResponseInfo{})))
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions2_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -872,15 +872,15 @@
   action->mutable_tell()->set_message("delayed");
   action->set_action_delay_ms(1000);
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // executor_callback_.Run() not expected to be run just yet, as the action is
@@ -903,11 +903,11 @@
 
   *actions_response.add_actions() = click_with_clean_contextual_ui;
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -926,11 +926,11 @@
   *actions_response.add_actions() = click_with_clean_contextual_ui;
   actions_response.add_actions()->mutable_tell()->set_message("Wait no!");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -944,11 +944,11 @@
 TEST_F(ScriptExecutorTest, ClearDetailsOnError) {
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_tell()->set_message("Hello");
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
@@ -965,17 +965,17 @@
   actions_response.set_script_payload("actions payload");
   actions_response.add_actions()->mutable_tell()->set_message("ok");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, "initial global payload",
-                                          "initial payload", _))
+  EXPECT_CALL(mock_service_, GetActions(_, _, _, "initial global payload",
+                                        "initial payload", _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   ActionsResponseProto next_actions_response;
   next_actions_response.set_global_payload("last global payload");
   next_actions_response.set_script_payload("last payload");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
-                                              "actions payload", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_, GetNextActions(_, "actions global payload",
+                                            "actions payload", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(next_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -992,14 +992,14 @@
   actions_response.set_script_payload("actions payload");
   actions_response.add_actions()->mutable_tell()->set_message("ok");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, "initial global payload",
-                                          "initial payload", _))
+  EXPECT_CALL(mock_service_, GetActions(_, _, _, "initial global payload",
+                                        "initial payload", _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
-                                              "actions payload", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_, GetNextActions(_, "actions global payload",
+                                            "actions payload", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_, Run(_));
@@ -1015,14 +1015,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // First check does not find the element, wait for dom waits 1s, then the
@@ -1053,27 +1053,27 @@
   // Both scripts end after the first set of actions. Capture the results.
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(SaveArg<3>(&processed_actions1_capture),
-                      RunOnceCallback<5>(net::HTTP_OK, "",
+                      RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{})))
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions2_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  // The first script to call OnGetNextActions is the interrupt, which starts
+  // The first script to call GetNextActions is the interrupt, which starts
   // with a tell.
   ASSERT_THAT(processed_actions1_capture, Not(IsEmpty()));
   EXPECT_EQ(ActionProto::ActionInfoCase::kTell,
             processed_actions1_capture[0].action().action_info_case());
   EXPECT_EQ(ACTION_APPLIED, processed_actions1_capture[0].status());
 
-  // The second script to call OnGetNextActions is the main script, with starts
+  // The second script to call GetNextActions is the main script, with starts
   // with a wait_for_dom
   ASSERT_THAT(processed_actions2_capture, Not(IsEmpty()));
   EXPECT_EQ(ActionProto::ActionInfoCase::kWaitForDom,
@@ -1091,16 +1091,16 @@
   {
     testing::InSequence seq;
     EXPECT_CALL(mock_service_,
-                OnGetNextActions(_, _, "payload for interrupt1", _, _, _))
-        .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+                GetNextActions(_, _, "payload for interrupt1", _, _, _, _))
+        .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                      ServiceRequestSender::ResponseInfo{}));
     EXPECT_CALL(mock_service_,
-                OnGetNextActions(_, _, "payload for interrupt2", _, _, _))
-        .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+                GetNextActions(_, _, "payload for interrupt2", _, _, _, _))
+        .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                      ServiceRequestSender::ResponseInfo{}));
     EXPECT_CALL(mock_service_,
-                OnGetNextActions(_, _, "main script payload", _, _, _))
-        .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+                GetNextActions(_, _, "main script payload", _, _, _, _))
+        .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                      ServiceRequestSender::ResponseInfo{}));
   }
 
@@ -1118,7 +1118,7 @@
         ToSelectorProto("element");
     wait_action->set_allow_interrupt(true);
   }
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("script_path"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("script_path"), _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                          ServiceRequestSender::ResponseInfo{}));
 
@@ -1126,15 +1126,15 @@
   RegisterInterrupt("interrupt", "interrupt_trigger");
   ActionsResponseProto interrupt_actions;
   InitInterruptActions(&interrupt_actions, "interrupt");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("interrupt"), _, _, _, _, _))
       .Times(3)
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK,
                                          Serialize(interrupt_actions),
                                          ServiceRequestSender::ResponseInfo{}));
 
   // All scripts succeed with no more actions.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1151,9 +1151,10 @@
       "last global payload from interrupt");
   next_interrupt_actions_response.set_script_payload(
       "last payload from interrupt");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
-                                              "payload for interrupt", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_,
+              GetNextActions(_, "global payload for interrupt",
+                             "payload for interrupt", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(next_interrupt_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1162,9 +1163,9 @@
       "last global payload from main");
   next_main_actions_response.set_script_payload("last payload from main");
   EXPECT_CALL(mock_service_,
-              OnGetNextActions(_, "last global payload from interrupt",
-                               "main script payload", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+              GetNextActions(_, "last global payload from interrupt",
+                             "main script payload", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(next_main_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1180,14 +1181,15 @@
   SetupInterruptibleScript(kScriptPath, "element");
   SetupInterrupt("interrupt", "interrupt_trigger");
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
-                                              "payload for interrupt", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_,
+              GetNextActions(_, "global payload for interrupt",
+                             "payload for interrupt", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
-                                              "main script payload", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_, GetNextActions(_, "global payload for interrupt",
+                                            "main script payload", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_, Run(_));
@@ -1216,10 +1218,10 @@
   // The script ends after the first set of actions. There is only one call
   // from the main script, running a WaitForDom - none from the interrupt.
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   EXPECT_CALL(executor_callback_,
@@ -1239,7 +1241,7 @@
   *wait_action->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
   // allow_interrupt is not set
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1250,10 +1252,10 @@
   // The script ends after the first set of actions. There is only one call
   // from the main script, running a WaitForDom - none from the interrupt.
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   EXPECT_CALL(executor_callback_,
@@ -1273,20 +1275,19 @@
 
   // The interrupt fails.
   EXPECT_CALL(mock_service_,
-              OnGetNextActions(_, _, "payload for interrupt", _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+              GetNextActions(_, _, "payload for interrupt", _, _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   // The main script gets a report of the failure from the interrupt, and fails
   // in turn.
-  EXPECT_CALL(
-      mock_service_,
-      OnGetNextActions(
-          _, _, "main script payload",
-          ElementsAre(Property(&ProcessedActionProto::status,
-                               ProcessedActionStatusProto::INTERRUPT_FAILED)),
-          _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_,
+              GetNextActions(_, _, "main script payload",
+                             ElementsAre(Property(
+                                 &ProcessedActionProto::status,
+                                 ProcessedActionStatusProto::INTERRUPT_FAILED)),
+                             _, _, _))
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1304,16 +1305,16 @@
   interrupt_actions.add_actions()->mutable_stop();
 
   // Get interrupt actions
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("interrupt"), _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK,
                                          Serialize(interrupt_actions),
                                          ServiceRequestSender::ResponseInfo{}));
 
   // We expect to get result of interrupt action, then result of the main script
   // action.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .Times(2)
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1338,7 +1339,7 @@
        ->mutable_auto_select_when()
        ->mutable_match() = ToSelectorProto("end_prompt");
 
-  EXPECT_CALL(mock_service_, OnGetActions("interrupt", _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions("interrupt", _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK,
                                          Serialize(interrupt_actions),
                                          ServiceRequestSender::ResponseInfo{}));
@@ -1357,7 +1358,7 @@
   *prompt_action->add_choices()->mutable_auto_select_when()->mutable_match() =
       ToSelectorProto("end_prompt");
   interruptible.add_actions()->mutable_tell()->set_message("done");
-  EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                          ServiceRequestSender::ResponseInfo{}));
 
@@ -1376,8 +1377,8 @@
                                 std::make_unique<ElementFinder::Result>());
       }));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1421,7 +1422,7 @@
   prompt->add_choices()->mutable_chip()->set_text("done");
   prompt->set_browse_mode(true);
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1434,7 +1435,7 @@
   auto* prompt = actions_response.add_actions()->mutable_prompt();
   prompt->add_choices()->mutable_chip()->set_text("done");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1453,7 +1454,7 @@
   prompt_action->set_allow_interrupt(true);
   *prompt_action->add_choices()->mutable_auto_select_when()->mutable_match() =
       ToSelectorProto("end_prompt");
-  EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                          ServiceRequestSender::ResponseInfo{}));
 
@@ -1490,8 +1491,8 @@
                                 std::make_unique<ElementFinder::Result>());
       }));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1516,7 +1517,7 @@
 
   ActionsResponseProto initial_actions_response;
   initial_actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
                                    Serialize(initial_actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
@@ -1529,11 +1530,11 @@
   auto* presentation = script->mutable_presentation();
   presentation->mutable_precondition();
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK,
                                    Serialize(next_actions_response),
                                    ServiceRequestSender::ResponseInfo{}))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1558,15 +1559,15 @@
   auto* presentation = script->mutable_presentation();
   presentation->mutable_precondition();
 
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
   script->set_path("path2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1590,7 +1591,7 @@
   ActionsResponseProto interrupt_actions;
   interrupt_actions.add_actions()->mutable_tell()->set_message("abc");
 
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("interrupt"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -1602,11 +1603,11 @@
   // We expect a call from the interrupt which will update the script list and a
   // second call from the interrupt to terminate. Then a call from the main
   // script which will finish without running any actions.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .Times(3)
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions),
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, Serialize(interrupt_actions),
                                    ServiceRequestSender::ResponseInfo{}))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1627,7 +1628,7 @@
   *wait_action->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
   wait_action->set_allow_interrupt(true);
-  EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                          ServiceRequestSender::ResponseInfo{}));
 
@@ -1635,13 +1636,13 @@
   ActionsResponseProto interrupt_actions;
   interrupt_actions.add_actions()->mutable_tell()->set_message(
       "interrupt status");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("interrupt"), _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK,
                                          Serialize(interrupt_actions),
                                          ServiceRequestSender::ResponseInfo{}));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1660,12 +1661,12 @@
   *wait_action->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
   wait_action->set_allow_interrupt(true);
-  EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible),
                                          ServiceRequestSender::ResponseInfo{}));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   EXPECT_CALL(executor_callback_,
@@ -1683,14 +1684,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // First check does not find the element, wait for dom waits 1s.
@@ -1727,14 +1728,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // Navigation starts before WaitForDom starts. WaitForDom does not wait and
@@ -1762,25 +1763,23 @@
   // A load even happens when loading the interrupt scripts, so while the
   // interrupt is being executed. This should not interfere with the WaitForDom
   // action that's running the interrupt.
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
-      .WillRepeatedly(
-          DoAll(InvokeWithoutArgs(
-                    [this]() { delegate_.UpdateNavigationState(true, false); }),
-                RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions),
-                                   ServiceRequestSender::ResponseInfo{}),
-                InvokeWithoutArgs([this]() {
-                  delegate_.UpdateNavigationState(false, false);
-                })));
+  EXPECT_CALL(mock_service_, GetActions(StrEq("interrupt"), _, _, _, _, _))
+      .WillRepeatedly(WithArgs<5>([this, interrupt_actions](auto callback) {
+        delegate_.UpdateNavigationState(true, false);
+        std::move(callback).Run(net::HTTP_OK, Serialize(interrupt_actions),
+                                ServiceRequestSender::ResponseInfo{});
+        delegate_.UpdateNavigationState(false, false);
+      }));
 
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(DoAll(SaveArg<3>(&processed_actions1_capture),
-                      RunOnceCallback<5>(net::HTTP_OK, "",
+                      RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{})))
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions2_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   EXPECT_CALL(executor_callback_, Run(_));
@@ -1795,14 +1794,14 @@
   actions_response.add_actions()->mutable_tell()->set_message("a");
   actions_response.add_actions()->mutable_tell()->set_message("b");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ true);
@@ -1822,14 +1821,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // WaitForDom does NOT wait for navigation to end, it immediately checks for
@@ -1864,14 +1863,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // As the element doesn't exist, WaitForDom returns and waits for 1s.
@@ -1904,14 +1903,14 @@
   *wait_for_dom->mutable_wait_condition()->mutable_match() =
       ToSelectorProto("element");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // As the element doesn't exist, WaitForDom returns and waits for 1s.
@@ -1942,14 +1941,14 @@
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_wait_for_navigation();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // WaitForNavigation returns immediately
@@ -1965,14 +1964,14 @@
   actions_response.add_actions()->mutable_expect_navigation();
   actions_response.add_actions()->mutable_wait_for_navigation();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // WaitForNavigation waits for navigation to start after expect_navigation
@@ -1993,14 +1992,14 @@
   actions_response.add_actions()->mutable_wait_for_navigation();
   actions_response.add_actions()->mutable_wait_for_navigation();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // The first wait_for_navigation waits for the navigation to happen. After
@@ -2022,14 +2021,14 @@
   actions_response.add_actions()->mutable_expect_navigation();
   actions_response.add_actions()->mutable_wait_for_navigation();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   delegate_.UpdateNavigationState(/* navigating= */ true, /* error= */ false);
@@ -2059,14 +2058,14 @@
   actions_response.add_actions()->mutable_expect_navigation();
   actions_response.add_actions()->mutable_wait_for_navigation();
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<3>(&processed_actions_capture),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
 
   // WaitForNavigation waits for navigation to start after expect_navigation
@@ -2088,7 +2087,7 @@
       ->mutable_chip()
       ->set_text("done");
 
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
 
@@ -2099,7 +2098,7 @@
 
   // The prompt action must finish. We don't bother continuing with the script
   // in this test.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _));
+  EXPECT_CALL(mock_service_, GetNextActions);
 
   (*ui_delegate_.GetUserActions())[0].RunCallback();
   EXPECT_EQ(AutofillAssistantState::RUNNING, delegate_.GetState());
@@ -2110,19 +2109,17 @@
   ActionProto* action = actions_response.add_actions();
   action->mutable_tell()->set_message("1");
   action->set_action_delay_ms(1000);
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(
           DoAll(Delay(&task_environment_, 200),
                 RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{})));
 
-  ActionsResponseProto next_actions_response;
-  next_actions_response.add_actions()->mutable_tell()->set_message("3");
   RoundtripTimingStats timing_stats;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetNextActions)
       .WillOnce(
           DoAll(SaveArg<4>(&timing_stats),
-                RunOnceCallback<5>(net::HTTP_OK, "",
+                RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{})));
   executor_->Run(&user_data_, executor_callback_.Get());
   EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
@@ -2136,14 +2133,46 @@
   EXPECT_EQ(1000, timing_stats.client_time_ms());
 }
 
+TEST_F(ScriptExecutorTest, RoundtripNetworkStats) {
+  ActionsResponseProto actions_response;
+  ActionProto* action = actions_response.add_actions();
+  action->mutable_tell()->set_message("Hello world");
+
+  ServiceRequestSender::ResponseInfo response_info;
+  response_info.encoded_body_length = 12;
+
+  EXPECT_CALL(mock_service_, GetActions)
+      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
+                                   response_info));
+
+  RoundtripNetworkStats captured_network_stats;
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(
+          DoAll(SaveArg<5>(&captured_network_stats),
+                RunOnceCallback<6>(net::HTTP_OK, "",
+                                   ServiceRequestSender::ResponseInfo{})));
+
+  EXPECT_CALL(executor_callback_,
+              Run(Field(&ScriptExecutor::Result::success, true)));
+  executor_->Run(&user_data_, executor_callback_.Get());
+
+  EXPECT_EQ(captured_network_stats.roundtrip_encoded_body_size_bytes(), 12);
+  EXPECT_EQ(captured_network_stats.roundtrip_decoded_body_size_bytes(),
+            static_cast<size_t>(Serialize(actions_response).size()));
+  ASSERT_EQ(captured_network_stats.action_stats().size(), 1);
+  EXPECT_EQ(captured_network_stats.action_stats(0).action_info_case(), 11);
+  EXPECT_EQ(captured_network_stats.action_stats(0).decoded_size_bytes(),
+            static_cast<size_t>(Serialize(*action).size()));
+}
+
 TEST_F(ScriptExecutorTest, ClearPersistentUiOnError) {
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_tell()->set_message("1");
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions)
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_UNAUTHORIZED, "",
                                    ServiceRequestSender::ResponseInfo{}));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index 6d0cdda..6ac64e67 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -47,7 +47,7 @@
             ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
 
     // Scripts run, but have no actions.
-    ON_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+    ON_CALL(mock_service_, GetActions)
         .WillByDefault(RunOnceCallback<5>(
             net::HTTP_OK, "", ServiceRequestSender::ResponseInfo{}));
   }
@@ -285,12 +285,11 @@
   InitScriptProto(actions_response.mutable_update_script_list()->add_scripts(),
                   "update path 2", "exists", "direct_action_name");
 
-  EXPECT_CALL(mock_service_,
-              OnGetActions(StrEq("runnable name"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("runnable name"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
@@ -327,12 +326,11 @@
   InitScriptProto(actions_response.mutable_update_script_list()->add_scripts(),
                   "update path 2", "exists", "direct_action_name");
 
-  EXPECT_CALL(mock_service_,
-              OnGetActions(StrEq("runnable name"), _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions(StrEq("runnable name"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillOnce(RunOnceCallback<6>(net::HTTP_OK, "",
                                    ServiceRequestSender::ResponseInfo{}));
 
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
@@ -368,18 +366,18 @@
   InitScriptProto(interrupt_proto, "interrupt", "exists");
   interrupt_proto->mutable_presentation()->set_interrupt(true);
 
-  EXPECT_CALL(mock_service_, OnGetActions("main", _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions("main", _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response),
                                    ServiceRequestSender::ResponseInfo{}));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, "",
+  EXPECT_CALL(mock_service_, GetNextActions)
+      .WillRepeatedly(RunOnceCallback<6>(net::HTTP_OK, "",
                                          ServiceRequestSender::ResponseInfo{}));
 
   ActionsResponseProto actions_interrupt;
   actions_response.set_script_payload("from interrupt");
   actions_response.add_actions()->mutable_tell()->set_message("interrupt");
 
-  EXPECT_CALL(mock_service_, OnGetActions("interrupt", _, _, _, _, _))
+  EXPECT_CALL(mock_service_, GetActions("interrupt", _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_interrupt),
                                    ServiceRequestSender::ResponseInfo{}));
 
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 52b0a69..d957629 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -641,6 +641,27 @@
   optional int64 client_time_ms = 2;
 }
 
+message RoundtripNetworkStats {
+  message ActionNetworkStats {
+    // The action type.
+    optional int32 action_info_case = 1;
+    // The size of this action after decoding, in bytes.
+    optional int64 decoded_size_bytes = 2;
+  }
+  // The total size of the received HTTP response body in bytes, before
+  // decoding. This is essentially the network footprint of the received
+  // response, modulo HTTP headers.
+  optional int64 roundtrip_encoded_body_size_bytes = 1;
+  // The total size of the received HTTP response body in bytes, after
+  // decoding. This is essentially the memory footprint of the received proto,
+  // and a baseline to compare the footprint of individual actions with.
+  optional int64 roundtrip_decoded_body_size_bytes = 2;
+  // The network stats for ALL received actions. Note that this may include
+  // actions that were not executed, so this list can be longer than
+  // |processed_actions|.
+  repeated ActionNetworkStats action_stats = 3;
+}
+
 // Next request to get a script's actions.
 message NextScriptActionsRequestProto {
   // The result of processing each ActionProto from the previous response. This
@@ -652,6 +673,8 @@
   // Tracks whether the last roundtrip triggered a slow connection warning and
   // whether it was shown to the user.
   optional SlowWarningStatus slow_connection_warning = 34;
+  // Roundtrip network stats for this RPC.
+  optional RoundtripNetworkStats network_stats = 3;
 }
 
 message CUPResponseData {
diff --git a/components/autofill_assistant/browser/service/java_service.cc b/components/autofill_assistant/browser/service/java_service.cc
index 1ee2edf..754cd68e 100644
--- a/components/autofill_assistant/browser/service/java_service.cc
+++ b/components/autofill_assistant/browser/service/java_service.cc
@@ -68,6 +68,7 @@
     const std::string& previous_script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
     const RoundtripTimingStats& timing_stats,
+    const RoundtripNetworkStats& network_stats,
     ServiceRequestSender::ResponseCallback callback) {
   JNIEnv* env = base::android::AttachCurrentThread();
   auto jprocessed_actions =
diff --git a/components/autofill_assistant/browser/service/java_service.h b/components/autofill_assistant/browser/service/java_service.h
index 8673db3d..471859f4 100644
--- a/components/autofill_assistant/browser/service/java_service.h
+++ b/components/autofill_assistant/browser/service/java_service.h
@@ -54,6 +54,7 @@
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       const RoundtripTimingStats& timing_stats,
+      const RoundtripNetworkStats& network_stats,
       ServiceRequestSender::ResponseCallback callback) override;
 
   // Get user data.
diff --git a/components/autofill_assistant/browser/service/java_test_endpoint_service.cc b/components/autofill_assistant/browser/service/java_test_endpoint_service.cc
index 1369cc0909..b4020f97 100644
--- a/components/autofill_assistant/browser/service/java_test_endpoint_service.cc
+++ b/components/autofill_assistant/browser/service/java_test_endpoint_service.cc
@@ -115,10 +115,11 @@
     const std::string& previous_script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
     const RoundtripTimingStats& timing_stats,
+    const RoundtripNetworkStats& network_stats,
     ServiceRequestSender::ResponseCallback callback) {
-  service_impl_->GetNextActions(trigger_context, previous_global_payload,
-                                previous_script_payload, processed_actions,
-                                timing_stats, std::move(callback));
+  service_impl_->GetNextActions(
+      trigger_context, previous_global_payload, previous_script_payload,
+      processed_actions, timing_stats, network_stats, std::move(callback));
 }
 
 void JavaTestEndpointService::GetUserData(
diff --git a/components/autofill_assistant/browser/service/java_test_endpoint_service.h b/components/autofill_assistant/browser/service/java_test_endpoint_service.h
index 1cc936e..3e05aa34 100644
--- a/components/autofill_assistant/browser/service/java_test_endpoint_service.h
+++ b/components/autofill_assistant/browser/service/java_test_endpoint_service.h
@@ -44,6 +44,7 @@
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       const RoundtripTimingStats& timing_stats,
+      const RoundtripNetworkStats& network_stats,
       ServiceRequestSender::ResponseCallback callback) override;
 
   void GetUserData(const CollectUserDataOptions& options,
diff --git a/components/autofill_assistant/browser/service/mock_service.cc b/components/autofill_assistant/browser/service/mock_service.cc
index 92da091..d8a280c7 100644
--- a/components/autofill_assistant/browser/service/mock_service.cc
+++ b/components/autofill_assistant/browser/service/mock_service.cc
@@ -10,13 +10,7 @@
 
 namespace autofill_assistant {
 
-MockService::MockService()
-    : ServiceImpl(/* client= */ nullptr,
-                  /* request_sender = */ nullptr,
-                  /* script_server_url = */ GURL("http://fake"),
-                  /* action_server_url = */ GURL("http://fake"),
-                  /* user_data_url = */ GURL("http://fake"),
-                  /* client_context = */ nullptr) {}
-MockService::~MockService() {}
+MockService::MockService() = default;
+MockService::~MockService() = default;
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/mock_service.h b/components/autofill_assistant/browser/service/mock_service.h
index ff3c97e3..cf6deed 100644
--- a/components/autofill_assistant/browser/service/mock_service.h
+++ b/components/autofill_assistant/browser/service/mock_service.h
@@ -8,69 +8,51 @@
 #include <string>
 #include <vector>
 
-#include "components/autofill_assistant/browser/service/service_impl.h"
+#include "components/autofill_assistant/browser/service/service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
 
-// TODO(crbug.com/806868): inherit from |Service| instead, and properly mock
-// methods as necessary.
-class MockService : public ServiceImpl {
+class MockService : public Service {
  public:
   MockService();
   ~MockService() override;
 
-  void GetScriptsForUrl(
-      const GURL& url,
-      const TriggerContext& trigger_context,
-      ServiceRequestSender::ResponseCallback callback) override {
-    // Transforming callback into a references allows using RunOnceCallback on
-    // the argument.
-    OnGetScriptsForUrl(url, trigger_context, callback);
-  }
-  MOCK_METHOD3(OnGetScriptsForUrl,
-               void(const GURL& url,
-                    const TriggerContext& trigger_context,
-                    ServiceRequestSender::ResponseCallback& callback));
-
-  void GetActions(const std::string& script_path,
-                  const GURL& url,
-                  const TriggerContext& trigger_context,
-                  const std::string& global_payload,
-                  const std::string& script_payload,
-                  ServiceRequestSender::ResponseCallback callback) override {
-    OnGetActions(script_path, url, trigger_context, global_payload,
-                 script_payload, callback);
-  }
-  MOCK_METHOD6(OnGetActions,
-               void(const std::string& script_path,
-                    const GURL& url,
-                    const TriggerContext& trigger_contexts,
-                    const std::string& global_payload,
-                    const std::string& script_payload,
-                    ServiceRequestSender::ResponseCallback& callback));
-
-  void GetNextActions(
-      const TriggerContext& trigger_context,
-      const std::string& previous_global_payload,
-      const std::string& previous_script_payload,
-      const std::vector<ProcessedActionProto>& processed_actions,
-      const RoundtripTimingStats& timing_stats,
-      ServiceRequestSender::ResponseCallback callback) override {
-    OnGetNextActions(trigger_context, previous_global_payload,
-                     previous_script_payload, processed_actions, timing_stats,
-                     callback);
-  }
-  MOCK_METHOD6(OnGetNextActions,
-               void(const TriggerContext& trigger_contexts,
-                    const std::string& previous_global_payload,
-                    const std::string& previous_script_payload,
-                    const std::vector<ProcessedActionProto>& processed_actions,
-                    const RoundtripTimingStats& timing_stats,
-                    ServiceRequestSender::ResponseCallback& callback));
-
-  MOCK_METHOD1(SetScriptStoreConfig,
-               void(const ScriptStoreConfig& script_store_config));
+  MOCK_METHOD(void,
+              GetScriptsForUrl,
+              (const GURL& url,
+               const TriggerContext& trigger_context,
+               ServiceRequestSender::ResponseCallback callback),
+              (override));
+  MOCK_METHOD(void,
+              GetActions,
+              (const std::string& script_path,
+               const GURL& url,
+               const TriggerContext& trigger_context,
+               const std::string& global_payload,
+               const std::string& script_payload,
+               ServiceRequestSender::ResponseCallback callback),
+              (override));
+  MOCK_METHOD(void,
+              GetNextActions,
+              (const TriggerContext& trigger_context,
+               const std::string& previous_global_payload,
+               const std::string& previous_script_payload,
+               const std::vector<ProcessedActionProto>& processed_actions,
+               const RoundtripTimingStats& timing_stats,
+               const RoundtripNetworkStats& network_stats,
+               ServiceRequestSender::ResponseCallback callback),
+              (override));
+  MOCK_METHOD(void,
+              SetScriptStoreConfig,
+              (const ScriptStoreConfig& script_store_config),
+              (override));
+  MOCK_METHOD(void,
+              GetUserData,
+              (const CollectUserDataOptions& options,
+               uint64_t run_id,
+               ServiceRequestSender::ResponseCallback callback),
+              (override));
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/service.h b/components/autofill_assistant/browser/service/service.h
index 00479a17..d2bf64ee 100644
--- a/components/autofill_assistant/browser/service/service.h
+++ b/components/autofill_assistant/browser/service/service.h
@@ -46,6 +46,7 @@
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       const RoundtripTimingStats& timing_stats,
+      const RoundtripNetworkStats& network_stats,
       ServiceRequestSender::ResponseCallback callback) = 0;
 
   virtual void SetScriptStoreConfig(
diff --git a/components/autofill_assistant/browser/service/service_impl.cc b/components/autofill_assistant/browser/service/service_impl.cc
index ad0e93f..323405d 100644
--- a/components/autofill_assistant/browser/service/service_impl.cc
+++ b/components/autofill_assistant/browser/service/service_impl.cc
@@ -131,13 +131,14 @@
     const std::string& previous_script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
     const RoundtripTimingStats& timing_stats,
+    const RoundtripNetworkStats& network_stats,
     ServiceRequestSender::ResponseCallback callback) {
   client_context_->Update(trigger_context);
   request_sender_->SendRequest(
       script_action_server_url_,
       ProtocolUtils::CreateNextScriptActionsRequest(
           previous_global_payload, previous_script_payload, processed_actions,
-          timing_stats, client_context_->AsProto()),
+          timing_stats, network_stats, client_context_->AsProto()),
       GetDefaultAuthMode(), std::move(callback), RpcType::GET_ACTIONS);
 }
 
diff --git a/components/autofill_assistant/browser/service/service_impl.h b/components/autofill_assistant/browser/service/service_impl.h
index e5375144..8eab9725 100644
--- a/components/autofill_assistant/browser/service/service_impl.h
+++ b/components/autofill_assistant/browser/service/service_impl.h
@@ -79,6 +79,7 @@
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       const RoundtripTimingStats& timing_stats,
+      const RoundtripNetworkStats& network_stats,
       ServiceRequestSender::ResponseCallback callback) override;
 
   void SetScriptStoreConfig(
diff --git a/components/autofill_assistant/browser/service/service_impl_unittest.cc b/components/autofill_assistant/browser/service/service_impl_unittest.cc
index df8217da..34288d6b 100644
--- a/components/autofill_assistant/browser/service/service_impl_unittest.cc
+++ b/components/autofill_assistant/browser/service/service_impl_unittest.cc
@@ -153,7 +153,7 @@
   service_->GetNextActions(
       TriggerContext(), std::string("fake_previous_global_payload"),
       std::string("fake_previous_script_payload"), /* processed_actions = */ {},
-      /* timing_stats = */ RoundtripTimingStats(),
+      /* timing_stats = */ RoundtripTimingStats(), RoundtripNetworkStats(),
       mock_response_callback_.Get());
 }
 
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 325ca5e7..7fa244c0 100644
--- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -938,16 +938,16 @@
     *actions_response.add_actions() = wait_for_dom_action;
     std::string serialized_actions_response;
     actions_response.SerializeToString(&serialized_actions_response);
-    EXPECT_CALL(mock_service, OnGetActions)
+    EXPECT_CALL(mock_service, GetActions)
         .WillOnce(RunOnceCallback<5>(200, serialized_actions_response,
                                      ServiceRequestSender::ResponseInfo{}));
 
     std::vector<ProcessedActionProto> captured_processed_actions;
-    EXPECT_CALL(mock_service, OnGetNextActions)
-        .WillOnce(WithArgs<3, 5>(
+    EXPECT_CALL(mock_service, GetNextActions)
+        .WillOnce(WithArgs<3, 6>(
             [&captured_processed_actions](
                 const std::vector<ProcessedActionProto>& processed_actions,
-                ServiceRequestSender::ResponseCallback& callback) {
+                ServiceRequestSender::ResponseCallback callback) {
               captured_processed_actions = processed_actions;
 
               // Send empty response to stop the script executor.
diff --git a/components/autofill_assistant/browser/website_login_manager.h b/components/autofill_assistant/browser/website_login_manager.h
index 771a598f..377bcf0c 100644
--- a/components/autofill_assistant/browser/website_login_manager.h
+++ b/components/autofill_assistant/browser/website_login_manager.h
@@ -85,11 +85,11 @@
       const autofill::FormData& form_data,
       base::OnceCallback<void()> callback) = 0;
 
-  // Checks if generated password can be committed.
-  virtual bool ReadyToCommitGeneratedPassword() = 0;
+  // Checks if generated password can be saved.
+  virtual bool ReadyToSaveGeneratedPassword() = 0;
 
-  // Commits the presaved passwod to the store.
-  virtual void CommitGeneratedPassword() = 0;
+  // Saves the presaved passwod to the store.
+  virtual void SaveGeneratedPassword() = 0;
 
   // Clears potentially submitted or pending forms in password manager. Used to
   // make password manager "forget" about any previously processed form that
@@ -97,9 +97,9 @@
   virtual void ResetPendingCredentials() = 0;
 
   // Returns true if password manager has processed a password update submission
-  // on a 3rd party website and it is ready to commit the updated credential to
+  // on a 3rd party website and it is ready to save the updated credential to
   // the password store.
-  virtual bool ReadyToCommitSubmittedPassword() = 0;
+  virtual bool ReadyToSaveSubmittedPassword() = 0;
 
   // Checks whether there is a password submission on the website and whether
   // the submission corresponds to a password update. In particular, it returns
@@ -108,7 +108,7 @@
   virtual bool SubmittedPasswordIsSame() = 0;
 
   // Saves the current submitted password to the disk. Returns true if a
-  // submitted password exist (E.g ReadyToCommitSubmittedPassword) and it is
+  // submitted password exist (e.g. ReadyToSaveSubmittedPassword) and it is
   // properly saved, false otherwise.
   virtual bool SaveSubmittedPassword() = 0;
 };
diff --git a/components/autofill_assistant/browser/website_login_manager_impl.cc b/components/autofill_assistant/browser/website_login_manager_impl.cc
index 45604f6..7e431cb 100644
--- a/components/autofill_assistant/browser/website_login_manager_impl.cc
+++ b/components/autofill_assistant/browser/website_login_manager_impl.cc
@@ -337,7 +337,7 @@
     form_fetcher_->AddConsumer(this);
   }
 
-  void CommitGeneratedPassword() {
+  void SaveGeneratedPassword() {
     password_save_manager_->Save(&form_data_ /* observed_form */,
                                  password_form_);
   }
@@ -483,14 +483,14 @@
   update_password_request_->FetchAndPresave();
 }
 
-bool WebsiteLoginManagerImpl::ReadyToCommitGeneratedPassword() {
+bool WebsiteLoginManagerImpl::ReadyToSaveGeneratedPassword() {
   return update_password_request_ != nullptr;
 }
 
-void WebsiteLoginManagerImpl::CommitGeneratedPassword() {
+void WebsiteLoginManagerImpl::SaveGeneratedPassword() {
   DCHECK(update_password_request_);
 
-  update_password_request_->CommitGeneratedPassword();
+  update_password_request_->SaveGeneratedPassword();
 
   update_password_request_.reset();
 }
@@ -499,7 +499,7 @@
   client_->GetPasswordManager()->ResetPendingCredentials();
 }
 
-bool WebsiteLoginManagerImpl::ReadyToCommitSubmittedPassword() {
+bool WebsiteLoginManagerImpl::ReadyToSaveSubmittedPassword() {
   return client_->GetPasswordManager()->HasSubmittedManager();
 }
 
@@ -508,7 +508,7 @@
 }
 
 bool WebsiteLoginManagerImpl::SaveSubmittedPassword() {
-  if (!ReadyToCommitSubmittedPassword()) {
+  if (!ReadyToSaveSubmittedPassword()) {
     return false;
   }
   client_->GetPasswordManager()->SaveSubmittedManager();
diff --git a/components/autofill_assistant/browser/website_login_manager_impl.h b/components/autofill_assistant/browser/website_login_manager_impl.h
index e8336e19..a3eecfb 100644
--- a/components/autofill_assistant/browser/website_login_manager_impl.h
+++ b/components/autofill_assistant/browser/website_login_manager_impl.h
@@ -56,13 +56,13 @@
                                 const autofill::FormData& form_data,
                                 base::OnceCallback<void()> callback) override;
 
-  bool ReadyToCommitGeneratedPassword() override;
+  bool ReadyToSaveGeneratedPassword() override;
 
-  void CommitGeneratedPassword() override;
+  void SaveGeneratedPassword() override;
 
   void ResetPendingCredentials() override;
 
-  bool ReadyToCommitSubmittedPassword() override;
+  bool ReadyToSaveSubmittedPassword() override;
 
   bool SubmittedPasswordIsSame() override;
 
diff --git a/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc b/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
index 34eb0d69..532c25c1 100644
--- a/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
+++ b/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
@@ -243,13 +243,13 @@
       {GURL(kFakeUrl), kFakeUsername}, kFakeNewPassword,
       MakeFormDataWithPasswordField(), base::OnceClosure());
 
-  // Commit generated password.
-  EXPECT_TRUE(manager_->ReadyToCommitGeneratedPassword());
+  // Save generated password.
+  EXPECT_TRUE(manager_->ReadyToSaveGeneratedPassword());
   PasswordForm new_form = MakeSimplePasswordForm();
   new_form.password_value = kFakeNewPassword16;
   // Check that additional data is populated correctly from matched form.
   EXPECT_CALL(*store(), UpdateLoginWithPrimaryKey(FormMatches(new_form), _));
-  manager_->CommitGeneratedPassword();
+  manager_->SaveGeneratedPassword();
   WaitForPasswordStore();
 }
 
@@ -361,7 +361,7 @@
   password_manager_->OnInformAboutUserInput(&driver_, updated_data);
   password_manager_->OnPasswordFormSubmitted(&driver_, updated_data);
   EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
-  EXPECT_TRUE(manager_->ReadyToCommitSubmittedPassword());
+  EXPECT_TRUE(manager_->ReadyToSaveSubmittedPassword());
   EXPECT_FALSE(manager_->SubmittedPasswordIsSame());
 
   PasswordForm expected_form(form);
@@ -383,7 +383,7 @@
   password_manager_->OnInformAboutUserInput(&driver_, non_updated_data);
   password_manager_->OnPasswordFormSubmitted(&driver_, non_updated_data);
   EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
-  EXPECT_TRUE(manager_->ReadyToCommitSubmittedPassword());
+  EXPECT_TRUE(manager_->ReadyToSaveSubmittedPassword());
   EXPECT_TRUE(manager_->SubmittedPasswordIsSame());
 
   // The expected form with the same password.
@@ -405,7 +405,7 @@
   password_manager_->OnPasswordFormsRendered(&driver_, {form.form_data}, true);
   password_manager_->OnPasswordFormSubmitted(&driver_, form.form_data);
   EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
-  EXPECT_TRUE(manager_->ReadyToCommitSubmittedPassword());
+  EXPECT_TRUE(manager_->ReadyToSaveSubmittedPassword());
   EXPECT_FALSE(manager_->SubmittedPasswordIsSame());
 
   // Expect the password to get saved.
@@ -419,7 +419,7 @@
                                            {MakeFormDataWithPasswordField()});
   // No user updates to this point.
   EXPECT_FALSE(password_manager_->GetSubmittedManagerForTest());
-  EXPECT_FALSE(manager_->ReadyToCommitSubmittedPassword());
+  EXPECT_FALSE(manager_->ReadyToSaveSubmittedPassword());
   EXPECT_FALSE(manager_->SubmittedPasswordIsSame());
   EXPECT_FALSE(manager_->SaveSubmittedPassword());
 }
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index b0777dd..b4b4b0a 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -1390,6 +1390,23 @@
     UpdateSurfaceBounds();
 }
 
+bool ClientControlledShellSurface::GetCanResizeFromSizeConstraints() const {
+  // Both min and max bounds of unresizable, maximized ARC windows are empty
+  // because Ash requires maximizable apps have empty max bounds.
+  // This assumes that ARC sets non-empty min sizes to all resizable apps.
+  //
+  // Example values of size constraints:
+  // ----------------------------------------------------------------------
+  // |           |          resizable           |      non-resizable      |
+  // ----------------------------------------------------------------------
+  // | freeform  | min: (400, 400), max: (0, 0) | min = max = window size |
+  // ----------------------------------------------------------------------
+  // | maximized | min: (400, 400), max: (0, 0) |   min = max = (0, 0)    |
+  // ----------------------------------------------------------------------
+
+  return minimum_size_ != maximum_size_;
+}
+
 void ClientControlledShellSurface::
     EnsureCompositorIsLockedForOrientationChange() {
   if (!orientation_compositor_lock_) {
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index ce0430d..508df80 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -272,6 +272,8 @@
 
   void UpdateFrameType() override;
 
+  bool GetCanResizeFromSizeConstraints() const override;
+
   void AttemptToStartDrag(int component, const gfx::PointF& location);
 
   // Lock the compositor if it's not already locked, or extends the
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index a4eb5d1..77363ad 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1193,6 +1193,26 @@
   ASSERT_FALSE(window_state->is_dragged());
 }
 
+TEST_F(ClientControlledShellSurfaceTest, ResizabilityAndSizeConstraints) {
+  std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface =
+      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  shell_surface->SetMinimumSize(gfx::Size(0, 0));
+  shell_surface->SetMaximumSize(gfx::Size(0, 0));
+  surface->Commit();
+  EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
+
+  shell_surface->SetMinimumSize(gfx::Size(400, 400));
+  shell_surface->SetMaximumSize(gfx::Size(0, 0));
+  surface->Commit();
+  EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
+
+  shell_surface->SetMinimumSize(gfx::Size(400, 400));
+  shell_surface->SetMaximumSize(gfx::Size(400, 400));
+  surface->Commit();
+  EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
+}
+
 namespace {
 
 // This class is only meant to used by CloseWindowWhenDraggingTest.
diff --git a/components/exo/extended_drag_source.cc b/components/exo/extended_drag_source.cc
index 9681600..c0d9ce4 100644
--- a/components/exo/extended_drag_source.cc
+++ b/components/exo/extended_drag_source.cc
@@ -16,6 +16,7 @@
 #include "base/notreached.h"
 #include "components/exo/data_source.h"
 #include "components/exo/surface.h"
+#include "components/exo/surface_observer.h"
 #include "components/exo/wm_helper.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/aura/client/aura_constants.h"
@@ -49,7 +50,8 @@
 // well as newly created ones (i.e: not added to a root window yet), in which
 // case OnDraggedWindowVisibilityChanged callback is called to notify when it
 // has just got visible.
-class ExtendedDragSource::DraggedWindowHolder : public aura::WindowObserver {
+class ExtendedDragSource::DraggedWindowHolder : public aura::WindowObserver,
+                                                public SurfaceObserver {
  public:
   DraggedWindowHolder(Surface* surface,
                       const gfx::Vector2d& drag_offset,
@@ -57,6 +59,7 @@
       : surface_(surface), drag_offset_(drag_offset), source_(source) {
     DCHECK(surface_);
     DCHECK(surface_->window());
+    surface_->AddSurfaceObserver(this);
     if (!FindToplevelWindow()) {
       DVLOG(1) << "Dragged window not added to root window yet.";
       surface_->window()->AddObserver(this);
@@ -70,9 +73,12 @@
     if (toplevel_window_) {
       toplevel_window_->RemoveObserver(this);
       toplevel_window_ = nullptr;
-    } else {
+    } else if (surface_) {
       surface_->window()->RemoveObserver(this);
     }
+
+    if (surface_)
+      surface_->RemoveSurfaceObserver(this);
   }
 
   aura::Window* toplevel_window() { return toplevel_window_; }
@@ -102,6 +108,22 @@
       source_->OnDraggedWindowVisibilityChanged(visible);
   }
 
+  void OnWindowDestroying(aura::Window* window) override {
+    DCHECK(window);
+    if (window == toplevel_window_) {
+      toplevel_window_->RemoveObserver(this);
+      toplevel_window_ = nullptr;
+    }
+  }
+
+  // SurfaceObserver:
+  void OnSurfaceDestroying(Surface* surface) override {
+    if (surface_ == surface) {
+      surface_->RemoveSurfaceObserver(this);
+      surface_ = nullptr;
+    }
+  }
+
   bool FindToplevelWindow() {
     if (!surface_->window()->GetRootWindow())
       return false;
@@ -114,7 +136,7 @@
     return true;
   }
 
-  Surface* const surface_;
+  Surface* surface_;
   gfx::Vector2d drag_offset_;
   ExtendedDragSource* const source_;
   aura::Window* toplevel_window_ = nullptr;
diff --git a/components/exo/extended_drag_source_unittest.cc b/components/exo/extended_drag_source_unittest.cc
index 459fb5c..c0f2c11 100644
--- a/components/exo/extended_drag_source_unittest.cc
+++ b/components/exo/extended_drag_source_unittest.cc
@@ -532,6 +532,23 @@
   EXPECT_TRUE(surface->window()->GetBoundsInScreen().origin().IsOrigin());
 }
 
+TEST_F(ExtendedDragSourceTest, DragRequestsInRow_NoCrash) {
+  // Create and map a toplevel shell surface, but hidden.
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({32, 32}).BuildShellSurface();
+  auto* surface = shell_surface->root_surface();
+  shell_surface->GetWidget()->Hide();
+
+  // Request two dragging |surface|'s actions in a roll, which a real
+  // world use case scenario when system is under heavy load.
+  extended_drag_source_->Drag(surface, gfx::Vector2d());
+  extended_drag_source_->Drag(surface, gfx::Vector2d());
+
+  // Make sure extended drag source gracefully handles window destruction during
+  // while the drag session is still alive.
+  shell_surface.reset();
+}
+
 TEST_F(ExtendedDragSourceTest, CancelDraggingOperation) {
   // Create and map a toplevel shell surface.
   auto shell_surface =
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 951683e2..4d424fe 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -632,6 +632,12 @@
     observer.OnConfigure(serial);
 }
 
+bool ShellSurface::GetCanResizeFromSizeConstraints() const {
+  // Both the default min and max sizes are empty and windows must be resizable
+  // in that case.
+  return (minimum_size_.IsEmpty() || minimum_size_ != maximum_size_);
+}
+
 void ShellSurface::AttemptToStartDrag(int component) {
   ash::WindowState* window_state =
       ash::WindowState::Get(widget_->GetNativeWindow());
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index ca81f8f..a4533dd 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -174,6 +174,8 @@
   // the behaviour to check for window dragging by setting ends_drag to true.
   void Configure(bool ends_drag = false);
 
+  bool GetCanResizeFromSizeConstraints() const override;
+
   void AttemptToStartDrag(int component);
 
   void EndDrag();
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 8b6d262..3b371320 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -1610,8 +1610,7 @@
 bool ShellSurfaceBase::CalculateCanResize() const {
   if (overlay_widget_ && overlay_can_resize_.has_value())
     return *overlay_can_resize_;
-  return !movement_disabled_ &&
-         (minimum_size_.IsEmpty() || minimum_size_ != maximum_size_);
+  return !movement_disabled_ && GetCanResizeFromSizeConstraints();
 }
 
 void ShellSurfaceBase::CommitWidget() {
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h
index 770847d..aeb3898 100644
--- a/components/exo/shell_surface_base.h
+++ b/components/exo/shell_surface_base.h
@@ -357,9 +357,9 @@
   void SetParentInternal(aura::Window* window);
   void SetContainerInternal(int container);
 
-  // Returns the resizability of the window. Useful to get the resizability
-  // without actually updating it.
-  bool CalculateCanResize() const;
+  // Converts min/max sizes to resizeability. This needs to be overridden as
+  // different clients have different default min/max values.
+  virtual bool GetCanResizeFromSizeConstraints() const = 0;
 
   // Returns true if this surface will exit fullscreen from a restore or
   // maximize request. Currently only true for Lacros.
@@ -385,6 +385,8 @@
   bool server_side_resize_ = false;
   bool needs_layout_on_show_ = false;
   bool client_supports_window_bounds_ = false;
+  gfx::Size minimum_size_;
+  gfx::Size maximum_size_;
 
   // The orientation to be applied when widget is being created. Only set when
   // widget is not created yet orientation lock is being set. This is currently
@@ -417,6 +419,10 @@
 
   void UpdatePinned();
 
+  // Returns the resizability of the window. Useful to get the resizability
+  // without actually updating it.
+  bool CalculateCanResize() const;
+
   aura::Window* parent_ = nullptr;
   bool activatable_ = true;
   bool can_minimize_ = true;
@@ -432,9 +438,7 @@
   base::OnceClosure surface_destroyed_callback_;
   bool system_modal_ = false;
   bool non_system_modal_window_was_active_ = false;
-  gfx::Size minimum_size_;
   gfx::Size pending_minimum_size_;
-  gfx::Size maximum_size_;
   gfx::Size pending_maximum_size_;
   gfx::SizeF pending_aspect_ratio_;
   bool pending_pip_ = false;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 3a169e9a..91cdabf 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -2284,4 +2284,12 @@
   EXPECT_EQ(callbacks.configure_state->bounds, gfx::Rect(10, 10, 300, 300));
 }
 
+TEST_F(ShellSurfaceTest, WindowIsResizableWithEmptySizeConstraints) {
+  auto shell_surface = test::ShellSurfaceBuilder({20, 20})
+                           .SetMinimumSize(gfx::Size(0, 0))
+                           .SetMaximumSize(gfx::Size(0, 0))
+                           .BuildShellSurface();
+  EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
+}
+
 }  // namespace exo
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index 459597d..c92e2c3 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -148,6 +148,8 @@
       WMHelper::GetInstance()->GetDefaultDeviceScaleFactor(),
       default_scale_cancellation);
   shell_surface->SetApplicationId("arc");
+  // ARC's default min size is non-empty.
+  shell_surface->SetMinimumSize(gfx::Size(1, 1));
   shell_surface->set_delegate(
       std::make_unique<ClientControlledShellSurfaceDelegate>(
           shell_surface.get()));
diff --git a/components/exo/test/shell_surface_builder.cc b/components/exo/test/shell_surface_builder.cc
index c5ce34f5..12f37e3a 100644
--- a/components/exo/test/shell_surface_builder.cc
+++ b/components/exo/test/shell_surface_builder.cc
@@ -159,6 +159,13 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetMinimumSize(
+    const gfx::Size& size) {
+  DCHECK(!built_);
+  min_size_ = size;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::SetDisableMovement() {
   DCHECK(!built_);
   disable_movement_ = true;
@@ -216,6 +223,9 @@
   if (!max_size_.IsEmpty())
     shell_surface->SetMaximumSize(max_size_);
 
+  if (!min_size_.IsEmpty())
+    shell_surface->SetMaximumSize(min_size_);
+
   if (popup_)
     shell_surface->SetPopup();
 
diff --git a/components/exo/test/shell_surface_builder.h b/components/exo/test/shell_surface_builder.h
index 10f343c..2eab3e5b 100644
--- a/components/exo/test/shell_surface_builder.h
+++ b/components/exo/test/shell_surface_builder.h
@@ -40,6 +40,7 @@
   ShellSurfaceBuilder& SetNoCommit();
   ShellSurfaceBuilder& SetCanMinimize(bool can_minimize);
   ShellSurfaceBuilder& SetMaximumSize(const gfx::Size& size);
+  ShellSurfaceBuilder& SetMinimumSize(const gfx::Size& size);
   ShellSurfaceBuilder& SetDisableMovement();
   ShellSurfaceBuilder& SetAsPopup();
   ShellSurfaceBuilder& SetCentered();
@@ -58,6 +59,7 @@
       gfx::BufferFormat::RGBA_8888;
   gfx::Point origin_;
   gfx::Size max_size_;
+  gfx::Size min_size_;
   ShellSurface* parent_shell_surface_ = nullptr;
   bool use_system_modal_container_ = false;
   bool commit_on_build_ = true;
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 68b84b9..98b6af7 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -336,6 +336,7 @@
     "//third_party/wayland-protocols:extended_drag",
     "//third_party/wayland-protocols:fullscreen_shell_protocol",
     "//third_party/wayland-protocols:gaming_input_protocol",
+    "//third_party/wayland-protocols:idle_inhibit_protocol",
     "//third_party/wayland-protocols:input_timestamps_protocol",
     "//third_party/wayland-protocols:keyboard_configuration_protocol",
     "//third_party/wayland-protocols:keyboard_extension_protocol",
diff --git a/components/exo/wayland/clients/client_helper.cc b/components/exo/wayland/clients/client_helper.cc
index 54781223..343a9c0 100644
--- a/components/exo/wayland/clients/client_helper.cc
+++ b/components/exo/wayland/clients/client_helper.cc
@@ -110,6 +110,8 @@
 DEFAULT_DELETER(zxdg_toplevel_v6, zxdg_toplevel_v6_destroy)
 DEFAULT_DELETER(zxdg_output_manager_v1, zxdg_output_manager_v1_destroy)
 DEFAULT_DELETER(weston_test, weston_test_destroy)
+DEFAULT_DELETER(zwp_idle_inhibit_manager_v1,
+                zwp_idle_inhibit_manager_v1_destroy)
 
 #if defined(USE_GBM)
 DEFAULT_DELETER(gbm_bo, gbm_bo_destroy)
diff --git a/components/exo/wayland/clients/client_helper.h b/components/exo/wayland/clients/client_helper.h
index d6941c2..96012d4 100644
--- a/components/exo/wayland/clients/client_helper.h
+++ b/components/exo/wayland/clients/client_helper.h
@@ -12,6 +12,7 @@
 #include <extended-drag-unstable-v1-client-protocol.h>
 #include <fullscreen-shell-unstable-v1-client-protocol.h>
 #include <gaming-input-unstable-v2-client-protocol.h>
+#include <idle-inhibit-unstable-v1-client-protocol.h>
 #include <input-timestamps-unstable-v1-client-protocol.h>
 #include <keyboard-configuration-unstable-v1-client-protocol.h>
 #include <keyboard-extension-unstable-v1-client-protocol.h>
@@ -128,6 +129,7 @@
 DEFAULT_DELETER_FDECL(zxdg_toplevel_v6)
 DEFAULT_DELETER_FDECL(zxdg_output_manager_v1)
 DEFAULT_DELETER_FDECL(weston_test)
+DEFAULT_DELETER_FDECL(zwp_idle_inhibit_manager_v1)
 
 #if defined(USE_GBM)
 DEFAULT_DELETER_FDECL(gbm_bo)
diff --git a/components/exo/wayland/clients/test/client_version_test.cc b/components/exo/wayland/clients/test/client_version_test.cc
index fa604058..21db861 100644
--- a/components/exo/wayland/clients/test/client_version_test.cc
+++ b/components/exo/wayland/clients/test/client_version_test.cc
@@ -8,6 +8,7 @@
 #include <cursor-shapes-unstable-v1-server-protocol.h>
 #include <extended-drag-unstable-v1-server-protocol.h>
 #include <gaming-input-unstable-v2-server-protocol.h>
+#include <idle-inhibit-unstable-v1-server-protocol.h>
 #include <keyboard-configuration-unstable-v1-server-protocol.h>
 #include <keyboard-extension-unstable-v1-server-protocol.h>
 #include <notification-shell-unstable-v1-server-protocol.h>
@@ -98,6 +99,7 @@
   std::unique_ptr<zcr_extended_drag_v1> zcr_extended_drag_v1;
   std::unique_ptr<zxdg_output_manager_v1> zxdg_output_manager_v1;
   std::unique_ptr<weston_test> weston_test;
+  std::unique_ptr<zwp_idle_inhibit_manager_v1> zwp_idle_inhibit_manager_v1;
 };
 
 typedef void (*InterfaceRegistryCallback)(Globals*,
@@ -195,6 +197,8 @@
           REGISTRY_CALLBACK(surface_augmenter, surface_augmenter),
           REGISTRY_CALLBACK(overlay_prioritizer, overlay_prioritizer),
           REGISTRY_CALLBACK(weston_test, weston_test),
+          REGISTRY_CALLBACK(zwp_idle_inhibit_manager_v1,
+                            zwp_idle_inhibit_manager_v1),
       };
   if (interfaces_callbacks.find(interface) != interfaces_callbacks.end()) {
     interfaces_callbacks[interface](globals, registry, id, version);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 7193843..fdb703b1 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -1188,10 +1188,17 @@
 
 PageLoadTracker* MetricsWebContentsObserver::GetActivePageLoadTrackerForRequest(
     const content::GlobalRequestID& global_request_id) {
+  // TODO(https://crbug.com/1301880): We will see a invalid request ID on
+  // DidFinishNavigation when we modified fencedframe tag's src attribute by
+  // JavaScript. This should be fixed to record metrics correctly.
+  if (global_request_id == content::GlobalRequestID())
+    return nullptr;
+
   // Runs a liner search here as we expect N is small enough. Let's consider
   // optimizations once this assumtion gets incorrect.
   for (const auto& kv : active_pages_) {
     PageLoadTracker* candidate = kv.second.get();
+    DCHECK(candidate);
     if (candidate->HasMatchingNavigationRequestID(global_request_id))
       return candidate;
   }
diff --git a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index e8af6652..9d03fdf 100644
--- a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -104,18 +104,6 @@
     return;
   }
 
-  if (!url_loader_factory_) {
-    TriggerCallback(std::move(callback), ResultCode::kErrorNoUrlLoader,
-                    PasswordRequirementsSpec());
-    return;
-  }
-
-  if (!url_loader_factory_) {
-    TriggerCallback(std::move(callback), ResultCode::kErrorNoUrlLoader,
-                    PasswordRequirementsSpec());
-    return;
-  }
-
   if (!origin.is_valid() || origin.HostIsIPAddress() ||
       !origin.SchemeIsHTTPOrHTTPS()) {
     VLOG(1) << "No valid origin";
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 0027413..26dbbbf 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -29,12 +29,6 @@
 const base::Feature kEnableFaviconForPasswords{
     "EnableFaviconForPasswords", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables UI that allows the user to create a strong password even if the field
-// wasn't parsed as a new password field.
-// TODO(crbug/1181254): Remove once it's launched.
-const base::Feature kEnableManualPasswordGeneration = {
-    "EnableManualPasswordGeneration", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables the overwriting of prefilled username fields if the server predicted
 // the field to contain a placeholder value.
 const base::Feature kEnableOverwritingPlaceholderUsernames{
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index a8665ae..77b665e 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -24,7 +24,6 @@
 extern const base::Feature kBiometricTouchToFill;
 extern const base::Feature kDetectFormSubmissionOnFormClear;
 extern const base::Feature kEnableFaviconForPasswords;
-extern const base::Feature kEnableManualPasswordGeneration;
 extern const base::Feature kEnableOverwritingPlaceholderUsernames;
 extern const base::Feature kEnablePasswordsAccountStorage;
 extern const base::Feature KEnablePasswordGenerationForClearTextFields;
diff --git a/components/services/screen_ai/BUILD.gn b/components/services/screen_ai/BUILD.gn
index b5fb37e..ef48e78c 100644
--- a/components/services/screen_ai/BUILD.gn
+++ b/components/services/screen_ai/BUILD.gn
@@ -8,8 +8,12 @@
     "screen_ai_service_impl.h",
   ]
 
-  public_deps = [
+  deps = [
     "//base",
+    "//components/services/screen_ai/public/cpp:utilities",
+  ]
+
+  public_deps = [
     "//components/services/screen_ai/public/mojom",
     "//mojo/public/cpp/bindings",
   ]
@@ -23,6 +27,8 @@
 
   deps = [
     "//base",
+    "//components/component_updater",
+    "//components/services/screen_ai/public/cpp:utilities",
     "//sandbox/linux:sandbox_services",
   ]
 
diff --git a/components/services/screen_ai/public/cpp/BUILD.gn b/components/services/screen_ai/public/cpp/BUILD.gn
index fc9084b..7295a13a 100644
--- a/components/services/screen_ai/public/cpp/BUILD.gn
+++ b/components/services/screen_ai/public/cpp/BUILD.gn
@@ -17,3 +17,18 @@
     "//content/public/browser",
   ]
 }
+
+source_set("utilities") {
+  sources = [
+    "pref_names.cc",
+    "pref_names.h",
+    "utilities.cc",
+    "utilities.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/component_updater",
+    "//components/prefs",
+  ]
+}
diff --git a/components/services/screen_ai/public/cpp/DEPS b/components/services/screen_ai/public/cpp/DEPS
index 794f22c..653076fa 100644
--- a/components/services/screen_ai/public/cpp/DEPS
+++ b/components/services/screen_ai/public/cpp/DEPS
@@ -1,5 +1,7 @@
 include_rules = [
   "+content/public/browser",
   "+components/keyed_service/core",
-  "+components/keyed_service/content"
+  "+components/keyed_service/content",
+  "+components/prefs",
+  "+components/component_updater"
 ]
diff --git a/components/services/screen_ai/public/cpp/pref_names.cc b/components/services/screen_ai/public/cpp/pref_names.cc
new file mode 100644
index 0000000..85ed7c8d
--- /dev/null
+++ b/components/services/screen_ai/public/cpp/pref_names.cc
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/services/screen_ai/public/cpp/pref_names.h"
+
+#include "base/files/file_path.h"
+#include "components/prefs/pref_registry_simple.h"
+
+namespace prefs {
+
+const char kScreenAIScheduledDeletionTimePrefName[] =
+    "accessibility.screen_ai.scheduled_deletion_time";
+
+}  // namespace prefs
+
+namespace screen_ai {
+
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterTimePref(prefs::kScreenAIScheduledDeletionTimePrefName,
+                             base::Time());
+}
+
+}  // namespace screen_ai
\ No newline at end of file
diff --git a/components/services/screen_ai/public/cpp/pref_names.h b/components/services/screen_ai/public/cpp/pref_names.h
new file mode 100644
index 0000000..f7c129f
--- /dev/null
+++ b/components/services/screen_ai/public/cpp/pref_names.h
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_PREF_NAMES_H_
+#define COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_PREF_NAMES_H_
+
+class PrefRegistrySimple;
+
+namespace prefs {
+
+// The scheduled time to clean up the ScreenAI library from the device.
+extern const char kScreenAIScheduledDeletionTimePrefName[];
+
+}  // namespace prefs
+
+namespace screen_ai {
+
+// Call once by the browser process to register Screen AI preferences.
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+
+}  // namespace screen_ai
+
+#endif  // COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_PREF_NAMES_H_
diff --git a/components/services/screen_ai/public/cpp/utilities.cc b/components/services/screen_ai/public/cpp/utilities.cc
new file mode 100644
index 0000000..13a3162c
--- /dev/null
+++ b/components/services/screen_ai/public/cpp/utilities.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/services/screen_ai/public/cpp/utilities.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "components/component_updater/component_updater_paths.h"
+
+namespace screen_ai {
+
+namespace {
+const base::FilePath::CharType kScreenAISubDirName[] =
+    FILE_PATH_LITERAL("screen_ai");
+
+const base::FilePath::CharType kScreenAILibraryFileName[] =
+    FILE_PATH_LITERAL("libchrome_screen_ai.so");
+}  // namespace
+
+const base::FilePath GetRelativeInstallDir() {
+  return base::FilePath(kScreenAISubDirName);
+}
+
+const base::FilePath GetLibraryFilePath() {
+  base::FilePath components_dir;
+  base::PathService::Get(component_updater::DIR_COMPONENT_USER,
+                         &components_dir);
+
+  if (components_dir.empty())
+    return base::FilePath();
+
+  // Get latest version.
+  base::FileEnumerator enumerator(components_dir.Append(kScreenAISubDirName),
+                                  /*recursive=*/false,
+                                  base::FileEnumerator::DIRECTORIES);
+  base::FilePath latest_version_dir;
+  for (base::FilePath version_dir = enumerator.Next(); !version_dir.empty();
+       version_dir = enumerator.Next()) {
+    latest_version_dir =
+        latest_version_dir < version_dir ? version_dir : latest_version_dir;
+  }
+
+  base::FilePath library_path =
+      latest_version_dir.Append(kScreenAILibraryFileName);
+  if (!base::PathExists(library_path))
+    return base::FilePath();
+
+  return library_path;
+}
+
+}  // namespace screen_ai
\ No newline at end of file
diff --git a/components/services/screen_ai/public/cpp/utilities.h b/components/services/screen_ai/public/cpp/utilities.h
new file mode 100644
index 0000000..45d8c70
--- /dev/null
+++ b/components/services/screen_ai/public/cpp/utilities.h
@@ -0,0 +1,19 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_UTILITIES_H_
+#define COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_UTILITIES_H_
+
+#include "base/files/file_path.h"
+
+namespace screen_ai {
+
+// Get the absolute path of the ScreenAI library.
+const base::FilePath GetLibraryFilePath();
+
+// Returns the install directory relative to components folder.
+const base::FilePath GetRelativeInstallDir();
+
+}  // namespace screen_ai
+#endif  // COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_UTILITIES_H_
diff --git a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
index 8bd1ee6..330166f 100644
--- a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
+++ b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
@@ -7,6 +7,7 @@
 #include <dlfcn.h>
 
 #include "base/files/file_util.h"
+#include "components/services/screen_ai/public/cpp/utilities.h"
 #include "sandbox/linux/syscall_broker/broker_command.h"
 #include "sandbox/linux/syscall_broker/broker_file_permission.h"
 
@@ -16,19 +17,21 @@
 namespace screen_ai {
 
 bool ScreenAIPreSandboxHook(sandbox::policy::SandboxLinux::Options options) {
-  // TODO(https://crbug.com/1278249): Add a common getter function for the
-  // library file path.
-  const base::FilePath library_path =
-      base::FilePath(FILE_PATH_LITERAL("/"))
-          .Append(FILE_PATH_LITERAL("lib"))
-          .Append(FILE_PATH_LITERAL("libchrome_screen_ai.so"));
-
-  void* screen_ai_library = dlopen(library_path.value().c_str(),
-                                   RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
-  // TODO(https://crbug.com/1278249): Consider handling differently when library
-  // is downloaded using component updater and feature is enabled by default.
-  if (!screen_ai_library)
-    VLOG(1) << dlerror();
+  // TODO(https://crbug.com/1278249): Ensure this is the same version of the
+  // library that is used in ScreenAIService and component updater has not added
+  // a newer version between the two steps.
+  const base::FilePath library_path = screen_ai::GetLibraryFilePath();
+  if (library_path.empty()) {
+    VLOG(1) << "Screen AI library not found.";
+  } else {
+    void* screen_ai_library = dlopen(library_path.value().c_str(),
+                                     RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
+    // The library is delivered by the component updater. If it is not available
+    // we cannot do anything about it here. The requests to the service will
+    // fail later as the library does not exist.
+    if (!screen_ai_library)
+      VLOG(1) << dlerror();
+  }
 
   auto* instance = sandbox::policy::SandboxLinux::GetInstance();
 
diff --git a/components/services/screen_ai/screen_ai_service_impl.cc b/components/services/screen_ai/screen_ai_service_impl.cc
index fc105c1..663fab78 100644
--- a/components/services/screen_ai/screen_ai_service_impl.cc
+++ b/components/services/screen_ai/screen_ai_service_impl.cc
@@ -4,18 +4,13 @@
 
 #include "components/services/screen_ai/screen_ai_service_impl.h"
 
-namespace screen_ai {
+#include "components/services/screen_ai/public/cpp/utilities.h"
 
-// static
-base::FilePath ScreenAIService::GetLibraryPath() {
-  return base::FilePath(FILE_PATH_LITERAL("/"))
-      .Append(FILE_PATH_LITERAL("lib"))
-      .Append(FILE_PATH_LITERAL("libchrome_screen_ai.so"));
-}
+namespace screen_ai {
 
 ScreenAIService::ScreenAIService(
     mojo::PendingReceiver<mojom::ScreenAIService> receiver)
-    : library_(GetLibraryPath()),
+    : library_(screen_ai::GetLibraryFilePath()),
       init_function_(reinterpret_cast<ScreenAIInitFunction>(
           library_.GetFunctionPointer("Init"))),
       annotator_function_(reinterpret_cast<ScreenAIAnnotateFunction>(
diff --git a/components/services/screen_ai/screen_ai_service_impl.h b/components/services/screen_ai/screen_ai_service_impl.h
index 382ff3d..23062f9 100644
--- a/components/services/screen_ai/screen_ai_service_impl.h
+++ b/components/services/screen_ai/screen_ai_service_impl.h
@@ -30,8 +30,6 @@
   ScreenAIService& operator=(const ScreenAIService&) = delete;
   ~ScreenAIService() override;
 
-  static base::FilePath GetLibraryPath();
-
  private:
   base::ScopedNativeLibrary library_;
 
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index 2523c63..fa0e1cb80 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -267,6 +267,8 @@
   SUPPRESSED_CONSECUTIVE_DISMISSALS = 16,
   // The timeout erreur was shown to the user.
   TIMEOUT_ERROR_SHOWN = 17,
+  // The web sign-in is not shown because the user is already signed in.
+  SUPPRESSED_ALREADY_SIGNED_IN = 18,
   MAX = 18,
 };
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index 2d9ccb6..44f1aaf 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -134,10 +134,8 @@
 
 void WebContentsObserverProxy::PrimaryMainDocumentElementAvailable() {
   JNIEnv* env = AttachCurrentThread();
-  // TODO(crbug.com/1288029): Rename DocumentAvailableInMainFrame to
-  // PrimaryMainDocumentElementAvailable in java code.
-  Java_WebContentsObserverProxy_documentAvailableInMainFrame(env,
-                                                             java_observer_);
+  Java_WebContentsObserverProxy_primaryMainDocumentElementAvailable(
+      env, java_observer_);
 }
 
 void WebContentsObserverProxy::DidStartNavigation(
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index 5af979b..a6ae6f0 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -647,7 +647,7 @@
 }
 
 blink::WebMediaDeviceInfoArray MediaDevicesManager::GetCachedDeviceInfo(
-    MediaDeviceType type) {
+    MediaDeviceType type) const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   return current_snapshot_[static_cast<size_t>(type)];
 }
diff --git a/content/browser/renderer_host/media/media_devices_manager.h b/content/browser/renderer_host/media/media_devices_manager.h
index 6f35878..a3f55fd2 100644
--- a/content/browser/renderer_host/media/media_devices_manager.h
+++ b/content/browser/renderer_host/media/media_devices_manager.h
@@ -145,7 +145,8 @@
   // TODO(guidou): Remove this function once content::GetMediaDeviceIDForHMAC
   // is rewritten to receive devices via a callback.
   // See http://crbug.com/648155.
-  blink::WebMediaDeviceInfoArray GetCachedDeviceInfo(MediaDeviceType type);
+  blink::WebMediaDeviceInfoArray GetCachedDeviceInfo(
+      MediaDeviceType type) const;
 
   MediaDevicesPermissionChecker* media_devices_permission_checker();
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
index 3eaa633..0f35632 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
@@ -244,10 +244,10 @@
 
     @Override
     @CalledByNative
-    public void documentAvailableInMainFrame() {
+    public void primaryMainDocumentElementAvailable() {
         handleObserverCall();
         for (mObserversIterator.rewind(); mObserversIterator.hasNext();) {
-            mObserversIterator.next().documentAvailableInMainFrame();
+            mObserversIterator.next().primaryMainDocumentElementAvailable();
         }
         finishObserverCall();
     }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
index 16e1f5da..ea9c6f6 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
@@ -135,7 +135,7 @@
     /**
      * Called once the window.document object of the main frame was created.
      */
-    public void documentAvailableInMainFrame() {}
+    public void primaryMainDocumentElementAvailable() {}
 
     /**
      * Notifies that a load has finished for a given frame.
diff --git a/content/renderer/accessibility/ax_tree_distiller.h b/content/renderer/accessibility/ax_tree_distiller.h
index d5e5184e..7ae4bff4 100644
--- a/content/renderer/accessibility/ax_tree_distiller.h
+++ b/content/renderer/accessibility/ax_tree_distiller.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_RENDERER_ACCESSIBILITY_AX_TREE_DISTILLER_H_
 #define CONTENT_RENDERER_ACCESSIBILITY_AX_TREE_DISTILLER_H_
 
+#include <memory>
 #include <vector>
 
 #include "ui/accessibility/ax_node_id_forward.h"
diff --git a/docs/privacy_budget/privacy_budget_instrumentation.md b/docs/privacy_budget/privacy_budget_instrumentation.md
index af7f28b..70714fd 100644
--- a/docs/privacy_budget/privacy_budget_instrumentation.md
+++ b/docs/privacy_budget/privacy_budget_instrumentation.md
@@ -62,7 +62,7 @@
 
    /* ... */
 
-   if (IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(my_surface)) {
+   if (IdentifiabilityStudySettings::Get()->ShouldSampleSurface(my_surface)) {
      // Only do work here.
    }
    ```
@@ -74,7 +74,7 @@
 
    /* ... */
 
-   if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(my_surface_type)) {
+   if (IdentifiabilityStudySettings::Get()->ShouldSampleType(my_surface_type)) {
      // Only do work here.
    }
    ```
@@ -99,7 +99,7 @@
 
    This includes calculating the `IdentifiableSurface` and any related digests.
    If calculating the `IdentifiableSurface` is expensive, then the code should
-   check `IsTypeAllowed()` before progressing.
+   check `ShouldSampleType()` before progressing.
 
    The primary mechanism for recovering from an unforeseen adverse effect of
    sampling a surface is to stop the collection of that specific sample by way
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
index 0d7d2fe..aa839781 100644
--- a/gin/gin_features.cc
+++ b/gin/gin_features.cc
@@ -19,6 +19,10 @@
 const base::Feature kV8CompactMaps{"V8CompactMaps",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Crashes on evacuation failures in a full GC instead of aborting evacuation.
+const base::Feature kV8CrashOnEvacuationFailure{
+    "V8CrashOnEvacuationFailure", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables a separate heap space for all map objects.
 const base::Feature kV8UseMapSpace{"V8UseMapSpace",
                                    base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/gin/gin_features.h b/gin/gin_features.h
index 9b4ccc33..4191c7fe 100644
--- a/gin/gin_features.h
+++ b/gin/gin_features.h
@@ -17,6 +17,7 @@
 GIN_EXPORT extern const base::Feature kV8ConcurrentSparkplug;
 GIN_EXPORT extern const base::FeatureParam<int>
     kV8ConcurrentSparkplugMaxThreads;
+GIN_EXPORT extern const base::Feature kV8CrashOnEvacuationFailure;
 GIN_EXPORT extern const base::Feature kV8ExperimentalRegexpEngine;
 GIN_EXPORT extern const base::Feature kV8FlushBytecode;
 GIN_EXPORT extern const base::Feature kV8FlushBaselineCode;
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index b123e69bf..6996e07 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -248,6 +248,9 @@
                          "--no-compact-maps");
   SetV8FlagsIfOverridden(features::kV8UseMapSpace, "--use-map-space",
                          "--no-use-map-space");
+  SetV8FlagsIfOverridden(features::kV8CrashOnEvacuationFailure,
+                         "--crash-on-aborted-evacuation",
+                         "--no-crash-on-aborted-evacuation");
   SetV8FlagsIfOverridden(features::kV8OptimizeJavascript, "--opt", "--no-opt");
   SetV8FlagsIfOverridden(features::kV8FlushBytecode, "--flush-bytecode",
                          "--no-flush-bytecode");
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc
index 973b11f..75505cb6 100644
--- a/gpu/config/gpu_finch_features.cc
+++ b/gpu/config/gpu_finch_features.cc
@@ -345,10 +345,6 @@
   if (!IsAImageReaderEnabled() || LimitAImageReaderMaxSizeToOne())
     return false;
 
-  // Not yet compatible with Vulkan.
-  if (IsUsingVulkan())
-    return false;
-
   return base::FeatureList::IsEnabled(kWebViewThreadSafeMedia);
 #else
   return false;
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 3b26657..6e6d6f7 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -594,12 +594,6 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          password_manager::features::kDetectFormSubmissionOnFormClear)},
-    {"enable-manual-password-generation",
-     flag_descriptions::kEnableManualPasswordGenerationName,
-     flag_descriptions::kEnableManualPasswordGenerationDescription,
-     flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(
-         password_manager::features::kEnableManualPasswordGeneration)},
     {"autofill-address-verification-in-save-prompt",
      flag_descriptions::kEnableAutofillAddressSavePromptAddressVerificationName,
      flag_descriptions::
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 7c4d4870..ea4c34d 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -222,12 +222,6 @@
 const char kEnableLongMessageDurationDescription[] =
     "Enables a long duration when an overlay message is shown.";
 
-const char kEnableManualPasswordGenerationName[] =
-    "Enable manual password generation.";
-const char kEnableManualPasswordGenerationDescription[] =
-    "Enable UI that allows to generate a strong password for any password "
-    "field";
-
 const char kEnableNewDownloadAPIName[] = "Enable new download API";
 const char kEnableNewDownloadAPIDescription[] =
     "Enable new download API (restricted to iOS 15.0+).";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index da19ea8..512bd0ce 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -204,12 +204,6 @@
 extern const char kEnableLongMessageDurationName[];
 extern const char kEnableLongMessageDurationDescription[];
 
-// Title and description for the flag to enable UI that allows the user to
-// create a strong password even if the field wasn't parsed as a new password
-// field.
-extern const char kEnableManualPasswordGenerationName[];
-extern const char kEnableManualPasswordGenerationDescription[];
-
 // Title and description for the flag to enable the new download API.
 extern const char kEnableNewDownloadAPIName[];
 extern const char kEnableNewDownloadAPIDescription[];
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
index 5ee282e..d52ab1be 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator.mm
@@ -10,6 +10,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/pref_names.h"
+#import "ios/chrome/browser/signin/authentication_service.h"
+#import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/signin/advanced_settings_signin/advanced_settings_signin_coordinator.h"
@@ -165,15 +167,30 @@
     consistencyPromoSigninCoordinatorWithBaseViewController:
         (UIViewController*)viewController
                                                     browser:(Browser*)browser {
+  ChromeBrowserState* browserState = browser->GetBrowserState();
   ChromeAccountManagerService* accountManagerService =
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          browser->GetBrowserState());
+      ChromeAccountManagerServiceFactory::GetForBrowserState(browserState);
   if (!accountManagerService->HasIdentities()) {
     RecordConsistencyPromoUserAction(
         signin_metrics::AccountConsistencyPromoAction::SUPPRESSED_NO_ACCOUNTS);
     return nil;
   }
-  PrefService* userPrefService = browser->GetBrowserState()->GetPrefs();
+  AuthenticationService* authenticationService =
+      AuthenticationServiceFactory::GetForBrowserState(browserState);
+  if (authenticationService->HasPrimaryIdentity(
+          signin::ConsentLevel::kSignin)) {
+    // For some reasons, Gaia might ask for the web sign-in while the user is
+    // already signed in. It might be a race conditions with a token already
+    // disabled on Gaia, and Chrome not aware of it yet?
+    // To avoid a crash (hitting CHECK() to sign-in while already being signed
+    // in), we need to skip the web sign-in dialog.
+    // Related to crbug.com/1308448.
+    RecordConsistencyPromoUserAction(
+        signin_metrics::AccountConsistencyPromoAction::
+            SUPPRESSED_ALREADY_SIGNED_IN);
+    return nil;
+  }
+  PrefService* userPrefService = browserState->GetPrefs();
   if (!signin::IsSigninAllowed(userPrefService)) {
     RecordConsistencyPromoUserAction(
         signin_metrics::AccountConsistencyPromoAction::
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_utils.mm b/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
index f2c0bfb..a622ae5d 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils.mm
@@ -137,13 +137,19 @@
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
   NSString* version_string =
       [defaults stringForKey:kDisplayedSSORecallForMajorVersionKey];
+  const base::Version version_shown(base::SysNSStringToUTF8(version_string));
 
-  if (version_string) {
-    const base::Version version_shown(base::SysNSStringToUTF8(version_string));
-    if (version_shown.IsValid()) {
-      if (current_version.components()[0] - version_shown.components()[0] < 2)
-        return false;
-    }
+  // If the version was not set, we need to set it in order to wait 2 major
+  // releases to show the sign-in promo.
+  if (!version_shown.IsValid()) {
+    [defaults setObject:base::SysUTF8ToNSString(current_version.GetString())
+                 forKey:kDisplayedSSORecallForMajorVersionKey];
+    return false;
+  }
+
+  // Wait 2 major releases to show the sign-in promo.
+  if (current_version.components()[0] - version_shown.components()[0] < 2) {
+    return false;
   }
 
   // The SSO promo should not be disabled if it is force disabled.
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm b/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
index 046f463..617a55e 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_utils_unittest.mm
@@ -83,12 +83,12 @@
   ChromeAccountManagerService* account_manager_service_;
 };
 
-// Should show the sign-in upgrade for the first time.
+// Should show the sign-in upgrade for the first time, after FRE.
 TEST_F(SigninUtilsTest, TestWillDisplay) {
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentities(@[ @"foo", @"bar" ]);
   const base::Version version_1_0("1.0");
-  EXPECT_TRUE(signin::ShouldPresentUserSigninUpgrade(
+  EXPECT_FALSE(signin::ShouldPresentUserSigninUpgrade(
       chrome_browser_state_.get(), version_1_0));
 }
 
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_constants.h b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_constants.h
index f6e0081..a1d30f68 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_constants.h
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_constants.h
@@ -18,7 +18,8 @@
 };
 
 // Key in the UserDefaults to record the version of the application when the
-// SSO Recall promo has been displayed.
+// sign-in promo has been displayed. The value is set on the first cold start to
+// make sure the sign-in promo is not triggered right after the FRE.
 // Exposed for testing.
 extern NSString* kDisplayedSSORecallForMajorVersionKey;
 // Key in the UserDefaults to record the GAIA id list when the sign-in promo
@@ -27,10 +28,12 @@
 extern NSString* kLastShownAccountGaiaIdVersionKey;
 // Key in the UserDefaults to record the number of time the sign-in promo has
 // been shown.
+// TODO(crbug.com/1312345): Need to merge with kDisplayedSSORecallPromoCountKey.
 // Exposed for testing.
 extern NSString* kSigninPromoViewDisplayCountKey;
 // Key in the UserDefaults to track how many times the SSO Recall promo has been
 // displayed.
+// TODO(crbug.com/1312345): Need to merge with kSigninPromoViewDisplayCountKey.
 // Exposed for testing.
 extern NSString* kDisplayedSSORecallPromoCountKey;
 
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
index b71f30c..9a9a20b 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
@@ -242,9 +242,7 @@
         _webState ? PasswordTabHelper::FromWebState(_webState)
                         ->GetPasswordManagerClient()
                   : nullptr;
-    if (base::FeatureList::IsEnabled(
-            password_manager::features::kEnableManualPasswordGeneration) &&
-        _syncService && _syncService->CanSyncFeatureStart() &&
+    if (_syncService && _syncService->CanSyncFeatureStart() &&
         passwordManagerClient &&
         passwordManagerClient->IsSavingAndFillingEnabled(_URL) &&
         _activeFieldIsPassword) {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
index 090d4d2..1e09189 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -95,15 +95,6 @@
 
 @implementation PasswordViewControllerTestCase
 
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-  if ([self isRunningTest:@selector(testPasswordGenerationOnManualFallback)]) {
-    config.features_enabled.push_back(
-        password_manager::features::kEnableManualPasswordGeneration);
-  }
-  return config;
-}
-
 - (void)setUp {
   [super setUp];
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
diff --git a/ios/chrome/browser/ui/bubble/bubble_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
index c4317a1..4700937 100644
--- a/ios/chrome/browser/ui/bubble/bubble_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
@@ -308,18 +308,23 @@
                    text:(NSString*)text
   voiceOverAnnouncement:(NSString*)voiceOverAnnouncement
             anchorPoint:(CGPoint)anchorPoint {
+  DCHECK(self.browserState);
   BubbleViewControllerPresenter* presenter =
       [self bubblePresenterForFeature:feature
                             direction:direction
                             alignment:alignment
                                  text:text];
-
+  if (!presenter)
+    return nil;
   presenter.voiceOverAnnouncement = voiceOverAnnouncement;
-
-  [presenter presentInViewController:self.rootViewController
-                                view:self.rootViewController.view
-                         anchorPoint:anchorPoint];
-
+  if ([presenter canPresentInView:self.rootViewController.view
+                      anchorPoint:anchorPoint] &&
+      feature_engagement::TrackerFactory::GetForBrowserState(self.browserState)
+          ->ShouldTriggerHelpUI(feature)) {
+    [presenter presentInViewController:self.rootViewController
+                                  view:self.rootViewController.view
+                           anchorPoint:anchorPoint];
+  }
   return presenter;
 }
 
@@ -478,7 +483,7 @@
                      text:(NSString*)text {
   DCHECK(self.browserState);
   if (!feature_engagement::TrackerFactory::GetForBrowserState(self.browserState)
-           ->ShouldTriggerHelpUI(feature)) {
+           ->WouldTriggerHelpUI(feature)) {
     return nil;
   }
   // Capture |weakSelf| instead of the feature engagement tracker object
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h
index 17930bcb..88d12718 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h
+++ b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h
@@ -74,6 +74,10 @@
 
 - (instancetype)init NS_UNAVAILABLE;
 
+// Check if the bubble has enough space to be presented in |parentView| with an
+// anchor point at |anchorPoint|.
+- (BOOL)canPresentInView:(UIView*)parentView anchorPoint:(CGPoint)anchorPoint;
+
 // Presents the bubble in |parentView|. The underlying BubbleViewController is
 // added as a child view controller of |parentViewController|. |anchorPoint|
 // determines where the bubble is anchored in window coordinates.
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
index 4cfe633..5d01cd6b 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.mm
@@ -152,6 +152,13 @@
           dismissalCallback:dismissalCallback];
 }
 
+- (BOOL)canPresentInView:(UIView*)parentView anchorPoint:(CGPoint)anchorPoint {
+  CGPoint anchorPointInParent = [parentView.window convertPoint:anchorPoint
+                                                         toView:parentView];
+  return !CGRectIsEmpty([self frameForBubbleInRect:parentView.bounds
+                                     atAnchorPoint:anchorPointInParent]);
+}
+
 - (void)presentInViewController:(UIViewController*)parentViewController
                            view:(UIView*)parentView
                     anchorPoint:(CGPoint)anchorPoint {
@@ -160,10 +167,9 @@
   self.bubbleViewController.view.frame =
       [self frameForBubbleInRect:parentView.bounds
                    atAnchorPoint:anchorPointInParent];
-  // If the bubble's frame is not set, we abandon this IPH attempt.
-  if (CGRectIsEmpty(self.bubbleViewController.view.frame)) {
-    return;
-  }
+  // The bubble's frame must be set. Call |canPresentInView| to make sure that
+  // the frame can be set before calling |presentInViewController|.
+  DCHECK(!CGRectIsEmpty(self.bubbleViewController.view.frame));
 
   self.presenting = YES;
   [parentViewController addChildViewController:self.bubbleViewController];
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_item.h
index 5397e55b..218e1a5 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_item.h
@@ -18,6 +18,10 @@
 // The accessory type to display on the trailing edge of the cell.
 @property(nonatomic, assign) UITableViewCellAccessoryType accessoryType;
 
+// The accessory view to display on the trailing edge of the cell. Overrides
+// the value of the |accessoryType| property.
+@property(nonatomic, strong) UIView* accessoryView;
+
 // Whether custom separator should be used. The separator can replace the
 // separator provided by UITableViewCell. It is a 0.5pt high line. Default is
 // NO.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm
index 6b38c8e..0c1fb2f 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_item.mm
@@ -28,6 +28,7 @@
   DCHECK([cell class] == self.cellClass);
   DCHECK([cell isKindOfClass:[TableViewCell class]]);
   cell.accessoryType = self.accessoryType;
+  cell.accessoryView = self.accessoryView;
   cell.useCustomSeparator = self.useCustomSeparator;
   cell.accessibilityTraits = self.accessibilityTraits;
   cell.accessibilityIdentifier = self.accessibilityIdentifier;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm b/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm
index f6f5616..6aca771 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_item_unittest.mm
@@ -48,4 +48,20 @@
   EXPECT_FALSE([testColor isEqual:cell.backgroundColor]);
 }
 
+TEST_F(TableViewItemTest, ConfigureCellAccessoryViewProperties) {
+  UIImageView* expectedImage = [[UIImageView alloc]
+      initWithImage:[UIImage systemImageNamed:@"arrow.up.forward.square"]];
+  TableViewItem* item = [[TableViewItem alloc] initWithType:0];
+  item.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+  item.accessoryView = expectedImage;
+
+  TableViewCell* cell = [[[item cellClass] alloc] init];
+  ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
+  [item configureCell:cell withStyler:styler];
+  // Internally in UITableViewCell, accessoryView takes precedence over
+  // accessoryType property.
+  EXPECT_EQ(cell.accessoryType, UITableViewCellAccessoryDisclosureIndicator);
+  EXPECT_EQ(cell.accessoryView, expectedImage);
+}
+
 }  // namespace
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index fadf66e..107a94b 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-09ef611186118dcc05839ae8cea3171005e1adbc
\ No newline at end of file
+0248579fc27260446f959aaae808cee0ed183ce7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 5654f11..acc6902 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b71644195d0c610382a0b772e0572ab00b083919
\ No newline at end of file
+b806495a84d53df4c0e8a84870f87499245536eb
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index bed42d47..ff1c991 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-7f08685a8606893d8200ed37c0117394a683d9f4
\ No newline at end of file
+bcc8e68dbfc7724cae6f71e3ffb7aec60af2c4d8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 1952c96e..0554a1c1 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-21d8aaa5967b8a4f2c631585279c9420985baac9
\ No newline at end of file
+7581b916da323629e64da913f37205a30adb1b23
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index b8c0e95..e71421f 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-00b14326ff2e8aea01a7072a34648387a50ce57b
\ No newline at end of file
+e30143fb33850b16a032e0088dbbaebd3c46710a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 5211db7..7f20975 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7eb732be764d6e59e3cdac2239b3af419695a8a5
\ No newline at end of file
+37bda1796dbb70b1075f08a27f0fc39f80854fd4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 14819f9..00f15fe2 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3b600f9821e5f459f835f5662edadb1b80eb1250
\ No newline at end of file
+b80e5c4b3df91074b2d457d222893856d497bf29
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 3431dc9..970ae3d 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d4fba11b7163267002242b5e3799a945f0f6a6a6
\ No newline at end of file
+c0a01748e2a5bf8600ce856809317f18c8c848da
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 5218db3d..fd0d5fbc 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2752f0138e794abddb30192b3b910718afb4092d
\ No newline at end of file
+1dec1c80f9461380ad979ec74a089e2c48828085
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 6d1daa2..a2de393 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-c72f5e6137570787819676cfb2c365e396ad27d8
\ No newline at end of file
+97fd81d62ae331f9b0e31c1a2c1f6b3e998692ab
\ No newline at end of file
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 9579d48..e07e1c7 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -27,20 +27,23 @@
   if (!cue_data)
     return true;
 
+  bool enable_vp9_ksvc =
 // On windows, currently only d3d11 supports decoding VP9 kSVC stream, we
 // shouldn't combine the switch kD3D11Vp9kSVCHWDecoding to kVp9kSVCHWDecoding
 // due to we want keep returning false to MediaCapability.
 #if BUILDFLAG(IS_WIN)
-  if (!base::FeatureList::IsEnabled(media::kD3D11Vp9kSVCHWDecoding)) {
-    DLOG(ERROR) << "Vp9 k-SVC hardware decoding is disabled";
-    return false;
-  }
+      base::FeatureList::IsEnabled(media::kD3D11Vp9kSVCHWDecoding);
+#elif defined(IS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+      // V4L2 stateless API decoder is not capable of decoding VP9 k-SVC stream.
+      false;
 #else
-  if (!base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding)) {
+      base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding);
+#endif
+
+  if (!enable_vp9_ksvc) {
     DLOG(ERROR) << "Vp9 k-SVC hardware decoding is disabled";
     return false;
   }
-#endif
 
   size_t num_of_layers = decoder_buffer.side_data_size() / sizeof(uint32_t);
   if (num_of_layers > 3u) {
diff --git a/services/device/wake_lock/power_save_blocker/power_save_blocker_lacros.cc b/services/device/wake_lock/power_save_blocker/power_save_blocker_lacros.cc
index 45bce93..d8b5875b 100644
--- a/services/device/wake_lock/power_save_blocker/power_save_blocker_lacros.cc
+++ b/services/device/wake_lock/power_save_blocker/power_save_blocker_lacros.cc
@@ -17,7 +17,7 @@
 /******** PowerSaveBlocker::Delegate ********/
 
 // Lacros-chrome PowerSaveBlocker uses ash-chrome ProwerSaveBlocker via either
-// crosapi (the default) or Wayland (if the idle inhibitor feature is enabled).
+// Wayland (the default) or crosapi (if the idle inhibitor feature is disabled).
 // RAII style is maintained by keeping a crosapi::mojom::PowerWakeLock Mojo
 // connection, whose disconnection triggers resource release in ash-chrome.
 // TODO(b/193670013): Cleanup logic after Wayland idle inhibitor replaces
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 318a1fa..f2c3f87 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5825,7 +5825,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -5833,14 +5833,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
@@ -5967,7 +5967,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -5975,14 +5975,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b513681e..3d31fdd 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -86140,7 +86140,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -86148,14 +86148,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -86257,7 +86257,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -86265,14 +86265,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -87644,21 +87644,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
@@ -87786,21 +87786,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
@@ -89341,21 +89341,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
@@ -89483,21 +89483,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "dimension_sets": [
@@ -90228,21 +90228,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -90324,21 +90324,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4981.0",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4983.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v102.0.4981.0",
-              "revision": "version:102.0.4981.0"
+              "location": "lacros_version_skew_tests_v102.0.4983.0",
+              "revision": "version:102.0.4983.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 197216d..aa47af7 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -28,16 +28,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4981.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4983.0/test_ash_chrome',
       '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
     ],
-    'identifier': 'Lacros version skew testing ash 102.0.4981.0',
+    'identifier': 'Lacros version skew testing ash 102.0.4983.0',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v102.0.4981.0',
-          'revision': 'version:102.0.4981.0',
+          'location': 'lacros_version_skew_tests_v102.0.4983.0',
+          'revision': 'version:102.0.4983.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index edd2d0f4..2419a4f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -657,6 +657,27 @@
             ]
         }
     ],
+    "AutofillComplementCountryCodeOnImport": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillComplementCountryCodeOnImport"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillDelayPopupControllerDeletion": [
         {
             "platforms": [
@@ -918,6 +939,28 @@
             ]
         }
     ],
+    "AutofillIgnoreEarlyClicksOnPopup": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_500ms",
+                    "params": {
+                        "duration": "500ms"
+                    },
+                    "enable_features": [
+                        "AutofillIgnoreEarlyClicksOnPopup"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillKeyboardAccessory": [
         {
             "platforms": [
@@ -6434,13 +6477,14 @@
                         "session_rate": "<3"
                     },
                     "enable_features": [
-                        "IPH_SideSearch",
+                        "SidePanelImprovedClobbering",
                         "SideSearch",
+                        "SideSearchClearCacheWhenClosed",
                         "SideSearchDSESupport"
                     ]
                 },
                 {
-                    "name": "SideSearchDesktopFeedback",
+                    "name": "SideSearchDesktopWithIPH",
                     "params": {
                         "availability": "any",
                         "event_trigger": "name:side_search_iph_tgr;comparator:==0;window:90;storage:360",
@@ -6449,7 +6493,25 @@
                     },
                     "enable_features": [
                         "IPH_SideSearch",
+                        "SidePanelImprovedClobbering",
                         "SideSearch",
+                        "SideSearchClearCacheWhenClosed",
+                        "SideSearchDSESupport"
+                    ]
+                },
+                {
+                    "name": "SideSearchDesktopWithIPHWithFeedback",
+                    "params": {
+                        "availability": "any",
+                        "event_trigger": "name:side_search_iph_tgr;comparator:==0;window:90;storage:360",
+                        "event_used": "name:side_search_opened;comparator:==0;window:90;storage:360",
+                        "session_rate": "<3"
+                    },
+                    "enable_features": [
+                        "IPH_SideSearch",
+                        "SidePanelImprovedClobbering",
+                        "SideSearch",
+                        "SideSearchClearCacheWhenClosed",
                         "SideSearchDSESupport",
                         "SideSearchFeedback"
                     ]
diff --git a/third_party/blink/common/privacy_budget/identifiability_study_settings.cc b/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
index e0d664c..db342d8 100644
--- a/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
+++ b/third_party/blink/common/privacy_budget/identifiability_study_settings.cc
@@ -117,7 +117,13 @@
   return is_enabled_;
 }
 
-bool IdentifiabilityStudySettings::IsSurfaceAllowed(
+bool IdentifiabilityStudySettings::ShouldSampleWebFeature(
+    mojom::WebFeature feature) const {
+  return ShouldSampleSurface(IdentifiableSurface::FromTypeAndToken(
+      IdentifiableSurface::Type::kWebFeature, feature));
+}
+
+bool IdentifiabilityStudySettings::ShouldSampleSurface(
     IdentifiableSurface surface) const {
   if (LIKELY(!is_enabled_))
     return false;
@@ -128,7 +134,7 @@
   return provider_->IsSurfaceAllowed(surface);
 }
 
-bool IdentifiabilityStudySettings::IsTypeAllowed(
+bool IdentifiabilityStudySettings::ShouldSampleType(
     IdentifiableSurface::Type type) const {
   if (LIKELY(!is_enabled_))
     return false;
@@ -139,20 +145,4 @@
   return provider_->IsTypeAllowed(type);
 }
 
-bool IdentifiabilityStudySettings::IsWebFeatureAllowed(
-    mojom::WebFeature feature) const {
-  return IsSurfaceAllowed(IdentifiableSurface::FromTypeAndToken(
-      IdentifiableSurface::Type::kWebFeature, feature));
-}
-
-bool IdentifiabilityStudySettings::ShouldSample(
-    IdentifiableSurface surface) const {
-  return IsSurfaceAllowed(surface);
-}
-
-bool IdentifiabilityStudySettings::ShouldSample(
-    IdentifiableSurface::Type type) const {
-  return IsTypeAllowed(type);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc b/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
index a1066b5..8a59099 100644
--- a/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
+++ b/third_party/blink/common/privacy_budget/identifiability_study_settings_unittest.cc
@@ -23,10 +23,10 @@
 
   EXPECT_FALSE(settings.IsActive());
   EXPECT_EQ(1, counts.count_of_is_active);
-  EXPECT_FALSE(settings.IsSurfaceAllowed(IdentifiableSurface()));
+  EXPECT_FALSE(settings.ShouldSampleSurface(IdentifiableSurface()));
   EXPECT_EQ(1, counts.count_of_is_active);
   EXPECT_FALSE(
-      settings.IsTypeAllowed(IdentifiableSurface::Type::kCanvasReadback));
+      settings.ShouldSampleType(IdentifiableSurface::Type::kCanvasReadback));
 
   // None of these should have been called.
   EXPECT_EQ(0, counts.count_of_is_surface_allowed);
@@ -46,8 +46,9 @@
 
   // No other calls should be made.
   EXPECT_TRUE(settings.IsActive());
-  EXPECT_TRUE(settings.IsSurfaceAllowed(IdentifiableSurface()));
-  EXPECT_TRUE(settings.IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+  EXPECT_TRUE(settings.ShouldSampleSurface(IdentifiableSurface()));
+  EXPECT_TRUE(
+      settings.ShouldSampleType(IdentifiableSurface::Type::kWebFeature));
 
   EXPECT_EQ(1, counts.count_of_is_active);
   EXPECT_EQ(1, counts.count_of_is_any_type_or_surface_blocked);
@@ -65,8 +66,9 @@
 
   // No other calls should be made.
   EXPECT_TRUE(settings.IsActive());
-  EXPECT_FALSE(settings.IsSurfaceAllowed(IdentifiableSurface()));
-  EXPECT_FALSE(settings.IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+  EXPECT_FALSE(settings.ShouldSampleSurface(IdentifiableSurface()));
+  EXPECT_FALSE(
+      settings.ShouldSampleType(IdentifiableSurface::Type::kWebFeature));
 
   EXPECT_EQ(1, counts.count_of_is_active);
   EXPECT_EQ(1, counts.count_of_is_any_type_or_surface_blocked);
@@ -77,9 +79,9 @@
 TEST(IdentifiabilityStudySettingsTest, DefaultSettings) {
   auto* default_settings = IdentifiabilityStudySettings::Get();
   EXPECT_FALSE(default_settings->IsActive());
-  EXPECT_FALSE(default_settings->IsSurfaceAllowed(IdentifiableSurface()));
-  EXPECT_FALSE(
-      default_settings->IsTypeAllowed(IdentifiableSurface::Type::kWebFeature));
+  EXPECT_FALSE(default_settings->ShouldSampleSurface(IdentifiableSurface()));
+  EXPECT_FALSE(default_settings->ShouldSampleType(
+      IdentifiableSurface::Type::kWebFeature));
 }
 
 TEST(IdentifiabilityStudySettingsTest, StaticSetProvider) {
@@ -91,7 +93,7 @@
       std::make_unique<CountingSettingsProvider>(&counts));
   auto* settings = IdentifiabilityStudySettings::Get();
   EXPECT_TRUE(settings->IsActive());
-  EXPECT_TRUE(settings->IsSurfaceAllowed(IdentifiableSurface()));
+  EXPECT_TRUE(settings->ShouldSampleSurface(IdentifiableSurface()));
   EXPECT_EQ(1, counts.count_of_is_surface_allowed);
 
   IdentifiabilityStudySettings::ResetStateForTesting();
diff --git a/third_party/blink/perf_tests/css/CustomPropertiesIdenticalSets.html b/third_party/blink/perf_tests/css/CustomPropertiesIdenticalSets.html
new file mode 100644
index 0000000..7db5496
--- /dev/null
+++ b/third_party/blink/perf_tests/css/CustomPropertiesIdenticalSets.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Comparing identical custom property sets</title>
+<script src="../resources/runner.js"></script>
+<script src="resources/utils.js"></script>
+<main id=main></main>
+<script>
+  const PROP_COUNT = 1000;
+  const TOKEN_COUNT = 3000; // Per custom property.
+  const NODE_COUNT = 20000;
+
+  // Generate declarations with values that have many tokens (i.e. values
+  // that would be expensive to call StyleVariables::operator== on).
+  //
+  // --x0:X X X ... 0
+  // --x1:X X X ... 1
+  // ...
+  let base_value = 'X '.repeat(TOKEN_COUNT / 2);
+  let declaration_array = [];
+  for (let i = 0; i < PROP_COUNT; i++) {
+    let value = base_value + i.toString(); // Make value unique.
+    declaration_array.push(`--x${i}:${value};`);
+  }
+
+  // Generate two rules which produce identical StyleVariables objects.
+  // It's important that they are identical, so that StyleVariables::operator==
+  // has to take the slowest possible path.
+  let declarations = declaration_array.join('\n');
+  applyCSSRule(`#main { ${declarations} }`);
+  applyCSSRule(`#main.change { ${declarations} }`);
+
+  createDOMTree(main, NODE_COUNT, 1 /* siblings */);
+
+  PerfTestRunner.measureTime({
+    description: 'Comparing identical custom property sets',
+    run: function() {
+      forceStyleRecalc(main);
+      main.classList.toggle('change');
+      forceStyleRecalc(main);
+    }
+  });
+</script>
diff --git a/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h b/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
index 503c87d..e172263e 100644
--- a/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
+++ b/third_party/blink/public/common/privacy_budget/identifiability_study_settings.h
@@ -63,41 +63,24 @@
   // true, it doesn't return false at any point after. The converse is not true.
   bool IsActive() const;
 
-  // Returns true if |surface| is allowed.
-  //
-  // Will always return false if IsActive() is false. I.e. If the study is
-  // inactive, all surfaces are considered to be blocked. Hence it is sufficient
-  // to call this function directly instead of calling IsActive() before it.
-  bool IsSurfaceAllowed(IdentifiableSurface surface) const;
-
-  // Returns true if |type| is allowed.
-  //
-  // Will always return false if IsActive() is false. I.e. If the study is
-  // inactive, all surface types are considered to be blocked. Hence it is
-  // sufficient to call this function directly instead of calling IsActive()
-  // before it.
-  bool IsTypeAllowed(IdentifiableSurface::Type type) const;
-
   // Returns true if |surface| should be sampled.
   //
-  // Will always return false if IsActive() is false or if IsSurfaceAllowed() is
-  // false. I.e. If the study is inactive, all surfaces are considered to be
-  // blocked. Hence it is sufficient to call this function directly instead of
-  // calling IsActive() before it.
-  bool ShouldSample(IdentifiableSurface surface) const;
+  // Will always return false if IsActive() is false. If the study is inactive,
+  // all surfaces are considered to be blocked. Hence it is sufficient to call
+  // this function directly instead of calling IsActive() before it.
+  bool ShouldSampleSurface(IdentifiableSurface surface) const;
 
   // Returns true if |type| should be sampled.
   //
-  // Will always return false if IsActive() is false or if IsTypeAllowed() is
-  // false. I.e. If the study is inactive, all surface types are considered to
-  // be blocked. Hence it is sufficient to call this function directly instead
-  // of calling IsActive() before it.
-  bool ShouldSample(IdentifiableSurface::Type type) const;
+  // Will always return false if IsActive() is false. If the study is inactive,
+  // all surface types are considered to be blocked. Hence it is sufficient to
+  // call this function directly instead of calling IsActive() before it.
+  bool ShouldSampleType(IdentifiableSurface::Type type) const;
 
   // Convenience method for determining whether the surface constructable from
-  // the type (|kWebFeature|) and the |feature| is allowed. See IsSurfaceAllowed
-  // for more detail.
-  bool IsWebFeatureAllowed(mojom::WebFeature feature) const;
+  // the type (|kWebFeature|) and the |feature| is allowed. See
+  // ShouldSampleSurface for more detail.
+  bool ShouldSampleWebFeature(mojom::WebFeature feature) const;
 
   // Only used for testing. Resets internal state and violates API contracts
   // made above about the lifetime of IdentifiabilityStudySettings*.
diff --git a/third_party/blink/public/platform/web_resource_request_sender.h b/third_party/blink/public/platform/web_resource_request_sender.h
index 04959db6..00d251f 100644
--- a/third_party/blink/public/platform/web_resource_request_sender.h
+++ b/third_party/blink/public/platform/web_resource_request_sender.h
@@ -103,8 +103,7 @@
       mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
       scoped_refptr<WebRequestPeer> peer,
       std::unique_ptr<ResourceLoadInfoNotifierWrapper>
-          resource_load_info_notifier_wrapper,
-      WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper);
+          resource_load_info_notifier_wrapper);
 
   // Call this method to initiate the request. If this method succeeds, then
   // the peer's methods will be called asynchronously to report various events.
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index f60a4719..852a413 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -401,9 +401,8 @@
   CSSStyleDeclaration* blink_receiver =
       V8CSSStyleDeclaration::ToWrappableUnsafe(v8_receiver);
   v8::Local<v8::Value> v8_property_value = info[0];
-  auto&& arg1_value =
-      NativeValueTraits<IDLStringTreatNullAsEmptyString>::NativeValue(
-          isolate, v8_property_value, exception_state);
+  auto&& arg1_value = NativeValueTraits<IDLAny>::NativeValue(
+      isolate, v8_property_value, exception_state);
   if (UNLIKELY(exception_state.HadException())) {
     return;
   }
diff --git a/third_party/blink/renderer/bindings/scripts/collect_idl_files.py b/third_party/blink/renderer/bindings/scripts/collect_idl_files.py
index cfc0d74..750304dd 100644
--- a/third_party/blink/renderer/bindings/scripts/collect_idl_files.py
+++ b/third_party/blink/renderer/bindings/scripts/collect_idl_files.py
@@ -11,10 +11,12 @@
 
 import optparse
 
-import blink_idl_parser
 import utilities
 import web_idl
 
+from idl_parser import idl_parser
+from idl_parser import idl_lexer
+
 _VALID_COMPONENTS = ('core', 'modules', 'extensions_chromeos')
 
 
@@ -52,12 +54,13 @@
     options, _ = parse_options()
 
     filepaths = utilities.read_idl_files_list_from_file(options.idl_list_file)
-    parser = blink_idl_parser.BlinkIDLParser()
+    lexer = idl_lexer.IDLLexer()
+    parser = idl_parser.IDLParser(lexer)
     ast_group = web_idl.AstGroup(
         component=web_idl.Component(options.component),
         for_testing=bool(options.for_testing))
     for filepath in filepaths:
-        ast_group.add_ast_node(blink_idl_parser.parse_file(parser, filepath))
+        ast_group.add_ast_node(idl_parser.ParseFile(parser, filepath))
     ast_group.write_to_file(options.output)
 
 
diff --git a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
index 8baf0781..ef7a3f1 100644
--- a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
+++ b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
@@ -13,8 +13,6 @@
 ../../../../pyjson5/src/json5/version.py
 ../../build/scripts/blinkbuild/__init__.py
 ../../build/scripts/blinkbuild/name_style_converter.py
-blink_idl_lexer.py
-blink_idl_parser.py
 collect_idl_files.py
 utilities.py
 web_idl/__init__.py
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index b1ab6987..f1540de 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -532,6 +532,8 @@
   "property_registry.h",
   "property_set_css_style_declaration.cc",
   "property_set_css_style_declaration.h",
+  "style_image_cache.cc",
+  "style_image_cache.h",
   "style_request.h",
   "remote_font_face_source.cc",
   "remote_font_face_source.h",
@@ -767,6 +769,7 @@
   "selector_query_test.cc",
   "style_element_test.cc",
   "style_engine_test.cc",
+  "style_image_cache_test.cc",
   "style_recalc_change_test.cc",
   "style_recalc_context_test.cc",
   "style_environment_variables_test.cc",
diff --git a/third_party/blink/renderer/core/css/css_image_value.cc b/third_party/blink/renderer/core/css/css_image_value.cc
index 7bb50209..f66e81b 100644
--- a/third_party/blink/renderer/core/css/css_image_value.cc
+++ b/third_party/blink/renderer/core/css/css_image_value.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/public/common/loader/referrer_utils.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
 #include "third_party/blink/renderer/core/css/css_markup.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -126,10 +127,8 @@
 
     FetchParameters params =
         PrepareFetch(document, image_request_behavior, cross_origin);
-    cached_image_ = MakeGarbageCollected<StyleFetchedImage>(
-        ImageResourceContent::Fetch(params, document.Fetcher()), document,
-        params.GetImageRequestBehavior() == FetchParameters::kDeferImageLoad,
-        origin_clean_ == OriginClean::kTrue, is_ad_related_, params.Url());
+    cached_image_ = document.GetStyleEngine().CacheStyleImage(
+        params, origin_clean_, is_ad_related_);
   }
   return cached_image_.Get();
 }
diff --git a/third_party/blink/renderer/core/css/css_style_declaration.cc b/third_party/blink/renderer/core/css/css_style_declaration.cc
index 40df9093..93c99066 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration.cc
+++ b/third_party/blink/renderer/core/css/css_style_declaration.cc
@@ -32,6 +32,7 @@
 
 #include <algorithm>
 
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
@@ -170,7 +171,7 @@
 NamedPropertySetterResult CSSStyleDeclaration::AnonymousNamedSetter(
     ScriptState* script_state,
     const AtomicString& name,
-    const String& value) {
+    const ScriptValue& value) {
   const ExecutionContext* execution_context =
       ExecutionContext::From(script_state);
   if (!execution_context)
@@ -187,7 +188,15 @@
       "CSSStyleDeclaration",
       CSSProperty::Get(ResolveCSSPropertyID(unresolved_property))
           .GetPropertyName());
-  SetPropertyInternal(unresolved_property, String(), value, false,
+  // Perform a type conversion from ES value to
+  // IDL [LegacyNullToEmptyString] DOMString only after we've confirmed that
+  // the property name is a valid CSS attribute name (see bug 1310062).
+  auto&& string_value =
+      NativeValueTraits<IDLStringTreatNullAsEmptyString>::NativeValue(
+          script_state->GetIsolate(), value.V8Value(), exception_state);
+  if (UNLIKELY(exception_state.HadException()))
+    return NamedPropertySetterResult::kIntercepted;
+  SetPropertyInternal(unresolved_property, String(), string_value, false,
                       execution_context->GetSecureContextMode(),
                       exception_state);
   if (exception_state.HadException())
diff --git a/third_party/blink/renderer/core/css/css_style_declaration.h b/third_party/blink/renderer/core/css/css_style_declaration.h
index 70666e1..c9da48b 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration.h
+++ b/third_party/blink/renderer/core/css/css_style_declaration.h
@@ -101,7 +101,7 @@
   // an argument (see bug 829408).
   NamedPropertySetterResult AnonymousNamedSetter(ScriptState*,
                                                  const AtomicString& name,
-                                                 const String& value);
+                                                 const ScriptValue& value);
   NamedPropertyDeleterResult AnonymousNamedDeleter(const AtomicString& name);
   void NamedPropertyEnumerator(Vector<String>& names, ExceptionState&);
   bool NamedPropertyQuery(const AtomicString&, ExceptionState&);
diff --git a/third_party/blink/renderer/core/css/css_style_declaration.idl b/third_party/blink/renderer/core/css/css_style_declaration.idl
index 7542d52..e158f1f 100644
--- a/third_party/blink/renderer/core/css/css_style_declaration.idl
+++ b/third_party/blink/renderer/core/css/css_style_declaration.idl
@@ -39,6 +39,8 @@
     // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-camel-cased-attribute
     // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed-attribute
     [Affects=Nothing] getter DOMString (DOMString name);
-    [CEReactions, CallWith=ScriptState] setter void (DOMString property, [TreatNullAs=EmptyString] DOMString propertyValue);
+    // The type of `propertyValue` is `any` in order not to perform any type
+    // conversion which may have side effect (c.f. https://crbug.com/1310062 ).
+    [CEReactions, CallWith=ScriptState] setter void (DOMString property, any propertyValue);
     deleter void (DOMString property);
 };
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index 771936b5..e001b939 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -71,7 +71,7 @@
     T value) {
   Document* document = nullptr;
   if ((document = media_values.GetDocument()) &&
-      (IdentifiabilityStudySettings::Get()->ShouldSample(
+      (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kMediaFeature)) &&
       !document->WasMediaFeatureEvaluated(static_cast<int>(feature_name))) {
     IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 23bdbf8b..7c8633f 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -3179,6 +3179,7 @@
   visitor->Trace(vtt_originating_element_);
   visitor->Trace(parent_for_detached_subtree_);
   visitor->Trace(ua_document_transition_style_);
+  visitor->Trace(style_image_cache_);
   FontSelectorClient::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index cb18cdf..2657b43 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -47,6 +47,7 @@
 #include "third_party/blink/renderer/core/css/layout_tree_rebuild_root.h"
 #include "third_party/blink/renderer/core/css/pending_sheet_type.h"
 #include "third_party/blink/renderer/core/css/rule_feature_set.h"
+#include "third_party/blink/renderer/core/css/style_image_cache.h"
 #include "third_party/blink/renderer/core/css/style_invalidation_root.h"
 #include "third_party/blink/renderer/core/css/style_recalc_root.h"
 #include "third_party/blink/renderer/core/css/vision_deficiency.h"
@@ -554,6 +555,13 @@
     return document_transition_tags_;
   }
 
+  StyleFetchedImage* CacheStyleImage(FetchParameters& params,
+                                     OriginClean origin_clean,
+                                     bool is_ad_related) {
+    return style_image_cache_.CacheStyleImage(GetDocument(), params,
+                                              origin_clean, is_ad_related);
+  }
+
   void Trace(Visitor*) const override;
   const char* NameInHeapSnapshot() const override { return "StyleEngine"; }
 
@@ -886,6 +894,7 @@
   friend class StyleEngineTest;
   friend class WhitespaceAttacherTest;
   friend class StyleCascadeTest;
+  friend class StyleImageCacheTest;
 
   HeapHashSet<Member<TextTrack>> text_tracks_;
   Member<Element> vtt_originating_element_;
@@ -899,6 +908,10 @@
   // The set of IDs for which ::page-transition-container pseudo elements are
   // generated during a DocumentTransition.
   Vector<AtomicString> document_transition_tags_;
+
+  // Cache for sharing StyleFetchedImage between CSSValues referencing the same
+  // URL.
+  StyleImageCache style_image_cache_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_image_cache.cc b/third_party/blink/renderer/core/css/style_image_cache.cc
new file mode 100644
index 0000000..cecc830
--- /dev/null
+++ b/third_party/blink/renderer/core/css/style_image_cache.cc
@@ -0,0 +1,32 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/style_image_cache.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
+#include "third_party/blink/renderer/core/style/style_fetched_image.h"
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
+
+namespace blink {
+
+StyleFetchedImage* StyleImageCache::CacheStyleImage(Document& document,
+                                                    FetchParameters& params,
+                                                    OriginClean origin_clean,
+                                                    bool is_ad_related) {
+  auto result = fetched_image_map_.insert(params.Url(), nullptr);
+  if (result.is_new_entry || !result.stored_value->value) {
+    result.stored_value->value = MakeGarbageCollected<StyleFetchedImage>(
+        ImageResourceContent::Fetch(params, document.Fetcher()), document,
+        params.GetImageRequestBehavior() == FetchParameters::kDeferImageLoad,
+        origin_clean == OriginClean::kTrue, is_ad_related, params.Url());
+  }
+  return result.stored_value->value;
+}
+
+void StyleImageCache::Trace(Visitor* visitor) const {
+  visitor->Trace(fetched_image_map_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/style_image_cache.h b/third_party/blink/renderer/core/css/style_image_cache.h
new file mode 100644
index 0000000..935b9034
--- /dev/null
+++ b/third_party/blink/renderer/core/css/style_image_cache.h
@@ -0,0 +1,50 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_IMAGE_CACHE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_IMAGE_CACHE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/css_origin_clean.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class Document;
+class FetchParameters;
+class StyleFetchedImage;
+
+// A per-StyleEngine cache for StyleImages. A CSSImageValue points to a
+// StyleImage, but different CSSImageValue objects with the same URL would not
+// have shared the same StyleImage without this cache.
+class CORE_EXPORT StyleImageCache {
+  DISALLOW_NEW();
+
+ public:
+  StyleImageCache() = default;
+
+  // Look up an existing StyleFetchedImage in the cache, or create a new one,
+  // add it to the cache, and start the fetch.
+  StyleFetchedImage* CacheStyleImage(Document&,
+                                     FetchParameters&,
+                                     OriginClean,
+                                     bool is_ad_related);
+
+  void Trace(Visitor*) const;
+
+ private:
+  // Map from URL to style image. A weak reference makes sure the entry is
+  // removed when no style declarations nor computed styles have a reference to
+  // the image.
+  HeapHashMap<KURL, WeakMember<StyleFetchedImage>> fetched_image_map_;
+
+  friend class StyleImageCacheTest;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_IMAGE_CACHE_H_
diff --git a/third_party/blink/renderer/core/css/style_image_cache_test.cc b/third_party/blink/renderer/core/css/style_image_cache_test.cc
new file mode 100644
index 0000000..ee3bdd9
--- /dev/null
+++ b/third_party/blink/renderer/core/css/style_image_cache_test.cc
@@ -0,0 +1,109 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/style_image_cache.h"
+
+#include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/style/style_fetched_image.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/heap/thread_state.h"
+
+namespace blink {
+
+class StyleImageCacheTest : public PageTestBase {
+ protected:
+  void SetUp() override {
+    PageTestBase::SetUp();
+    GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+  }
+  const HeapHashMap<KURL, WeakMember<StyleFetchedImage>>& FetchedImageMap() {
+    return GetDocument().GetStyleEngine().style_image_cache_.fetched_image_map_;
+  }
+};
+
+TEST_F(StyleImageCacheTest, DuplicateBackgroundImageURLs) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      .rule1 { background-image: url(url.png) }
+      .rule2 { background-image: url(url.png) }
+    </style>
+    <div id="target"></div>
+  )HTML");
+
+  Element* target = GetDocument().getElementById("target");
+  ASSERT_TRUE(target);
+  ASSERT_FALSE(target->ComputedStyleRef().BackgroundLayers().GetImage());
+
+  target->setAttribute(blink::html_names::kClassAttr, "rule1");
+  UpdateAllLifecyclePhasesForTest();
+
+  StyleImage* rule1_image =
+      target->ComputedStyleRef().BackgroundLayers().GetImage();
+  EXPECT_TRUE(rule1_image);
+
+  target->setAttribute(blink::html_names::kClassAttr, "rule2");
+  UpdateAllLifecyclePhasesForTest();
+
+  StyleImage* rule2_image =
+      target->ComputedStyleRef().BackgroundLayers().GetImage();
+  EXPECT_EQ(rule1_image, rule2_image);
+}
+
+TEST_F(StyleImageCacheTest, CustomPropertyURL) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      :root { --bg: url(url.png) }
+      #target { background-image: var(--bg) }
+      .green { background-color: green }
+    </style>
+    <div id="target"></div>
+  )HTML");
+
+  Element* target = GetDocument().getElementById("target");
+
+  StyleImage* initial_image =
+      target->ComputedStyleRef().BackgroundLayers().GetImage();
+  EXPECT_TRUE(initial_image);
+
+  target->setAttribute(blink::html_names::kClassAttr, "green");
+  UpdateAllLifecyclePhasesForTest();
+
+  StyleImage* image_after_recalc =
+      target->ComputedStyleRef().BackgroundLayers().GetImage();
+  EXPECT_EQ(initial_image, image_after_recalc);
+}
+
+TEST_F(StyleImageCacheTest, WeakReferenceGC) {
+  SetBodyInnerHTML(R"HTML(
+    <style id="sheet">
+      #target1 { background-image: url(url.png) }
+      #target2 { background-image: url(url2.png) }
+    </style>
+    <div id="target1"></div>
+    <div id="target2"></div>
+  )HTML");
+  UpdateAllLifecyclePhasesForTest();
+
+  EXPECT_TRUE(FetchedImageMap().Contains(KURL("http://test.com/url.png")));
+  EXPECT_TRUE(FetchedImageMap().Contains(KURL("http://test.com/url2.png")));
+  EXPECT_EQ(FetchedImageMap().size(), 2u);
+
+  Element* sheet = GetDocument().getElementById("sheet");
+  ASSERT_TRUE(sheet);
+  sheet->remove();
+  UpdateAllLifecyclePhasesForTest();
+  ThreadState::Current()->CollectAllGarbageForTesting();
+
+  // After the sheet has been removed, the lifecycle update and garbage
+  // collection have been run, the weak references in the cache should have been
+  // collected.
+  EXPECT_FALSE(FetchedImageMap().Contains(KURL("http://test.com/url.png")));
+  EXPECT_FALSE(FetchedImageMap().Contains(KURL("http://test.com/url2.png")));
+  EXPECT_EQ(FetchedImageMap().size(), 0u);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 247f1d5..8550af2e 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1317,7 +1317,7 @@
 void Element::RecordScrollbarSizeForStudy(int measurement,
                                           bool is_width,
                                           bool is_offset) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kScrollbarSize) ||
       (!is_offset && !IsViewportScrollElement()))
     return;
diff --git a/third_party/blink/renderer/core/frame/dactyloscoper.cc b/third_party/blink/renderer/core/frame/dactyloscoper.cc
index 8e88fda..2342470c 100644
--- a/third_party/blink/renderer/core/frame/dactyloscoper.cc
+++ b/third_party/blink/renderer/core/frame/dactyloscoper.cc
@@ -26,7 +26,7 @@
 namespace {
 
 bool ShouldSample(WebFeature feature) {
-  return IdentifiabilityStudySettings::Get()->ShouldSample(
+  return IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
       IdentifiableSurface::FromTypeAndToken(
           IdentifiableSurface::Type::kWebFeature, feature));
 }
diff --git a/third_party/blink/renderer/core/frame/navigator_ua_data.cc b/third_party/blink/renderer/core/frame/navigator_ua_data.cc
index a8dc23b..7192ff0 100644
--- a/third_party/blink/renderer/core/frame/navigator_ua_data.cc
+++ b/third_party/blink/renderer/core/frame/navigator_ua_data.cc
@@ -124,7 +124,7 @@
   ExecutionContext* context = GetExecutionContext();
   if (context) {
     // Record IdentifiabilityStudy metrics if the client is in the study.
-    if (UNLIKELY(IdentifiabilityStudySettings::Get()->ShouldSample(
+    if (UNLIKELY(IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
             identifiable_surface))) {
       IdentifiableTokenBuilder token_builder;
       for (const auto& brand : brand_set_) {
@@ -163,7 +163,7 @@
   DCHECK(execution_context);
 
   bool record_identifiability =
-      IdentifiabilityStudySettings::Get()->ShouldSample(
+      IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kNavigatorUAData_GetHighEntropyValues);
   UADataValues* values = MakeGarbageCollected<UADataValues>();
   // According to
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index ed4fb44..8f8d65c6b 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -472,7 +472,7 @@
                                 base::TimeTicks::Now() - start_time_,
                                 image_->width(), image_->height());
 
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kCanvasReadback)) {
     // Creating this ImageDataBuffer has some overhead, namely getting the
     // SkImage and computing the pixmap. We need the StaticBitmapImage to be
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index e5b86b1e..6e63785 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -376,7 +376,7 @@
     auto* execution_context = ExecutionContext::From(script_state);
     auto* async_creator = MakeGarbageCollected<CanvasAsyncBlobCreator>(
         image_bitmap, options, function_type, start_time, execution_context,
-        IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+        IdentifiabilityStudySettings::Get()->ShouldSampleType(
             IdentifiableSurface::Type::kCanvasReadback)
             ? IdentifiabilityInputDigest(context)
             : 0,
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 36326b20..9406334 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -314,7 +314,7 @@
 
 void HTMLCanvasElement::IdentifiabilityReportWithDigest(
     IdentifiableToken canvas_contents_token) const {
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kCanvasReadback)) {
     RecordIdentifiabilityMetric(
         blink::IdentifiableSurface::FromTypeAndToken(
@@ -331,7 +331,7 @@
   auto* result = GetCanvasRenderingContextInternal(type, attributes);
 
   Document& doc = GetDocument();
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kCanvasRenderingContext)) {
     IdentifiabilityMetricBuilder(doc.UkmSourceID())
         .Add(IdentifiableSurface::FromTypeAndToken(
@@ -1099,7 +1099,7 @@
         image_bitmap, options,
         CanvasAsyncBlobCreator::kHTMLCanvasToBlobCallback, callback, start_time,
         GetExecutionContext(),
-        IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+        IdentifiabilityStudySettings::Get()->ShouldSampleType(
             IdentifiableSurface::Type::kCanvasReadback)
             ? IdentifiabilityInputDigest(context_)
             : 0);
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 780e7c4..0cb890ac 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
@@ -922,7 +922,7 @@
   MIMETypeRegistry::SupportsType support =
       GetSupportsType(ContentType(mime_type));
 
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kHTMLMediaElement_CanPlayType)) {
     blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Add(
diff --git a/third_party/blink/renderer/core/layout/grid.cc b/third_party/blink/renderer/core/layout/grid.cc
index 479af828..e02f922 100644
--- a/third_party/blink/renderer/core/layout/grid.cc
+++ b/third_party/blink/renderer/core/layout/grid.cc
@@ -139,7 +139,7 @@
 
 ListGrid::GridCell* ListGrid::GridTrack::Find(wtf_size_t index) const {
   auto orthogonal_axis = OrthogonalDirection(direction_);
-  for (auto* cell = cells_.Head(); cell;
+  for (GridCell* cell = cells_->Head(); cell;
        cell = cell->NextInDirection(direction_)) {
     wtf_size_t cell_index = cell->Index(orthogonal_axis);
     if (cell_index == index)
@@ -154,11 +154,11 @@
   return first < second ? -1 : (first != second);
 }
 
-DoublyLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
+GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
     GridCell* cell) {
   cell->SetTraversalMode(direction_);
 
-  return cells_.Insert(
+  return cells_->Insert(
       cell, [this](ListGrid::GridCell* first, ListGrid::GridCell* second) {
         // This is ugly but we need to do this in order the
         // DoublyLinkedList::Insert() algorithm to work at that code
@@ -171,7 +171,7 @@
       });
 }
 
-DoublyLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
+GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
     LayoutBox& item,
     const GridSpan& span) {
   auto compare_cells = [this](ListGrid::GridCell* first,
@@ -186,9 +186,9 @@
   wtf_size_t col_index = direction_ == kForColumns ? Index() : span.StartLine();
   wtf_size_t row_index = direction_ == kForColumns ? span.StartLine() : Index();
 
-  auto result = cells_.Insert(
-      base::WrapUnique(new GridCell(row_index, col_index)), compare_cells);
-  auto* cell = result.node;
+  auto result = cells_->Insert(
+      MakeGarbageCollected<GridCell>(row_index, col_index), compare_cells);
+  GridCell* cell = result.node;
   for (auto index : span) {
     cell->AppendItem(item);
 
@@ -203,21 +203,21 @@
           direction_ == kForColumns ? Index() : index + 1;
       wtf_size_t next_row_index =
           direction_ == kForColumns ? index + 1 : Index();
-      auto next_cell =
-          base::WrapUnique(new GridCell(next_row_index, next_col_index));
-      if (InsertAfter(next_cell.get(), cell).is_new_entry)
-        next_cell.release();
+      GridCell* next_cell =
+          MakeGarbageCollected<GridCell>(next_row_index, next_col_index);
+      InsertAfter(next_cell, cell);
     }
     cell = cell->Next();
   }
   return result;
 }
 
-DoublyLinkedList<ListGrid::GridCell>::AddResult
-ListGrid::GridTrack::InsertAfter(GridCell* cell, GridCell* insertion_point) {
+GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::InsertAfter(
+    GridCell* cell,
+    GridCell* insertion_point) {
   insertion_point->SetTraversalMode(direction_);
   cell->SetTraversalMode(direction_);
-  if (auto* next = insertion_point->Next()) {
+  if (GridCell* next = insertion_point->Next()) {
     if (next == cell)
       return {cell, false};
     // We need to set the traversal mode for the next cell as we're
@@ -225,25 +225,7 @@
     // and prev_ pointers.
     next->SetTraversalMode(direction_);
   }
-  return cells_.InsertAfter(cell, insertion_point);
-}
-
-ListGrid::GridTrack::~GridTrack() {
-  // We destroy cells just when disposing columns as we don't want to
-  // double free them.
-  // TODO(svillar): we need to eventually get rid of this different
-  // destructors depending on the axis.
-  if (direction_ == kForRows) {
-    cells_.Clear();
-    return;
-  }
-
-  while (!cells_.IsEmpty()) {
-    cells_.Head()->SetTraversalMode(kForColumns);
-    if (cells_.Head()->Next())
-      cells_.Head()->Next()->SetTraversalMode(kForColumns);
-    delete cells_.RemoveHead();
-  }
+  return cells_->InsertAfter(cell, insertion_point);
 }
 
 const GridItemList& ListGrid::Cell(wtf_size_t row_index,
@@ -251,7 +233,7 @@
   DEFINE_STATIC_LOCAL(const GridItemList, empty_vector, ());
   for (auto* row = rows_.Head(); row; row = row->Next()) {
     if (row->Index() == row_index) {
-      auto* cell = row->Find(column_index);
+      GridCell* cell = row->Find(column_index);
       return cell ? cell->Items() : empty_vector;
     }
     if (row->Index() > row_index)
@@ -353,13 +335,17 @@
   if (direction == direction_)
     return;
   direction_ = direction;
-  std::swap(next_, next_ortho_);
-  std::swap(prev_, prev_ortho_);
+  GridCell* next = Next();
+  SetNext(next_ortho_);
+  next_ortho_ = next;
+  GridCell* prev = Prev();
+  SetPrev(prev_ortho_);
+  prev_ortho_ = prev;
 }
 
 ListGrid::GridCell* ListGrid::GridCell::NextInDirection(
     GridTrackSizingDirection direction) const {
-  return direction_ == direction ? next_ : next_ortho_;
+  return direction_ == direction ? Next() : next_ortho_.Get();
 }
 
 std::unique_ptr<Grid::GridIterator> ListGrid::CreateIterator(
diff --git a/third_party/blink/renderer/core/layout/grid.h b/third_party/blink/renderer/core/layout/grid.h
index 65da4e0d..3a9cb0c 100644
--- a/third_party/blink/renderer/core/layout/grid.h
+++ b/third_party/blink/renderer/core/layout/grid.h
@@ -7,9 +7,11 @@
 
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/grid_linked_list.h"
 #include "third_party/blink/renderer/core/layout/order_iterator.h"
 #include "third_party/blink/renderer/core/style/grid_area.h"
 #include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h"
 #include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
@@ -29,7 +31,6 @@
   }
 };
 
-// TODO(svillar): Perhaps we should use references here.
 typedef Vector<UntracedMember<LayoutBox>, 1> GridItemList;
 typedef LinkedHashSet<wtf_size_t, OrderedTrackIndexSetHashTraits>
     OrderedTrackIndexSet;
@@ -175,10 +176,7 @@
   // only created for those cells which do have items inside. Each
   // GridCell will be part of two different DLL, one representing the
   // column and another one representing the row.
-  class GridCell final : public DoublyLinkedListNode<GridCell> {
-    USING_FAST_MALLOC(GridCell);
-    friend class WTF::DoublyLinkedListNode<GridCell>;
-
+  class GridCell final : public GridLinkedListNodeBase<GridCell> {
    public:
     GridCell(wtf_size_t row, wtf_size_t column) : row_(row), column_(column) {}
 
@@ -190,6 +188,12 @@
 
     const GridItemList& Items() const { return items_; }
 
+    void Trace(Visitor* visitor) const final {
+      visitor->Trace(prev_ortho_);
+      visitor->Trace(next_ortho_);
+      GridLinkedListNodeBase<GridCell>::Trace(visitor);
+    }
+
     // DoublyLinkedListNode classes must provide a next_ and prev_
     // pointers to the DoublyLinkedList class so that it could perform
     // the list operations. In the case of GridCells we need them to
@@ -213,10 +217,8 @@
     GridCell* NextInDirection(GridTrackSizingDirection) const;
 
    private:
-    GridCell* prev_{nullptr};
-    GridCell* next_{nullptr};
-    GridCell* prev_ortho_{nullptr};
-    GridCell* next_ortho_{nullptr};
+    Member<GridCell> prev_ortho_;
+    Member<GridCell> next_ortho_;
 
     GridTrackSizingDirection direction_{kForColumns};
     GridItemList items_;
@@ -239,22 +241,21 @@
 
    public:
     GridTrack(wtf_size_t index, GridTrackSizingDirection direction)
-        : index_(index), direction_(direction) {}
+        : cells_(MakeGarbageCollected<GridLinkedList<GridCell>>()),
+          index_(index),
+          direction_(direction) {}
 
     wtf_size_t Index() const { return index_; }
-    DoublyLinkedList<GridCell>::AddResult Insert(GridCell*);
-    DoublyLinkedList<GridCell>::AddResult InsertAfter(
-        GridCell* cell,
-        GridCell* insertion_point);
-    DoublyLinkedList<GridCell>::AddResult Insert(LayoutBox&, const GridSpan&);
+    GridLinkedList<GridCell>::AddResult Insert(GridCell*);
+    GridLinkedList<GridCell>::AddResult InsertAfter(GridCell* cell,
+                                                    GridCell* insertion_point);
+    GridLinkedList<GridCell>::AddResult Insert(LayoutBox&, const GridSpan&);
     GridCell* Find(wtf_size_t cell_index) const;
 
-    const DoublyLinkedList<GridCell>& Cells() const { return cells_; }
-
-    ~GridTrack();
+    const GridLinkedList<GridCell>& Cells() const { return *cells_; }
 
    private:
-    DoublyLinkedList<GridCell> cells_;
+    Persistent<GridLinkedList<GridCell>> cells_;
     wtf_size_t index_;
     GridTrackSizingDirection direction_;
 
@@ -308,7 +309,7 @@
 
  private:
   const ListGrid& grid_;
-  ListGrid::GridCell* cell_node_{nullptr};
+  Persistent<ListGrid::GridCell> cell_node_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid_linked_list.h b/third_party/blink/renderer/core/layout/grid_linked_list.h
index d3be481..ca72023 100644
--- a/third_party/blink/renderer/core/layout/grid_linked_list.h
+++ b/third_party/blink/renderer/core/layout/grid_linked_list.h
@@ -54,6 +54,9 @@
 
 namespace blink {
 
+template <typename NodeType>
+class GridLinkedList;
+
 // A class defining the type of node in the GridLinkedList should inherit
 // GridLinkedListNodeBase. This will give previous and next pointer for the
 // node, as well as apply garbage collection to all nodes.
@@ -62,17 +65,21 @@
     : public GarbageCollected<GridLinkedListNodeBase<NodeType>> {
  public:
   GridLinkedListNodeBase() = default;
+  virtual ~GridLinkedListNodeBase() = default;
 
   NodeType* Prev() const { return prev_; }
   NodeType* Next() const { return next_; }
-  void SetPrev(NodeType* prev) { prev_ = prev; }
-  void SetNext(NodeType* next) { next_ = next; }
 
-  void Trace(Visitor* visitor) const {
+  virtual void Trace(Visitor* visitor) const {
     visitor->Trace(prev_);
     visitor->Trace(next_);
   }
 
+ protected:
+  friend class GridLinkedList<NodeType>;
+  void SetPrev(NodeType* prev) { prev_ = prev; }
+  void SetNext(NodeType* next) { next_ = next; }
+
  private:
   Member<NodeType> prev_;
   Member<NodeType> next_;
diff --git a/third_party/blink/renderer/core/layout/grid_linked_list_test.cc b/third_party/blink/renderer/core/layout/grid_linked_list_test.cc
index b3aad4e..1563470 100644
--- a/third_party/blink/renderer/core/layout/grid_linked_list_test.cc
+++ b/third_party/blink/renderer/core/layout/grid_linked_list_test.cc
@@ -20,7 +20,9 @@
 class IntNode : public GridLinkedListNodeBase<IntNode> {
  public:
   explicit IntNode(int value) : value_(value) {}
-  ~IntNode() { destructor_calls.fetch_add(1, std::memory_order_relaxed); }
+  ~IntNode() override {
+    destructor_calls.fetch_add(1, std::memory_order_relaxed);
+  }
 
   int Value() const { return value_; }
 
diff --git a/third_party/blink/renderer/core/layout/grid_test.cc b/third_party/blink/renderer/core/layout/grid_test.cc
index cbc0a34e..a88a4c2 100644
--- a/third_party/blink/renderer/core/layout/grid_test.cc
+++ b/third_party/blink/renderer/core/layout/grid_test.cc
@@ -340,13 +340,13 @@
     return;
 
   auto track = base::WrapUnique(new ListGrid::GridTrack(0, kForColumns));
-  auto* cell = new ListGrid::GridCell(0, 0);
+  ListGrid::GridCell* cell = MakeGarbageCollected<ListGrid::GridCell>(0, 0);
 
   auto result = track->Insert(cell);
   EXPECT_TRUE(result.is_new_entry);
   EXPECT_EQ(cell, result.node);
 
-  auto* cell2 = new ListGrid::GridCell(1, 0);
+  ListGrid::GridCell* cell2 = MakeGarbageCollected<ListGrid::GridCell>(1, 0);
   result = track->Insert(cell2);
   EXPECT_TRUE(result.is_new_entry);
   EXPECT_EQ(cell2, result.node);
@@ -355,7 +355,7 @@
   EXPECT_FALSE(result.is_new_entry);
   EXPECT_EQ(cell2, result.node);
 
-  auto* cell3 = new ListGrid::GridCell(2, 0);
+  ListGrid::GridCell* cell3 = MakeGarbageCollected<ListGrid::GridCell>(2, 0);
   result = track->InsertAfter(cell3, cell2);
   EXPECT_TRUE(result.is_new_entry);
   EXPECT_EQ(cell3, result.node);
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 907fd4e..69f6da1 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -235,7 +235,7 @@
 void OffscreenCanvas::RecordIdentifiabilityMetric(
     const blink::IdentifiableSurface& surface,
     const IdentifiableToken& token) const {
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface))
     return;
   blink::IdentifiabilityMetricBuilder(GetExecutionContext()->UkmSourceID())
       .Add(surface, token)
diff --git a/third_party/blink/renderer/core/script/pending_script.cc b/third_party/blink/renderer/core/script/pending_script.cc
index a3fa931..3dcfec2 100644
--- a/third_party/blink/renderer/core/script/pending_script.cc
+++ b/third_party/blink/renderer/core/script/pending_script.cc
@@ -161,11 +161,13 @@
 
   std::unique_ptr<scheduler::TaskAttributionTracker::TaskScope>
       task_attribution_scope;
-  DCHECK(ThreadScheduler::Current());
-  ScriptState* script_state = ToScriptStateForMainWorld(frame);
-  if (auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker()) {
-    task_attribution_scope =
-        tracker->CreateTaskScope(script_state, absl::nullopt);
+  if (ScriptState* script_state = ToScriptStateForMainWorld(frame)) {
+    DCHECK(ThreadScheduler::Current());
+    if (auto* tracker =
+            ThreadScheduler::Current()->GetTaskAttributionTracker()) {
+      task_attribution_scope =
+          tracker->CreateTaskScope(script_state, absl::nullopt);
+    }
   }
 
   Script* script = GetSource(document_url);
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.h b/third_party/blink/renderer/core/style/style_fetched_image.h
index 6016fc5..98a59d1 100644
--- a/third_party/blink/renderer/core/style/style_fetched_image.h
+++ b/third_party/blink/renderer/core/style/style_fetched_image.h
@@ -38,8 +38,8 @@
 
 // This class represents an <image> that loads a single image resource (the
 // url(...) function.)
-class StyleFetchedImage final : public StyleImage,
-                                public ImageResourceObserver {
+class CORE_EXPORT StyleFetchedImage final : public StyleImage,
+                                            public ImageResourceObserver {
   USING_PRE_FINALIZER(StyleFetchedImage, Prefinalize);
 
  public:
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h b/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
index 9379d73..4b92cb03 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h
@@ -180,7 +180,7 @@
   void AddTokens() {}
 
   const bool is_canvas_type_allowed_ =
-      IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kCanvasReadback);
 
   Member<ExecutionContext> execution_context_;
diff --git a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index 6f3dce44..e1764c71 100644
--- a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -84,7 +84,7 @@
 void RecordGamepadsForIdentifiabilityStudy(
     ExecutionContext* context,
     HeapVector<Member<Gamepad>> gamepads) {
-  if (!context || !IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (!context || !IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
                       IdentifiableSurface::FromTypeAndToken(
                           IdentifiableSurface::Type::kWebFeature,
                           WebFeature::kGetGamepads)))
diff --git a/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc b/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
index c41ab40a..b5ea2ab 100644
--- a/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
+++ b/third_party/blink/renderer/modules/keyboard/keyboard_layout.cc
@@ -83,7 +83,7 @@
   }
 
   if (!EnsureServiceConnected()) {
-    if (IdentifiabilityStudySettings::Get()->ShouldSample(
+    if (IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
             kGetKeyboardLayoutMapSurface)) {
       RecordGetLayoutMapResult(ExecutionContext::From(script_state),
                                IdentifiableToken());
@@ -132,8 +132,9 @@
 
   ScriptState::Scope script_state_scope(script_state);
 
-  bool instrumentation_on = IdentifiabilityStudySettings::Get()->ShouldSample(
-      kGetKeyboardLayoutMapSurface);
+  bool instrumentation_on =
+      IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
+          kGetKeyboardLayoutMapSurface);
 
   switch (result->status) {
     case mojom::blink::GetKeyboardLayoutMapStatus::kSuccess:
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
index c886f63..99a3314 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_identifiability_metrics.cc
@@ -26,12 +26,12 @@
 namespace {
 
 bool IsDecodingInfoTypeAllowed() {
-  return IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  return IdentifiabilityStudySettings::Get()->ShouldSampleType(
       IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
 }
 
 bool ShouldSampleDecodingInfoType() {
-  return IdentifiabilityStudySettings::Get()->ShouldSample(
+  return IdentifiabilityStudySettings::Get()->ShouldSampleType(
       IdentifiableSurface::Type::kMediaCapabilities_DecodingInfo);
 }
 
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
index bccac9966..0b112a8 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -360,7 +360,7 @@
   ContentType content_type(type);
   bool result = handler->CanSupportMimeType(content_type.GetType(),
                                             content_type.Parameter("codecs"));
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kMediaRecorder_IsTypeSupported)) {
     blink::IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Add(blink::IdentifiableSurface::FromTypeAndToken(
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index 384cc5f..af8f48c 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -683,7 +683,7 @@
 void MediaSource::RecordIdentifiabilityMetric(ExecutionContext* context,
                                               const String& type,
                                               bool result) {
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kMediaSource_IsTypeSupported)) {
     return;
   }
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
index 7bd2894..d82ababc 100644
--- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
@@ -30,8 +30,7 @@
     std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source) {
   MediaStreamSource* const source = MakeGarbageCollected<MediaStreamSource>(
       "id", MediaStreamSource::StreamType::kTypeVideo, "name",
-      /*remote=*/false);
-  source->SetPlatformSource(std::move(media_stream_video_source));
+      /*remote=*/false, std::move(media_stream_video_source));
 
   MediaStreamComponent* const component =
       MakeGarbageCollected<MediaStreamComponent>(source);
diff --git a/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc b/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
index c06668aa..f6b60682 100644
--- a/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
+++ b/third_party/blink/renderer/modules/mediastream/identifiability_metrics.cc
@@ -273,7 +273,7 @@
                                  ExecutionContext* context,
                                  IdentifiableToken token) {
   if (surface.IsValid() && context &&
-      IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
+      IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface)) {
     IdentifiabilityMetricBuilder(context->UkmSourceID())
         .Add(surface, token)
         .Record(context->UkmRecorder());
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 37fda2c..d2775c93 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -242,7 +242,7 @@
   constexpr IdentifiableSurface::Type surface_type =
       IdentifiableSurface::Type::kMediaDevices_GetUserMedia;
   IdentifiableSurface surface;
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(surface_type)) {
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(surface_type)) {
     surface = IdentifiableSurface::FromTypeAndToken(
         surface_type, TokenFromConstraints(options));
   }
@@ -564,7 +564,7 @@
 
 void RecordEnumeratedDevices(ScriptPromiseResolver* resolver,
                              const MediaDeviceInfoVector& media_devices) {
-  if (!IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleWebFeature(
           WebFeature::kIdentifiabilityMediaDevicesEnumerateDevices)) {
     return;
   }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
index b8f2aac..e9261f24 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
@@ -113,17 +113,18 @@
     auto delegate = std::make_unique<MockVideoCapturerSource>();
     delegate_ = delegate.get();
     EXPECT_CALL(*delegate_, GetPreferredFormats());
-    video_capturer_source_ = new MediaStreamVideoCapturerSource(
-        /*LocalFrame =*/nullptr,
-        WTF::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
-                  WTF::Unretained(this)),
-        std::move(delegate));
+    auto video_capturer_source =
+        std::make_unique<MediaStreamVideoCapturerSource>(
+            /*LocalFrame =*/nullptr,
+            WTF::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
+                      WTF::Unretained(this)),
+            std::move(delegate));
+    video_capturer_source_ = video_capturer_source.get();
     video_capturer_source_->SetMediaStreamDispatcherHostForTesting(
         mock_dispatcher_host_.CreatePendingRemoteAndBind());
     stream_source_ = MakeGarbageCollected<MediaStreamSource>(
         "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
-        false /* remote */);
-    stream_source_->SetPlatformSource(base::WrapUnique(video_capturer_source_));
+        false /* remote */, std::move(video_capturer_source));
     stream_source_id_ = stream_source_->Id();
 
     MediaStreamVideoCapturerSource::DeviceCapturerFactoryCallback callback =
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
index da332d10..30db7b31 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_renderer_sink_test.cc
@@ -34,12 +34,13 @@
 
 class MediaStreamVideoRendererSinkTest : public testing::Test {
  public:
-  MediaStreamVideoRendererSinkTest()
-      : mock_source_(new MockMediaStreamVideoSource()) {
+  MediaStreamVideoRendererSinkTest() {
+    auto mock_source = std::make_unique<MockMediaStreamVideoSource>();
+    mock_source_ = mock_source.get();
     media_stream_source_ = MakeGarbageCollected<MediaStreamSource>(
         String::FromUTF8("dummy_source_id"), MediaStreamSource::kTypeVideo,
-        String::FromUTF8("dummy_source_name"), false /* remote */);
-    media_stream_source_->SetPlatformSource(base::WrapUnique(mock_source_));
+        String::FromUTF8("dummy_source_name"), false /* remote */,
+        std::move(mock_source));
     WebMediaStreamTrack web_track = MediaStreamVideoTrack::CreateVideoTrack(
         mock_source_, WebPlatformMediaStreamSource::ConstraintsOnceCallback(),
         true);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
index 75dc8411..610e38c 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
@@ -49,8 +49,7 @@
     mock_stream_video_source_->DisableStopForRestart();
     stream_source_ = MakeGarbageCollected<MediaStreamSource>(
         String::FromUTF8("dummy_source_id"), MediaStreamSource::kTypeVideo,
-        String::FromUTF8("dummy_source_name"), false /* remote */);
-    stream_source_->SetPlatformSource(
+        String::FromUTF8("dummy_source_name"), false /* remote */,
         base::WrapUnique(mock_stream_video_source_));
     ON_CALL(*mock_stream_video_source_, SetCanDiscardAlpha)
         .WillByDefault(Return());
diff --git a/third_party/blink/renderer/modules/mediastream/navigator_media_stream.cc b/third_party/blink/renderer/modules/mediastream/navigator_media_stream.cc
index 9edebfb..0b3e7354 100644
--- a/third_party/blink/renderer/modules/mediastream/navigator_media_stream.cc
+++ b/third_party/blink/renderer/modules/mediastream/navigator_media_stream.cc
@@ -65,7 +65,7 @@
   IdentifiableSurface surface;
   constexpr IdentifiableSurface::Type surface_type =
       IdentifiableSurface::Type::kNavigator_GetUserMedia;
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(surface_type)) {
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(surface_type)) {
     surface = IdentifiableSurface::FromTypeAndToken(
         surface_type, TokenFromConstraints(options));
   }
diff --git a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
index 43a9d2e8..bbabafc 100644
--- a/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/processed_local_audio_source_test.cc
@@ -87,15 +87,6 @@
 
   ~ProcessedLocalAudioSourceTest() override = default;
 
-  void SetUp() override {
-    SimTest::SetUp();
-    audio_source_ = MakeGarbageCollected<MediaStreamSource>(
-        String::FromUTF8("audio_label"), MediaStreamSource::kTypeAudio,
-        String::FromUTF8("audio_track"), false /* remote */);
-    audio_component_ = MakeGarbageCollected<MediaStreamComponent>(
-        audio_source_->Id(), audio_source_);
-  }
-
   void TearDown() override {
     SimTest::TearDown();
     audio_source_ = nullptr;
@@ -117,7 +108,11 @@
             base::DoNothing(),
             scheduler::GetSingleThreadTaskRunnerForTesting());
     source->SetAllowInvalidRenderFrameIdForTesting(true);
-    audio_source_->SetPlatformSource(std::move(source));
+    audio_source_ = MakeGarbageCollected<MediaStreamSource>(
+        String::FromUTF8("audio_label"), MediaStreamSource::kTypeAudio,
+        String::FromUTF8("audio_track"), false /* remote */, std::move(source));
+    audio_component_ = MakeGarbageCollected<MediaStreamComponent>(
+        audio_source_->Id(), audio_source_);
   }
 
   void CheckSourceFormatMatches(const media::AudioParameters& params) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client.cc b/third_party/blink/renderer/modules/mediastream/user_media_client.cc
index fffd64d..70fda40c 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_client.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_client.cc
@@ -27,7 +27,7 @@
 namespace blink {
 namespace {
 
-static int g_next_request_id = 0;
+static int32_t g_next_request_id = 0;
 
 // The histogram counts the number of calls to the JS APIs
 // getUserMedia() and getDisplayMedia().
@@ -140,7 +140,7 @@
   // Save histogram data so we can see how much GetUserMedia is used.
   UpdateAPICount(user_media_request->MediaRequestType());
 
-  int request_id = g_next_request_id++;
+  int32_t request_id = g_next_request_id++;
   blink::WebRtcLogMessage(base::StringPrintf(
       "UMCI::RequestUserMedia({request_id=%d}, {audio constraints=%s}, "
       "{video constraints=%s})",
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 7fd169b..7af9c61 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -339,7 +339,7 @@
                             const String& result_name);
 
   UserMediaRequest* request() { return request_; }
-  int request_id() const { return request_->request_id(); }
+  int32_t request_id() const { return request_->request_id(); }
 
   State state() const { return state_; }
   void set_state(State state) { state_ = state; }
@@ -969,7 +969,7 @@
 }
 
 void UserMediaProcessor::OnStreamGenerated(
-    int request_id,
+    int32_t request_id,
     MediaStreamRequestResult result,
     const String& label,
     const Vector<MediaStreamDevice>& audio_devices,
@@ -1144,7 +1144,7 @@
 }
 
 void UserMediaProcessor::OnStreamGenerationFailed(
-    int request_id,
+    int32_t request_id,
     MediaStreamRequestResult result) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!IsCurrentRequestInfo(request_id)) {
@@ -1571,7 +1571,7 @@
     const String& constraint_name) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   SendLogMessage(base::StringPrintf(
-      "UMP::OnCreateNativeTracksCompleted({request_id = %d}, {label=%s})",
+      "UMP::OnCreateNativeTracksCompleted({request_id=%d}, {label=%s})",
       request_info->request_id(), label.Utf8().c_str()));
   if (result == MediaStreamRequestResult::OK) {
     GetUserMediaRequestSucceeded(request_info->descriptor(),
@@ -1620,7 +1620,7 @@
 }
 
 void UserMediaProcessor::DelayedGetUserMediaRequestSucceeded(
-    int request_id,
+    int32_t request_id,
     MediaStreamDescriptor* component,
     UserMediaRequest* user_media_request) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -1655,7 +1655,7 @@
 }
 
 void UserMediaProcessor::DelayedGetUserMediaRequestFailed(
-    int request_id,
+    int32_t request_id,
     UserMediaRequest* user_media_request,
     MediaStreamRequestResult result,
     const String& constraint_name) {
@@ -1818,7 +1818,7 @@
   return false;
 }
 
-bool UserMediaProcessor::IsCurrentRequestInfo(int request_id) const {
+bool UserMediaProcessor::IsCurrentRequestInfo(int32_t request_id) const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return current_request_info_ &&
          current_request_info_->request_id() == request_id;
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.h b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
index 76bd427..8a08a77 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
@@ -147,7 +147,7 @@
   class RequestInfo;
   using LocalStreamSources = HeapVector<Member<MediaStreamSource>>;
 
-  void OnStreamGenerated(int request_id,
+  void OnStreamGenerated(int32_t request_id,
                          blink::mojom::blink::MediaStreamRequestResult result,
                          const String& label,
                          const Vector<blink::MediaStreamDevice>& audio_devices,
@@ -163,17 +163,17 @@
   gfx::Size GetScreenSize();
 
   void OnStreamGenerationFailed(
-      int request_id,
+      int32_t request_id,
       blink::mojom::blink::MediaStreamRequestResult result);
 
-  bool IsCurrentRequestInfo(int request_id) const;
+  bool IsCurrentRequestInfo(int32_t request_id) const;
   bool IsCurrentRequestInfo(UserMediaRequest* user_media_request) const;
   void DelayedGetUserMediaRequestSucceeded(
-      int request_id,
+      int32_t request_id,
       MediaStreamDescriptor* descriptor,
       UserMediaRequest* user_media_request);
   void DelayedGetUserMediaRequestFailed(
-      int request_id,
+      int32_t request_id,
       UserMediaRequest* user_media_request,
       blink::mojom::blink::MediaStreamRequestResult result,
       const String& constraint_name);
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.h b/third_party/blink/renderer/modules/mediastream/user_media_request.h
index 5f00b1b57..379d1706 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -141,8 +141,8 @@
   // ExecutionContextLifecycleObserver
   void ContextDestroyed() override;
 
-  void set_request_id(int id) { request_id_ = id; }
-  int request_id() { return request_id_; }
+  void set_request_id(int32_t id) { request_id_ = id; }
+  int32_t request_id() { return request_id_; }
 
   void set_has_transient_user_activation(bool value) {
     has_transient_user_activation_ = value;
@@ -162,7 +162,7 @@
   const bool should_prefer_current_tab_ = false;
   bool should_disable_hardware_noise_suppression_;
   bool has_transient_user_activation_ = false;
-  int request_id_ = -1;
+  int32_t request_id_ = -1;
 
   Member<UserMediaController> controller_;
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index 3ccacb2a..6db8e8f3 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -213,8 +213,11 @@
   configuration->combined_audio_video_bwe = ConstraintToOptional(
       constraints,
       &MediaTrackConstraintSetPlatform::goog_combined_audio_video_bwe);
+#if BUILDFLAG(IS_FUCHSIA)
+  // TODO(crbug.com/804275): Delete when Fuchsia no longer depends on it.
   configuration->enable_dtls_srtp = ConstraintToOptional(
       constraints, &MediaTrackConstraintSetPlatform::enable_dtls_srtp);
+#endif
 }
 
 // Class mapping responses from calls to libjingle CreateOffer/Answer and
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
index 208e08c..4ab13c2 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc
@@ -372,7 +372,7 @@
   }
   capabilities->setHeaderExtensions(header_extensions);
 
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kRtcRtpReceiverGetCapabilities)) {
     IdentifiableTokenBuilder builder;
     IdentifiabilityAddRTCRtpCapabilitiesToBuilder(builder, *capabilities);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
index a262c1d6..2d49b549b 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -822,7 +822,7 @@
   }
   capabilities->setHeaderExtensions(header_extensions);
 
-  if (IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kRtcRtpSenderGetCapabilities)) {
     IdentifiableTokenBuilder builder;
     IdentifiabilityAddRTCRtpCapabilitiesToBuilder(builder, *capabilities);
diff --git a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
index a9d9ce3..22e5f26 100644
--- a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
+++ b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
@@ -83,7 +83,7 @@
 namespace {
 
 void RecordPlugins(LocalDOMWindow* window, DOMPluginArray* plugins) {
-  if (!IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleWebFeature(
           WebFeature::kNavigatorPlugins) ||
       !window) {
     return;
@@ -110,7 +110,8 @@
 void RecordMimeTypes(LocalDOMWindow* window, DOMMimeTypeArray* mime_types) {
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorMimeTypes);
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface) || !window) {
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface) ||
+      !window) {
     return;
   }
   IdentifiableTokenBuilder builder;
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
index dff21a1..3e6d1cd 100644
--- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
+++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.cc
@@ -285,7 +285,7 @@
   if (!pending_callback_ || request_id != request_id_)
     return;
 
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
           IdentifiableSurface::FromTypeAndToken(
               IdentifiableSurface::Type::kWebFeature,
               WebFeature::kScreenOrientationLock))) {
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc b/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
index 8f62dc5..31dac78 100644
--- a/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
+++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector_statics.cc
@@ -88,7 +88,7 @@
   results.ReserveInitialCapacity(results.size());
   for (const auto& format : formats)
     results.push_back(BarcodeDetector::BarcodeFormatToString(format));
-  if (IdentifiabilityStudySettings::Get()->IsWebFeatureAllowed(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleWebFeature(
           WebFeature::kBarcodeDetector_GetSupportedFormats)) {
     IdentifiableTokenBuilder builder;
     for (const auto& format_string : results)
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index abd14ce..7b797040 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -107,7 +107,7 @@
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature,
       WebFeature::kSpeechSynthesis_GetVoices_Method);
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(surface))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface))
     return;
   if (!GetSupplementable()->GetFrame())
     return;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index a44f62f..8d2f6fc 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -609,7 +609,7 @@
     GLenum internalformat,
     GLint* values,
     GLint length) {
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kWebGLInternalFormatParameter))
     return;
   const auto& ukm_params = GetUkmParameters();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 1e315ceb..b78f578c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -801,7 +801,7 @@
 
     make_xr_compatible_resolver_ = nullptr;
 
-    if (IdentifiabilityStudySettings::Get()->ShouldSample(
+    if (IdentifiabilityStudySettings::Get()->ShouldSampleSurface(
             IdentifiableSurface::FromTypeAndToken(
                 IdentifiableSurface::Type::kWebFeature,
                 WebFeature::kWebGLRenderingContextMakeXRCompatible))) {
@@ -3378,7 +3378,7 @@
 };
 
 bool ShouldMeasureGLParam(GLenum pname) {
-  return IdentifiabilityStudySettings::Get()->ShouldSample(
+  return IdentifiabilityStudySettings::Get()->ShouldSampleType(
              blink::IdentifiableSurface::Type::kWebGLParameter) &&
          std::find(std::begin(kIdentifiableGLParams),
                    std::end(kIdentifiableGLParams),
@@ -3390,7 +3390,7 @@
 void WebGLRenderingContextBase::RecordIdentifiableGLParameterDigest(
     GLenum pname,
     IdentifiableToken value) {
-  DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  DCHECK(IdentifiabilityStudySettings::Get()->ShouldSampleType(
       blink::IdentifiableSurface::Type::kWebGLParameter));
   const auto ukm_params = GetUkmParameters();
   blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
@@ -3404,7 +3404,7 @@
     GLenum shader_type,
     GLenum precision_type,
     WebGLShaderPrecisionFormat* format) {
-  DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  DCHECK(IdentifiabilityStudySettings::Get()->ShouldSampleType(
       blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat));
 
   const auto& ukm_params = GetUkmParameters();
@@ -3570,7 +3570,7 @@
     case GL_SCISSOR_TEST:
       return GetBooleanParameter(script_state, pname);
     case GL_SHADING_LANGUAGE_VERSION:
-      if (IdentifiabilityStudySettings::Get()->ShouldSample(
+      if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
               blink::IdentifiableSurface::Type::kWebGLParameter)) {
         RecordIdentifiableGLParameterDigest(
             pname, IdentifiabilityBenignStringToken(String(
@@ -3638,7 +3638,7 @@
     case GL_VENDOR:
       return WebGLAny(script_state, String("WebKit"));
     case GL_VERSION:
-      if (IdentifiabilityStudySettings::Get()->ShouldSample(
+      if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
               blink::IdentifiableSurface::Type::kWebGLParameter)) {
         RecordIdentifiableGLParameterDigest(
             pname, IdentifiabilityBenignStringToken(
@@ -3659,7 +3659,7 @@
       return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
-        if (IdentifiabilityStudySettings::Get()->ShouldSample(
+        if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
           RecordIdentifiableGLParameterDigest(
               pname, IdentifiabilityBenignStringToken(
@@ -3674,7 +3674,7 @@
       return ScriptValue::CreateNull(script_state->GetIsolate());
     case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
-        if (IdentifiabilityStudySettings::Get()->ShouldSample(
+        if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
           RecordIdentifiableGLParameterDigest(
               pname, IdentifiabilityBenignStringToken(
@@ -3859,7 +3859,7 @@
     case GL_RENDERBUFFER_DEPTH_SIZE:
     case GL_RENDERBUFFER_STENCIL_SIZE:
       ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
-      if (IdentifiabilityStudySettings::Get()->ShouldSample(
+      if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
               blink::IdentifiableSurface::Type::kWebGLParameter)) {
         RecordIdentifiableGLParameterDigest(pname, value);
       }
@@ -3944,7 +3944,7 @@
                                         &precision);
   auto* result = MakeGarbageCollected<WebGLShaderPrecisionFormat>(
       range[0], range[1], precision);
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat)) {
     RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
   }
@@ -7486,7 +7486,7 @@
   GLfloat value = 0;
   if (!isContextLost())
     ContextGL()->GetFloatv(pname, &value);
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kWebGLParameter)) {
     RecordIdentifiableGLParameterDigest(pname, value);
   }
@@ -7512,7 +7512,7 @@
         break;
     }
   }
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleType(
           blink::IdentifiableSurface::Type::kWebGLParameter)) {
     RecordIdentifiableGLParameterDigest(pname, value);
   }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index 96070f6f..faa292a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -194,7 +194,7 @@
     GPUAdapter* adapter) const {
   constexpr IdentifiableSurface::Type type =
       IdentifiableSurface::Type::kGPU_RequestAdapter;
-  if (!IdentifiabilityStudySettings::Get()->ShouldSample(type))
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(type))
     return;
   ExecutionContext* context = GetExecutionContext();
   if (!context)
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access.cc b/third_party/blink/renderer/modules/webmidi/midi_access.cc
index b63711c7..8d40d183 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access.cc
+++ b/third_party/blink/renderer/modules/webmidi/midi_access.cc
@@ -88,7 +88,7 @@
   constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
       IdentifiableSurface::Type::kWebFeature,
       WebFeature::kRequestMIDIAccess_ObscuredByFootprinting);
-  if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) {
+  if (IdentifiabilityStudySettings::Get()->ShouldSampleSurface(surface)) {
     IdentifiableTokenBuilder builder;
     for (const auto& port : ports) {
       builder.AddToken(IdentifiabilityBenignStringToken(port.id));
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
index 7315cb7..bd4ddd9 100644
--- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -104,7 +104,7 @@
 void FontMatchingMetrics::ReportLocalFontExistenceByUniqueNameOnly(
     const AtomicString& font_name,
     bool font_exists) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontExistenceByUniqueNameOnly)) {
     return;
   }
@@ -126,7 +126,7 @@
   // type and kLocalFontLoadPostScriptName are allowed. (If the former is not,
   // InsertFontHashIntoMap would not be called.)
   if (!font_data ||
-      !IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      !IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontLoadPostScriptName)) {
     return;
   }
@@ -147,7 +147,7 @@
     const AtomicString& name,
     const FontDescription& font_description,
     SimpleFontData* resulting_font_data) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontLookupByUniqueOrFamilyName)) {
     return;
   }
@@ -172,7 +172,7 @@
   // We ignore lookups that result in loading fallbacks for now as they should
   // only be temporary.
   if (is_loading_fallback ||
-      !IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+      !IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontLookupByUniqueNameOnly)) {
     return;
   }
@@ -194,7 +194,7 @@
     FontFallbackPriority fallback_priority,
     const FontDescription& font_description,
     SimpleFontData* resulting_font_data) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontLookupByFallbackCharacter)) {
     return;
   }
@@ -213,7 +213,7 @@
 void FontMatchingMetrics::ReportLastResortFallbackFontLookup(
     const FontDescription& font_description,
     SimpleFontData* resulting_font_data) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kLocalFontLookupAsLastResort)) {
     return;
   }
@@ -232,7 +232,7 @@
     UScriptCode script,
     FontDescription::GenericFamilyType generic_family_type,
     const AtomicString& resulting_font_name) {
-  if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+  if (!IdentifiabilityStudySettings::Get()->ShouldSampleType(
           IdentifiableSurface::Type::kGenericFontLookup)) {
     return;
   }
@@ -295,7 +295,7 @@
   for (const auto& surface_entry : hash_maps_with_corresponding_surface_types) {
     TokenToTokenHashMap* hash_map = surface_entry.first;
     const IdentifiableSurface::Type surface_type = surface_entry.second;
-    if (IdentifiabilityStudySettings::Get()->ShouldSample(surface_type)) {
+    if (IdentifiabilityStudySettings::Get()->ShouldSampleType(surface_type)) {
       for (const auto& individual_lookup : *hash_map) {
         builder.Add(IdentifiableSurface::FromTypeAndToken(
                         surface_type, individual_lookup.key.token),
diff --git a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
index 52de0724..7a4f7479 100644
--- a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
@@ -456,6 +456,7 @@
     mojom::blink::RendererEvictionReason reason) {
   if (!back_forward_cache_loader_helper_)
     return;
+  DCHECK(IsSuspendedForBackForwardCache());
   back_forward_cache_loader_helper_->EvictFromBackForwardCache(reason);
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
index 1bdea7d7..432d4cb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/mojo_url_loader_client.cc
@@ -294,8 +294,12 @@
 
 void MojoURLLoaderClient::Freeze(WebLoaderFreezeMode mode) {
   freeze_mode_ = mode;
-  if (mode == WebLoaderFreezeMode::kNone) {
+  if (mode != WebLoaderFreezeMode::kBufferIncoming) {
+    // Back/forward cache eviction should only be triggered when `freeze_mode_`
+    // is kBufferIncoming.
     StopBackForwardCacheEvictionTimer();
+  }
+  if (mode == WebLoaderFreezeMode::kNone) {
     task_runner_->PostTask(
         FROM_HERE, WTF::Bind(&MojoURLLoaderClient::FlushDeferredMessages,
                              weak_factory_.GetWeakPtr()));
@@ -345,6 +349,7 @@
 
 void MojoURLLoaderClient::EvictFromBackForwardCache(
     blink::mojom::RendererEvictionReason reason) {
+  DCHECK_EQ(freeze_mode_, WebLoaderFreezeMode::kBufferIncoming);
   StopBackForwardCacheEvictionTimer();
   auto* back_forward_cache_loader_helper = GetBackForwardCacheLoaderHelper();
   if (!back_forward_cache_loader_helper)
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
index 2316fc9d..72c67e2a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
@@ -173,20 +173,7 @@
     mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
     scoped_refptr<WebRequestPeer> peer,
     std::unique_ptr<ResourceLoadInfoNotifierWrapper>
-        resource_load_info_notifier_wrapper,
-    WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
-  if (IsInflightNetworkRequestBackForwardCacheSupportEnabled()) {
-    // Sync fetches are triggered by script, which should not run when a
-    // document is in back-forward cache. If we somehow made it here, we should
-    // trigger a back-forward cache eviction.
-    auto* helper =
-        back_forward_cache_loader_helper.GetBackForwardCacheLoaderHelper();
-    if (helper) {
-      helper->EvictFromBackForwardCache(
-          mojom::RendererEvictionReason::kJavaScriptExecution);
-    }
-  }
-
+        resource_load_info_notifier_wrapper) {
   CheckSchemeForReferrerPolicy(*request);
 
   DCHECK(loader_options & network::mojom::kURLLoadOptionSynchronous);
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
index 1a0288a..8651bf01 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
@@ -482,7 +482,7 @@
   }
 
   if (sync_load_response) {
-    DCHECK(freeze_mode_ == WebLoaderFreezeMode::kNone);
+    DCHECK_EQ(freeze_mode_, WebLoaderFreezeMode::kNone);
 
     loader_options |= network::mojom::kURLLoadOptionSynchronous;
     request->load_flags |= net::LOAD_IGNORE_LIMITS;
@@ -499,8 +499,7 @@
         url_loader_factory_, std::move(throttles), timeout_interval,
         cors_exempt_header_list_, terminate_sync_load_event_,
         std::move(download_to_blob_registry), base::WrapRefCounted(this),
-        std::move(resource_load_info_notifier_wrapper),
-        back_forward_cache_loader_helper_);
+        std::move(resource_load_info_notifier_wrapper));
     return;
   }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
index 19c31b94..ab3fbd4 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader_unittest.cc
@@ -86,9 +86,7 @@
       mojo::PendingRemote<mojom::BlobRegistry> download_to_blob_registry,
       scoped_refptr<WebRequestPeer> peer,
       std::unique_ptr<ResourceLoadInfoNotifierWrapper>
-          resource_load_info_notifier_wrapper,
-      WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
-      override {
+          resource_load_info_notifier_wrapper) override {
     *response = std::move(sync_load_response_);
   }
 
diff --git a/third_party/blink/renderer/platform/mediastream/media_constraints.cc b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
index 549bbf0..fb91766 100644
--- a/third_party/blink/renderer/platform/mediastream/media_constraints.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_constraints.cc
@@ -371,7 +371,10 @@
       voice_activity_detection("voiceActivityDetection"),
       ice_restart("iceRestart"),
       goog_use_rtp_mux("googUseRtpMux"),
+#if BUILDFLAG(IS_FUCHSIA)
+      // TODO(crbug.com/804275): Delete when Fuchsia no longer depends on it.
       enable_dtls_srtp("enableDtlsSrtp"),
+#endif
       enable_rtp_data_channels("enableRtpDataChannels"),
       enable_dscp("enableDscp"),
       enable_i_pv6("enableIPv6"),
@@ -383,58 +386,33 @@
       goog_cpu_overuse_detection("googCpuOveruseDetection"),
       goog_high_start_bitrate("googHighStartBitrate"),
       goog_payload_padding("googPayloadPadding"),
-      goog_latency_ms("latencyMs") {}
+      goog_latency_ms("latencyMs") {
+}
 
 Vector<const BaseConstraint*> MediaTrackConstraintSetPlatform::AllConstraints()
     const {
-  return {&width,
-          &height,
-          &aspect_ratio,
-          &frame_rate,
-          &facing_mode,
-          &resize_mode,
-          &volume,
-          &sample_rate,
-          &sample_size,
-          &echo_cancellation,
-          &echo_cancellation_type,
-          &latency,
-          &channel_count,
-          &device_id,
-          &group_id,
-          &media_stream_source,
-          &disable_local_echo,
-          &pan,
-          &tilt,
-          &zoom,
-          &render_to_associated_sink,
-          &goog_echo_cancellation,
-          &goog_experimental_echo_cancellation,
-          &goog_auto_gain_control,
-          &goog_experimental_auto_gain_control,
-          &goog_noise_suppression,
-          &goog_highpass_filter,
-          &goog_experimental_noise_suppression,
-          &goog_audio_mirroring,
-          &goog_da_echo_cancellation,
-          &goog_noise_reduction,
-          &offer_to_receive_audio,
-          &offer_to_receive_video,
-          &voice_activity_detection,
-          &ice_restart,
-          &goog_use_rtp_mux,
-          &enable_dtls_srtp,
-          &enable_rtp_data_channels,
-          &enable_dscp,
-          &enable_i_pv6,
-          &goog_enable_video_suspend_below_min_bitrate,
-          &goog_num_unsignalled_recv_streams,
-          &goog_combined_audio_video_bwe,
-          &goog_screencast_min_bitrate,
-          &goog_cpu_overuse_detection,
-          &goog_high_start_bitrate,
-          &goog_payload_padding,
-          &goog_latency_ms};
+  return {
+    &width, &height, &aspect_ratio, &frame_rate, &facing_mode, &resize_mode,
+        &volume, &sample_rate, &sample_size, &echo_cancellation,
+        &echo_cancellation_type, &latency, &channel_count, &device_id,
+        &group_id, &media_stream_source, &disable_local_echo, &pan, &tilt,
+        &zoom, &render_to_associated_sink, &goog_echo_cancellation,
+        &goog_experimental_echo_cancellation, &goog_auto_gain_control,
+        &goog_experimental_auto_gain_control, &goog_noise_suppression,
+        &goog_highpass_filter, &goog_experimental_noise_suppression,
+        &goog_audio_mirroring, &goog_da_echo_cancellation,
+        &goog_noise_reduction, &offer_to_receive_audio, &offer_to_receive_video,
+        &voice_activity_detection, &ice_restart, &goog_use_rtp_mux,
+#if BUILDFLAG(IS_FUCHSIA)
+        // TODO(crbug.com/804275): Delete when Fuchsia no longer depends on it.
+        &enable_dtls_srtp,
+#endif
+        &enable_rtp_data_channels, &enable_dscp, &enable_i_pv6,
+        &goog_enable_video_suspend_below_min_bitrate,
+        &goog_num_unsignalled_recv_streams, &goog_combined_audio_video_bwe,
+        &goog_screencast_min_bitrate, &goog_cpu_overuse_detection,
+        &goog_high_start_bitrate, &goog_payload_padding, &goog_latency_ms
+  };
 }
 
 bool MediaTrackConstraintSetPlatform::IsUnconstrained() const {
diff --git a/third_party/blink/renderer/platform/mediastream/media_constraints.h b/third_party/blink/renderer/platform/mediastream/media_constraints.h
index acdb8ad8..aa5970a 100644
--- a/third_party/blink/renderer/platform/mediastream/media_constraints.h
+++ b/third_party/blink/renderer/platform/mediastream/media_constraints.h
@@ -267,7 +267,10 @@
   BooleanConstraint voice_activity_detection;
   BooleanConstraint ice_restart;
   BooleanConstraint goog_use_rtp_mux;
+#if BUILDFLAG(IS_FUCHSIA)
+  // TODO(crbug.com/804275): Delete when Fuchsia no longer depends on it.
   BooleanConstraint enable_dtls_srtp;
+#endif
   BooleanConstraint enable_rtp_data_channels;
   BooleanConstraint enable_dscp;
   BooleanConstraint enable_i_pv6;
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index b4fd845..b039d05 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -513,7 +513,7 @@
 
 crbug.com/951895 [ Debug Mac ] transforms/2d/transform-2d.html [ Slow ]
 
-crbug.com/980804 fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
+crbug.com/980804 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Slow ]
 
 crbug.com/983642 virtual/gpu/fast/canvas/canvas-composite-alpha.html [ Slow ]
 crbug.com/983642 [ Debug Mac ] fast/canvas/canvas-composite-alpha.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f5e0f3d..5a488eb 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2032,8 +2032,6 @@
 crbug.com/520611 [ Debug ] fast/filesystem/workers/file-writer-events-shared-worker.html [ Failure Pass ]
 crbug.com/520194 http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-overridesexpires.html [ Failure Pass ]
 
-crbug.com/892032 fast/events/wheel/wheel-latched-scroll-node-removed.html [ Failure Pass ]
-
 crbug.com/1051136 fast/forms/select/listbox-overlay-scrollbar.html [ Failure ]
 
 # These performance-sensitive user-timing tests are flaky in debug on all platforms, and flaky on all configurations of windows.
@@ -5679,7 +5677,6 @@
 crbug.com/476553 virtual/scroll-unification/scrollbars/listbox-scrollbar-combinations.html [ Crash Failure Pass Timeout ]
 crbug.com/476553 virtual/scroll-unification-layout_ng_block_frag/fast/forms/fieldset/fieldset-legend-change.html [ Crash Failure Pass Timeout ]
 crbug.com/476553 virtual/scroll-unification-percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-deleted-scrollbar.html [ Crash Failure Pass Timeout ]
-crbug.com/476553 virtual/scroll-unification-percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Crash Failure Pass Timeout ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/auto-scrollbar-fades-out.html [ Crash Failure Pass Timeout ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/basic-scrollbar.html [ Crash Failure Pass Timeout ]
 crbug.com/476553 virtual/scroll-unification-prefer_compositing_to_lcd_text/scrollbars/disabled-scrollbar.html [ Crash Failure Pass Timeout ]
@@ -5978,9 +5975,6 @@
 
 # Sheriff 2020-09-23
 crbug.com/1131551 compositing/transitions/transform-on-large-layer.html [ Failure Pass Timeout ]
-crbug.com/1057060 virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Pass Timeout ]
-crbug.com/1057060 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Pass Timeout ]
-crbug.com/1057060 virtual/scroll-unification/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Failure Pass Timeout ]
 
 crbug.com/1136163 [ Linux ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html [ Failure ]
 
@@ -7704,6 +7698,15 @@
 crbug.com/1311786 external/wpt/navigation-api/navigation-methods/sandboxing-back-parent.html [ Skip ]
 crbug.com/1311786 external/wpt/navigation-api/navigation-methods/sandboxing-back-sibling.html [ Skip ]
 
+# Scroll Unification known issues (go/su-web-tests) for enabling in test:
+crbug.com/1311431 [ Mac ] fast/scroll-behavior/overscroll-behavior.html [ Failure Pass ]
+crbug.com/1248231 fast/events/touch/touch-latched-scroll-node-removed.html [ Failure Pass ]
+crbug.com/1248231 fast/events/wheel/wheel-latched-scroll-node-removed.html [ Failure Timeout Pass ]
+crbug.com/1311731 [ Linux ] fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure Pass ]
+crbug.com/1311731 [ Win ] fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure Pass ]
+crbug.com/1248581 fast/scrolling/resize-corner-tracking-touch.html [ Failure Pass ]
+crbug.com/1312036 virtual/hidpi/fast/scrolling/scrollbars/dsf-ready/mouse-interactions-dsf-2.html [ Failure Pass ]
+
 # Sheriff 2022-03-29
 crbug.com/1311138 [ Mac10.13 ] virtual/document-transition/wpt_internal/document-transition/one-element-two-targets.html [ Skip ]
 crbug.com/1311138 [ Mac10.14 ] virtual/document-transition/wpt_internal/document-transition/one-element-two-targets.html [ Skip ]
diff --git a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html b/third_party/blink/web_tests/virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
similarity index 96%
rename from third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
rename to third_party/blink/web_tests/virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
index 83d653ab..d645f18 100644
--- a/third_party/blink/web_tests/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
+++ b/third_party/blink/web_tests/virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <title>Tests mouse autoscroll interactions on a non-custom composited div scrollbar.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/gesture-util.js"></script>
-<script src="../../../resources/scrollbar-util.js"></script>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script src="../../../../../resources/gesture-util.js"></script>
+<script src="../../../../../resources/scrollbar-util.js"></script>
 <style>
 .appearance {
   width: 100px;
diff --git a/third_party/private-join-and-compute/OWNERS b/third_party/private-join-and-compute/OWNERS
index 91b00c1..4345771 100644
--- a/third_party/private-join-and-compute/OWNERS
+++ b/third_party/private-join-and-compute/OWNERS
@@ -1,3 +1,2 @@
-jdoerrie@chromium.org
 kwlyeo@chromium.org
 vasilii@chromium.org
diff --git a/third_party/zxcvbn-cpp/OWNERS b/third_party/zxcvbn-cpp/OWNERS
index 08fcf9b..a10e9420 100644
--- a/third_party/zxcvbn-cpp/OWNERS
+++ b/third_party/zxcvbn-cpp/OWNERS
@@ -1,2 +1 @@
-jdoerrie@chromium.org
 vasilii@chromium.org
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 7318518f..27d08c0 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -228,7 +228,8 @@
   if output_directory:
     gn_args = _ParseGnArgs(os.path.join(output_directory, 'args.gn'))
     build_config[models.BUILD_CONFIG_GN_ARGS] = gn_args
-
+    build_config[models.BUILD_CONFIG_OUT_DIRECTORY] = os.path.relpath(
+        output_directory, start=source_directory)
   git_rev = _DetectGitRevision(source_directory)
   if git_rev:
     build_config[models.BUILD_CONFIG_GIT_REVISION] = git_rev
diff --git a/tools/binary_size/libsupersize/file_format.py b/tools/binary_size/libsupersize/file_format.py
index c8a16c4..e62f69eb 100644
--- a/tools/binary_size/libsupersize/file_format.py
+++ b/tools/binary_size/libsupersize/file_format.py
@@ -48,10 +48,9 @@
 }
 
 # Keys in build config for old .size files.
-_LEGACY_METADATA_BUILD_CONFIG_KEYS = (
-    models.BUILD_CONFIG_GIT_REVISION,
-    models.BUILD_CONFIG_GN_ARGS,
-)
+_LEGACY_METADATA_BUILD_CONFIG_KEYS = (models.BUILD_CONFIG_GIT_REVISION,
+                                      models.BUILD_CONFIG_GN_ARGS,
+                                      models.BUILD_CONFIG_OUT_DIRECTORY)
 
 # Ensure each |models.SECTION_*| (except |SECTION_MULTIPLE|) has an entry.
 assert len(_SECTION_SORT_ORDER) + 1 == len(models.SECTION_NAME_TO_SECTION)
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py
index 416608f3..6fed98f5 100644
--- a/tools/binary_size/libsupersize/models.py
+++ b/tools/binary_size/libsupersize/models.py
@@ -19,6 +19,7 @@
 BUILD_CONFIG_GN_ARGS = 'gn_args'
 BUILD_CONFIG_TITLE = 'title'
 BUILD_CONFIG_URL = 'url'
+BUILD_CONFIG_OUT_DIRECTORY = 'out_directory'
 
 METADATA_APK_FILENAME = 'apk_file_name'  # Path relative to output_directory.
 METADATA_APK_SIZE = 'apk_size'  # File size of apk in bytes.
diff --git a/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden b/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden
index b387261..00a5980 100644
--- a/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden
+++ b/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden
@@ -1,6 +1,7 @@
 BuildConfig:
 git_revision=abc123
 gn_args=var1=true var2="foo"
+out_directory=out/Release
 Metadata:
 Container1:
 apk_file_name=test.apk
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
index 62b971e7..46bda6be 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
@@ -10,6 +10,7 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
 map_file_name=../../../test.map
+out_directory=out/Release
 zipalign_padding=32
 Section .text: has 100.0% of 35982248 bytes accounted for from 22 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (0.0%)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
index 98774dd..2b98f9b 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -7,6 +7,7 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
 map_file_name=../../../test.map
+out_directory=out/Release
 Section .text: has 100.0% of 35982248 bytes accounted for from 22 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (0.0%)
 * 16 have source paths. Accounts for 73986 bytes (0.2%).
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf_No_Map.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf_No_Map.golden
index ee0569b..e5c82ee 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf_No_Map.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf_No_Map.golden
@@ -6,6 +6,7 @@
 elf_relocations_count=394087
 git_revision=abc123
 gn_args=var1=true var2="foo"
+out_directory=out/Release
 Section .text: has 100.0% of 35982248 bytes accounted for from 11 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 83704 bytes (0.2%)
 * 11 have source paths. Accounts for 35982248 bytes (100.0%).
diff --git a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
index 90ba441..a8b2396 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
@@ -1,5 +1,6 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
+out_directory=out/Release
 apk_file_name=Bundle.minimal.apks
 apk_signature_block_size=0
 apk_size=147858981
diff --git a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
index aaf4b23f..541c12bb 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
@@ -2,6 +2,7 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
 map_file_name=../../../test.map
+out_directory=out/Release
 Section .text: has 100.0% of 35982248 bytes accounted for from 17 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (0.0%)
 * 14 have source paths. Accounts for 74034 bytes (0.2%).
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
index b4c8521..da028d0e 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
@@ -7,6 +7,7 @@
 git_revision=abc123
 gn_args=var1=true var2="foo"
 map_file_name=../../../test.map
+out_directory=out/Release
 Section .text: has 100.0% of 35982248 bytes accounted for from 22 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (0.0%)
 * 16 have source paths. Accounts for 73986 bytes (0.2%).
diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden
index 642af63..74023e3 100644
--- a/tools/binary_size/libsupersize/testdata/Console.golden
+++ b/tools/binary_size/libsupersize/testdata/Console.golden
@@ -72,6 +72,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../../../test.map
+    out_directory=out/Release
 
 Section Sizes (Total=128.0mb (134218045 bytes)):
     .bss: 1.24mb (1300456 bytes) (not included in totals)
diff --git a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
index a8a85f8..3155707 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
@@ -2,6 +2,7 @@
     baz=yes
     foo=1
     gn_args=var1=true var2="foo"
+    out_directory=out/Release
 Old Metadata:
     bar=[1, 2, 3]
     git_revision=abc123
diff --git a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
index b46120da..b6e06a64 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
@@ -8,6 +8,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../../../test.map
+    out_directory=out/Release
 Old Metadata:
 New Metadata:
 
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden
index 3f4223c4..a6c7710 100644
--- a/tools/binary_size/libsupersize/testdata/FullDescription.golden
+++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -8,6 +8,7 @@
     git_revision=abc123
     gn_args=var1=true var2="foo"
     map_file_name=../../../test.map
+    out_directory=out/Release
 
 Section Sizes (Total=128.0mb (134218045 bytes)):
     .bss: 1.24mb (1300456 bytes) (not included in totals)
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py
index 08a567e..4d9d5e4 100755
--- a/tools/idl_parser/idl_lexer.py
+++ b/tools/idl_parser/idl_lexer.py
@@ -251,8 +251,6 @@
     return self.tokens
 
   def Lexer(self):
-    if not self._lexobj:
-      self._lexobj = lex.lex(object=self, lextab=None, optimize=0)
     return self._lexobj
 
   def _AddToken(self, token):
@@ -275,7 +273,7 @@
       self.tokens.remove(key.upper())
       del self.keywords[key]
 
-  def __init__(self):
+  def __init__(self, optimize=True):
     self.index = [0]
     self._lex_errors = 0
     self.linex = []
@@ -284,7 +282,7 @@
     self.tokens = []
     self._AddTokens(IDLLexer.tokens)
     self._AddKeywords(IDLLexer.keywords)
-    self._lexobj = None
+    self._lexobj = lex.lex(object=self, lextab=None, optimize=optimize)
     self.last = None
     self.lines = None
 
diff --git a/tools/memory/partition_allocator/inspect_utils.cc b/tools/memory/partition_allocator/inspect_utils.cc
index 1685c7c7..68c28a3b 100644
--- a/tools/memory/partition_allocator/inspect_utils.cc
+++ b/tools/memory/partition_allocator/inspect_utils.cc
@@ -11,7 +11,7 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 
-namespace partition_alloc::internal::tools {
+namespace partition_alloc::tools {
 
 base::ScopedFD OpenProcMem(pid_t pid) {
   std::string path = base::StringPrintf("/proc/%d/mem", pid);
@@ -75,8 +75,7 @@
 
 uintptr_t IndexThreadCacheNeedleArray(pid_t pid, int mem_fd, size_t index) {
   std::vector<base::debug::MappedMemoryRegion> regions;
-  DCHECK_LT(index,
-            partition_alloc::internal::tools::kThreadCacheNeedleArraySize);
+  DCHECK_LT(index, kThreadCacheNeedleArraySize);
 
   {
     // Ensures that the mappings are not going to change.
@@ -135,10 +134,8 @@
         continue;
       }
 
-      if (needle_array_candidate[0] ==
-              partition_alloc::internal::tools::kNeedle1 &&
-          needle_array_candidate[kThreadCacheNeedleArraySize - 1] ==
-              partition_alloc::internal::tools::kNeedle2) {
+      if (needle_array_candidate[0] == kNeedle1 &&
+          needle_array_candidate[kThreadCacheNeedleArraySize - 1] == kNeedle2) {
         LOG(INFO) << "Got it! Address = 0x" << std::hex
                   << needle_array_candidate[index];
         return needle_array_candidate[index];
@@ -150,4 +147,4 @@
   return 0;
 }
 
-}  // namespace partition_alloc::internal::tools
+}  // namespace partition_alloc::tools
diff --git a/tools/memory/partition_allocator/inspect_utils.h b/tools/memory/partition_allocator/inspect_utils.h
index 3c5c4fe..c28a803f 100644
--- a/tools/memory/partition_allocator/inspect_utils.h
+++ b/tools/memory/partition_allocator/inspect_utils.h
@@ -19,7 +19,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace partition_alloc::internal::tools {
+namespace partition_alloc::tools {
 
 // SIGSTOPs a process.
 class ScopedSigStopper {
@@ -78,6 +78,6 @@
   alignas(T) char buffer_[sizeof(T)];
 };
 
-}  // namespace partition_alloc::internal::tools
+}  // namespace partition_alloc::tools
 
 #endif  // TOOLS_MEMORY_PARTITION_ALLOCATOR_INSPECT_UTILS_H_
diff --git a/tools/memory/partition_allocator/pa_buckets_inspect.cc b/tools/memory/partition_allocator/pa_buckets_inspect.cc
index fea0106..e58fef2b 100644
--- a/tools/memory/partition_allocator/pa_buckets_inspect.cc
+++ b/tools/memory/partition_allocator/pa_buckets_inspect.cc
@@ -19,7 +19,6 @@
 
 #include "base/allocator/partition_allocator/partition_root.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
-
 #include "base/check_op.h"
 #include "base/debug/proc_maps_linux.h"
 #include "base/files/file.h"
@@ -34,9 +33,12 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "tools/memory/partition_allocator/inspect_utils.h"
 
-namespace partition_alloc::internal::tools {
+namespace partition_alloc::tools {
 namespace {
 
+using partition_alloc::internal::BucketIndexLookup;
+using partition_alloc::internal::kNumBuckets;
+
 constexpr const char* kDumpName = "dump.dat";
 constexpr const char* kTmpDumpName = "dump.dat.tmp";
 
@@ -46,7 +48,7 @@
 
 void DisplayPerBucketData(
     const std::unordered_map<uintptr_t, size_t>& live_allocs) {
-  constexpr base::internal::BucketIndexLookup lookup{};
+  constexpr BucketIndexLookup lookup{};
   std::cout << "Per-bucket stats:"
             << "\nIndex\tBucket Size\t#Allocs\tTotal Size\tFragmentation"
             << std::string(80, '-') << "\n";
@@ -56,7 +58,7 @@
   size_t total_memory = 0;
   for (const auto& pair : live_allocs) {
     total_memory += pair.second;
-    const auto index = base::internal::BucketIndexLookup::GetIndex(pair.second);
+    const auto index = BucketIndexLookup::GetIndex(pair.second);
     alloc_size[index] += pair.second;
     alloc_nums[index]++;
   }
@@ -91,9 +93,12 @@
 }
 
 }  // namespace
-}  // namespace partition_alloc::internal::tools
+}  // namespace partition_alloc::tools
 
 int main(int argc, char** argv) {
+  using partition_alloc::internal::AllocInfo;
+  using partition_alloc::internal::kAllocInfoSize;
+
   if (argc < 2) {
     LOG(ERROR) << "Usage:" << argv[0] << " <PID> "
                << "[address. 0 to scan the process memory]";
@@ -103,7 +108,7 @@
   int pid = atoi(argv[1]);
   uintptr_t registry_address = 0;
 
-  auto mem_fd = partition_alloc::internal::tools::OpenProcMem(pid);
+  auto mem_fd = partition_alloc::tools::OpenProcMem(pid);
 
   if (argc == 3) {
     uint64_t address;
@@ -111,24 +116,22 @@
     registry_address = static_cast<uintptr_t>(address);
   } else {
     // Scan the memory.
-    registry_address = partition_alloc::internal::tools::FindAllocInfoAddress(
-        pid, mem_fd.get());
+    registry_address =
+        partition_alloc::tools::FindAllocInfoAddress(pid, mem_fd.get());
   }
 
   CHECK(registry_address);
 
-  auto alloc_info = std::make_unique<partition_alloc::internal::AllocInfo>();
-  partition_alloc::internal::tools::ReadMemory(
-      mem_fd.get(), registry_address,
-      sizeof(partition_alloc::internal::AllocInfo),
-      reinterpret_cast<char*>(alloc_info.get()));
+  auto alloc_info = std::make_unique<AllocInfo>();
+  partition_alloc::tools::ReadMemory(mem_fd.get(), registry_address,
+                                     sizeof(AllocInfo),
+                                     reinterpret_cast<char*>(alloc_info.get()));
 
   size_t old_index = 0;
   size_t new_index = alloc_info->index;
 
   std::unordered_map<uintptr_t, size_t> live_allocs = {};
   while (true) {
-    using partition_alloc::internal::kAllocInfoSize;
     base::TimeTicks tick = base::TimeTicks::Now();
 
     size_t len = old_index < new_index ? new_index - old_index
@@ -150,11 +153,10 @@
     constexpr const char* kClearScreen = "\033[2J\033[1;1H";
     std::cout << kClearScreen << "Time to gather data = " << gather_time_ms
               << "ms\n";
-    partition_alloc::internal::tools::DisplayPerBucketData(live_allocs);
+    partition_alloc::tools::DisplayPerBucketData(live_allocs);
 
-    partition_alloc::internal::tools::ReadMemory(
-        mem_fd.get(), registry_address,
-        sizeof(partition_alloc::internal::AllocInfo),
+    partition_alloc::tools::ReadMemory(
+        mem_fd.get(), registry_address, sizeof(AllocInfo),
         reinterpret_cast<char*>(alloc_info.get()));
 
     old_index = new_index;
diff --git a/tools/memory/partition_allocator/pa_dump_heap.cc b/tools/memory/partition_allocator/pa_dump_heap.cc
index 6b523e52b..deb7a7c 100644
--- a/tools/memory/partition_allocator/pa_dump_heap.cc
+++ b/tools/memory/partition_allocator/pa_dump_heap.cc
@@ -5,11 +5,13 @@
 // Dumps PartitionAlloc's heap into a file.
 
 #include <sys/mman.h>
+
 #include <cstdlib>
 #include <cstring>
 #include <string>
 
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
+#include "base/allocator/partition_allocator/partition_ref_count.h"
 #include "base/allocator/partition_allocator/partition_root.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
 #include "base/check.h"
@@ -22,7 +24,18 @@
 #include "base/values.h"
 #include "tools/memory/partition_allocator/inspect_utils.h"
 
-namespace partition_alloc::internal::tools {
+namespace partition_alloc::tools {
+
+using partition_alloc::internal::kInvalidBucketSize;
+using partition_alloc::internal::kSuperPageSize;
+using partition_alloc::internal::PartitionPage;
+using partition_alloc::internal::PartitionPageSize;
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+using partition_alloc::internal::PartitionRefCountPointer;
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
+using partition_alloc::internal::PartitionSuperPageExtentEntry;
+using partition_alloc::internal::SystemPageSize;
+using partition_alloc::internal::ThreadSafe;
 
 class HeapDumper {
  public:
@@ -260,7 +273,7 @@
           }
           uintptr_t slot_address =
               slot_span_start + slot_index * metadata.bucket->slot_size;
-          auto* ref_count = internal::PartitionRefCountPointer(slot_address);
+          auto* ref_count = PartitionRefCountPointer(slot_address);
           uint32_t requested_size = ref_count->requested_size();
 
           // Address space dumping is not synchronized with allocation, meaning
@@ -303,9 +316,8 @@
                                    int mem_fd) NO_THREAD_SAFETY_ANALYSIS {
     uintptr_t tcache_registry_address =
         IndexThreadCacheNeedleArray(pid, mem_fd, 1);
-    auto registry =
-        RawBuffer<base::internal::ThreadCacheRegistry>::ReadFromMemFd(
-            mem_fd, tcache_registry_address);
+    auto registry = RawBuffer<ThreadCacheRegistry>::ReadFromMemFd(
+        mem_fd, tcache_registry_address);
     if (!registry)
       return 0;
 
@@ -314,8 +326,7 @@
     if (!tcache_address)
       return 0;
 
-    auto tcache = RawBuffer<base::internal::ThreadCache>::ReadFromMemFd(
-        mem_fd, tcache_address);
+    auto tcache = RawBuffer<ThreadCache>::ReadFromMemFd(mem_fd, tcache_address);
     if (!tcache)
       return 0;
 
@@ -335,7 +346,7 @@
   size_t local_root_copy_mapping_size_ = 0;
 };
 
-}  // namespace partition_alloc::internal::tools
+}  // namespace partition_alloc::tools
 
 int main(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
@@ -349,11 +360,11 @@
   int pid = atoi(command_line->GetSwitchValueASCII("pid").c_str());
   LOG(WARNING) << "PID = " << pid;
 
-  auto mem_fd = partition_alloc::internal::tools::OpenProcMem(pid);
-  partition_alloc::internal::tools::HeapDumper dumper{pid, mem_fd.get()};
+  auto mem_fd = partition_alloc::tools::OpenProcMem(pid);
+  partition_alloc::tools::HeapDumper dumper{pid, mem_fd.get()};
 
   {
-    partition_alloc::internal::tools::ScopedSigStopper stopper{pid};
+    partition_alloc::tools::ScopedSigStopper stopper{pid};
     if (!dumper.FindRoot()) {
       LOG(WARNING) << "Cannot find (or copy) the root";
       return 1;
diff --git a/tools/memory/partition_allocator/pa_tcache_inspect.cc b/tools/memory/partition_allocator/pa_tcache_inspect.cc
index 961407d..988161cb 100644
--- a/tools/memory/partition_allocator/pa_tcache_inspect.cc
+++ b/tools/memory/partition_allocator/pa_tcache_inspect.cc
@@ -10,6 +10,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+
 #include <algorithm>
 #include <cstring>
 #include <ios>
@@ -20,7 +21,6 @@
 
 #include "base/allocator/partition_allocator/partition_root.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
-
 #include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/debug/proc_maps_linux.h"
@@ -41,7 +41,13 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "tools/memory/partition_allocator/inspect_utils.h"
 
-namespace partition_alloc::internal::tools {
+namespace partition_alloc::tools {
+
+using partition_alloc::internal::BucketIndexLookup;
+using partition_alloc::internal::PartitionBucket;
+using partition_alloc::internal::SlotSpanMetadata;
+using partition_alloc::internal::ThreadSafe;
+
 namespace {
 
 // Scans the process memory to look for the thread cache registry address. This
@@ -124,13 +130,11 @@
   size_t CachedMemory() const;
   uintptr_t GetRootAddress();
 
-  const std::vector<RawBuffer<base::internal::ThreadCache>>& thread_caches()
-      const {
+  const std::vector<RawBuffer<ThreadCache>>& thread_caches() const {
     return thread_caches_;
   }
 
-  static bool should_purge(
-      const RawBuffer<base::internal::ThreadCache>& tcache) {
+  static bool should_purge(const RawBuffer<ThreadCache>& tcache) {
     return tcache.get()->should_purge_;
   }
 
@@ -143,8 +147,8 @@
   uintptr_t registry_addr_;
   int mem_fd_;
   pid_t pid_;
-  RawBuffer<base::internal::ThreadCacheRegistry> registry_;
-  std::vector<RawBuffer<base::internal::ThreadCache>> thread_caches_;
+  RawBuffer<ThreadCacheRegistry> registry_;
+  std::vector<RawBuffer<ThreadCache>> thread_caches_;
 };
 
 class PartitionRootInspector {
@@ -154,7 +158,7 @@
     size_t allocated_slots = 0;
     size_t freelist_size = 0;
 
-    base::internal::PartitionBucket<base::internal::ThreadSafe> bucket;
+    PartitionBucket<ThreadSafe> bucket;
     std::vector<size_t> freelist_sizes;
     // Flattened versions of the lists.
     std::vector<SlotSpanMetadata<ThreadSafe>> active_slot_spans;
@@ -167,9 +171,7 @@
   // Returns true for success.
   bool GatherStatistics();
   const std::vector<BucketStats>& bucket_stats() const { return bucket_stats_; }
-  const PartitionRoot<base::internal::ThreadSafe>* root() {
-    return root_.get();
-  }
+  const PartitionRoot<ThreadSafe>* root() { return root_.get(); }
 
  private:
   void Update();
@@ -177,7 +179,7 @@
   uintptr_t root_addr_;
   int mem_fd_;
   pid_t pid_;
-  RawBuffer<PartitionRoot<base::internal::ThreadSafe>> root_;
+  RawBuffer<PartitionRoot<ThreadSafe>> root_;
   std::vector<BucketStats> bucket_stats_;
 };
 
@@ -194,15 +196,15 @@
   // This is going to take a while, make sure that the metadata don't change.
   ScopedSigStopper stopper{pid_};
 
-  auto registry = RawBuffer<base::internal::ThreadCacheRegistry>::ReadFromMemFd(
-      mem_fd_, registry_addr_);
+  auto registry =
+      RawBuffer<ThreadCacheRegistry>::ReadFromMemFd(mem_fd_, registry_addr_);
   if (!registry.has_value())
     return false;
 
   registry_ = *registry;
-  base::internal::ThreadCache* head = registry_.get()->list_head_;
+  ThreadCache* head = registry_.get()->list_head_;
   while (head) {
-    auto tcache = RawBuffer<base::internal::ThreadCache>::ReadFromMemFd(
+    auto tcache = RawBuffer<ThreadCache>::ReadFromMemFd(
         mem_fd_, reinterpret_cast<uintptr_t>(head));
     if (!tcache.has_value()) {
       LOG(WARNING) << "Failed to read a ThreadCache";
@@ -232,16 +234,16 @@
 
 std::vector<ThreadCacheInspector::BucketStats>
 ThreadCacheInspector::AccumulateThreadCacheBuckets() {
-  std::vector<BucketStats> result(base::internal::ThreadCache::kBucketCount);
+  std::vector<BucketStats> result(ThreadCache::kBucketCount);
   for (auto& tcache : thread_caches_) {
-    for (int i = 0; i < base::internal::ThreadCache::kBucketCount; i++) {
+    for (int i = 0; i < ThreadCache::kBucketCount; i++) {
       result[i].count += tcache.get()->buckets_[i].count;
       result[i].per_thread_limit = tcache.get()->buckets_[i].limit;
     }
   }
 
-  base::internal::BucketIndexLookup lookup{};
-  for (int i = 0; i < base::internal::ThreadCache::kBucketCount; i++) {
+  BucketIndexLookup lookup{};
+  for (int i = 0; i < ThreadCache::kBucketCount; i++) {
     result[i].size = lookup.bucket_sizes()[i];
   }
   return result;
@@ -249,26 +251,22 @@
 
 void PartitionRootInspector::Update() {
   auto root =
-      RawBuffer<PartitionRoot<base::internal::ThreadSafe>>::ReadFromMemFd(
-          mem_fd_, root_addr_);
+      RawBuffer<PartitionRoot<ThreadSafe>>::ReadFromMemFd(mem_fd_, root_addr_);
   if (root.has_value())
     root_ = *root;
 }
 
 namespace {
 
-bool CopySlotSpanList(
-    std::vector<base::internal::SlotSpanMetadata<base::internal::ThreadSafe>>&
-        list,
-    uintptr_t head_address,
-    int mem_fd) {
-  absl::optional<RawBuffer<base::internal::SlotSpanMetadata<ThreadSafe>>>
-      metadata;
+bool CopySlotSpanList(std::vector<SlotSpanMetadata<ThreadSafe>>& list,
+                      uintptr_t head_address,
+                      int mem_fd) {
+  absl::optional<RawBuffer<SlotSpanMetadata<ThreadSafe>>> metadata;
   for (uintptr_t slot_span_address = head_address; slot_span_address;
        slot_span_address =
            reinterpret_cast<uintptr_t>(metadata->get()->next_slot_span)) {
-    metadata = RawBuffer<base::internal::SlotSpanMetadata<
-        base::internal::ThreadSafe>>::ReadFromMemFd(mem_fd, slot_span_address);
+    metadata = RawBuffer<SlotSpanMetadata<ThreadSafe>>::ReadFromMemFd(
+        mem_fd, slot_span_address);
     if (!metadata.has_value())
       return false;
     list.push_back(*metadata->get());
@@ -560,7 +558,7 @@
   result.SetKey("buckets", std::move(bucket_stats));
   return result;
 }
-}  // namespace partition_alloc::internal::tools
+}  // namespace partition_alloc::tools
 
 int main(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
@@ -578,15 +576,14 @@
   base::FilePath json_filename =
       base::CommandLine::ForCurrentProcess()->GetSwitchValuePath("json");
 
-  auto mem_fd = partition_alloc::internal::tools::OpenProcMem(pid);
+  auto mem_fd = partition_alloc::tools::OpenProcMem(pid);
   // Scan the memory.
   uintptr_t registry_address =
-      partition_alloc::internal::tools::FindThreadCacheRegistry(pid,
-                                                                mem_fd.get());
+      partition_alloc::tools::FindThreadCacheRegistry(pid, mem_fd.get());
   CHECK(registry_address);
 
   LOG(INFO) << "Getting the thread cache registry";
-  partition_alloc::internal::tools::ThreadCacheInspector thread_cache_inspector{
+  partition_alloc::tools::ThreadCacheInspector thread_cache_inspector{
       registry_address, mem_fd.get(), pid};
   std::map<base::PlatformThreadId, std::string> tid_to_name;
 
@@ -601,7 +598,7 @@
     if (!ok)
       continue;
 
-    partition_alloc::internal::tools::PartitionRootInspector root_inspector{
+    partition_alloc::tools::PartitionRootInspector root_inspector{
         thread_cache_inspector.GetRootAddress(), mem_fd.get(), pid};
     bool has_bucket_stats = root_inspector.GatherStatistics();
 
@@ -610,7 +607,7 @@
       // as at worst we would display wrong data, and TID reuse is very unlikely
       // in normal scenarios.
       if (tid_to_name.find(tcache.get()->thread_id()) == tid_to_name.end()) {
-        tid_to_name = partition_alloc::internal::tools::ThreadNames(pid);
+        tid_to_name = partition_alloc::tools::ThreadNames(pid);
         break;
       }
     }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 89837198..51b9562 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1119,6 +1119,9 @@
   <int value="17" label="SigninTimeoutErrorShown">
     The sign-in time out error was shown to the user.
   </int>
+  <int value="18" label="SuppressedAlreadySignedIn">
+    The web sign-in is not shown because the user is already signed in.
+  </int>
 </enum>
 
 <enum name="AccountConsistencyPromoAfterDismissal">
@@ -6204,6 +6207,27 @@
   <int value="2" label="Preflight call ignored"/>
 </enum>
 
+<enum name="AutofillCreditCardSeamlessnessBitmask">
+  <summary>
+    A bitmask indicating which credit card field types were autofilled.
+  </summary>
+  <int value="1" label="-name, -num, -exp, +cvc"/>
+  <int value="2" label="-name, -num, +exp, -cvc"/>
+  <int value="3" label="-name, -num, +exp, +cvc"/>
+  <int value="4" label="-name, +num, -exp, -cvc"/>
+  <int value="5" label="-name, +num, -exp, +cvc"/>
+  <int value="6" label="-name, +num, +exp, -cvc"/>
+  <int value="7" label="-name, +num, +exp, +cvc"/>
+  <int value="8" label="+name, -num, -exp, -cvc"/>
+  <int value="9" label="+name, -num, -exp, +cvc"/>
+  <int value="10" label="+name, -num, +exp, -cvc"/>
+  <int value="11" label="+name, -num, +exp, +cvc"/>
+  <int value="12" label="+name, +num, -exp, -cvc"/>
+  <int value="13" label="+name, +num, -exp, +cvc"/>
+  <int value="14" label="+name, +num, +exp, -cvc"/>
+  <int value="15" label="+name, +num, +exp, +cvc"/>
+</enum>
+
 <enum name="AutofillCreditCardUnmaskDecisionMetric">
   <int value="0" label="WebAuthn only"/>
   <int value="1" label="CVC followed by WebAuthn"/>
@@ -6504,6 +6528,14 @@
   <int value="1841" label="ADDRESS_HOME_ADDRESS_WITH_NAME: accepted"/>
   <int value="1856" label="ADDRESS_HOME_FLOOR: edited"/>
   <int value="1857" label="ADDRESS_HOME_FLOOR: accepted"/>
+  <int value="1872" label="NAME_FULL_WITH_HONORIFIC_PREFIX: edited"/>
+  <int value="1873" label="NAME_FULL_WITH_HONORIFIC_PREFIX: accepted"/>
+  <int value="1888" label="BIRTHDATE_DAY: edited"/>
+  <int value="1889" label="BIRTHDATE_DAY: accepted"/>
+  <int value="1904" label="BIRTHDATE_MONTH: edited"/>
+  <int value="1905" label="BIRTHDATE_MONTH: accepted"/>
+  <int value="1920" label="BIRTHDATE_YEAR_4_DIGITS: edited"/>
+  <int value="1921" label="BIRTHDATE_YEAR_4_DIGITS: accepted"/>
 </enum>
 
 <enum name="AutofillErrorDialogType">
@@ -7399,6 +7431,27 @@
   <int value="97" label="SEARCH_TERM"/>
   <int value="98" label="PRICE"/>
   <int value="99" label="NOT_PASSWORD"/>
+  <int value="100" label="SINGLE_USERNAME"/>
+  <int value="101" label="NOT_USERNAME"/>
+  <int value="102" label="UPI_VPA"/>
+  <int value="103" label="ADDRESS_HOME_STREET_NAME"/>
+  <int value="104" label="ADDRESS_HOME_HOUSE_NUMBER"/>
+  <int value="105" label="ADDRESS_HOME_SUBPREMISE"/>
+  <int value="106" label="ADDRESS_HOME_OTHER_SUBUNIT"/>
+  <int value="107" label="NAME_LAST_FIRST"/>
+  <int value="108" label="NAME_LAST_CONJUNCTION"/>
+  <int value="109" label="NAME_LAST_SECOND"/>
+  <int value="110" label="NAME_HONORIFIC_PREFIX"/>
+  <int value="111" label="ADDRESS_HOME_PREMISE_NAME"/>
+  <int value="112" label="ADDRESS_HOME_DEPENDENT_STREET_NAME"/>
+  <int value="113" label="ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME"/>
+  <int value="114" label="ADDRESS_HOME_ADDRESS"/>
+  <int value="115" label="ADDRESS_HOME_ADDRESS_WITH_NAME"/>
+  <int value="116" label="ADDRESS_HOME_FLOOR"/>
+  <int value="117" label="NAME_FULL_WITH_HONORIFIC_PREFIX"/>
+  <int value="118" label="BIRTHDATE_DAY"/>
+  <int value="119" label="BIRTHDATE_MONTH"/>
+  <int value="120" label="BIRTHDATE_YEAR_4_DIGITS"/>
 </enum>
 
 <enum name="AutofillServerPredictionAvailability">
@@ -62048,6 +62101,38 @@
   <int value="1" label="Caught event before click"/>
 </enum>
 
+<enum name="MoveMigratorResumeStep">
+  <int value="0" label="Start"/>
+  <int value="1" label="MoveSplitItems"/>
+  <int value="2" label="MoveLacrosItems"/>
+  <int value="3" label="MoveTmpDir"/>
+  <int value="4" label="Completed"/>
+</enum>
+
+<enum name="MoveMigratorTaskStatus">
+  <int value="0" label="Succeeded"/>
+  <int value="1" label="Cancelled"/>
+  <int value="2" label="PreMigrationCleanUpDeleteLacrosDirFailed"/>
+  <int value="3" label="PreMigrationCleanUpDeleteTmpDirFailed"/>
+  <int value="4" label="PreMigrationCleanUpDeleteTmpSplitDirFailed"/>
+  <int value="5" label="PreMigrationCleanUpNotEnoughSpace"/>
+  <int value="6" label="SetupLacrosDirCreateTmpDirFailed"/>
+  <int value="7" label="SetupLacrosDirCreateTmpProfileDirFailed"/>
+  <int value="8" label="SetupLacrosDirCopyTargetItemsFailed"/>
+  <int value="9" label="SetupLacrosDirWriteFirstRunSentinelFileFailed"/>
+  <int value="10" label="SetupAshDirCreateSplitDirFailed"/>
+  <int value="11" label="SetupAshDirMigrateLevelDBForLocalStateFailed"/>
+  <int value="12" label="SetupAshDirMigrateLevelDBForStateFailed"/>
+  <int value="13" label="SetupAshDirMigratePreferencesFailed"/>
+  <int value="14" label="MoveLacrosItemsToNewDirNoWritePerm"/>
+  <int value="15" label="MoveLacrosItemsToNewDirMoveFailed"/>
+  <int value="16" label="MoveSplitItemsToOriginalDirMoveSplitItemsFailed"/>
+  <int value="17" label="MoveSplitItemsToOriginalDirCreateDirFailed"/>
+  <int value="18" label="MoveSplitItemsToOriginalDirMoveExtensionsFailed"/>
+  <int value="19" label="MoveSplitItemsToOriginalDirMoveIndexedDBFailed"/>
+  <int value="20" label="MoveTmpDirToLacrosDirMoveFailed"/>
+</enum>
+
 <enum name="MSECodec">
   <int value="0" label="(Unknown)"/>
   <int value="1" label="VP8"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 1571688..70534438 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -474,6 +474,127 @@
   <summary>The time taken for copying lacros data.</summary>
 </histogram>
 
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.CancelledMigrationTime"
+    units="ms" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The time taken for profile migration before it is cancelled by the user
+    during move migration. Profile move migration happens once after Lacros and
+    move migration is enabled. This only gets recorded if the user clicks
+    &quot;Skip&quot; from the migration UI displayed during the migration.
+    Profile move migration is a feature to migrate profile data from Ash to
+    Lacros once after Lacros is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.PosixErrno.{TaskStatus}"
+    units="errno" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    Recorded when profile move migration fails. Profile move migration happens
+    once after Lacros and move migration is enabled. Records the errno set by
+    the operation that caused the migration to fail. `TaskStatus` is used to
+    determine which step the error occurred. Profile move migration is a feature
+    to migrate profile data from Ash to Lacros once after Lacros is enabled.
+  </summary>
+  <token key="TaskStatus">
+    <variant name="Cancelled"/>
+    <variant name="MoveLacrosItemsToNewDirMoveFailed"/>
+    <variant name="MoveLacrosItemsToNewDirNoWritePerm"/>
+    <variant name="MoveSplitItemsToOriginalDirCreateDirFailed"/>
+    <variant name="MoveSplitItemsToOriginalDirMoveExtensionsFailed"/>
+    <variant name="MoveSplitItemsToOriginalDirMoveIndexedDBFailed"/>
+    <variant name="MoveSplitItemsToOriginalDirMoveSplitItemsFailed"/>
+    <variant name="MoveTmpDirToLacrosDirMoveFailed"/>
+    <variant name="PreMigrationCleanUpDeleteLacrosDirFailed"/>
+    <variant name="PreMigrationCleanUpDeleteTmpDirFailed"/>
+    <variant name="PreMigrationCleanUpDeleteTmpSplitDirFailed"/>
+    <variant name="PreMigrationCleanUpNotEnoughSpace"/>
+    <variant name="SetupAshDirCreateSplitDirFailed"/>
+    <variant name="SetupAshDirMigrateLevelDBForLocalStateFailed"/>
+    <variant name="SetupAshDirMigrateLevelDBForStateFailed"/>
+    <variant name="SetupAshDirMigratePreferencesFailed"/>
+    <variant name="SetupLacrosDirCopyTargetItemsFailed"/>
+    <variant name="SetupLacrosDirCreateTmpDirFailed"/>
+    <variant name="SetupLacrosDirCreateTmpProfileDirFailed"/>
+    <variant name="SetupLacrosDirWriteFirstRunSentinelFileFailed"/>
+    <variant name="Succeeded"/>
+  </token>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.PreMigrationCleanUpTime"
+    units="ms" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The time taken for move migration to run PreMigrationCleanUp() and recorded
+    once when profile move migration happens. Profile move migration migrates
+    profile data from Ash to Lacros after Lacros is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.ResumeStep"
+    enum="MoveMigratorResumeStep" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The step from which move migration is resumed from. Recorded once at the
+    beginning of profile move migration. Profile move migration gets resumed
+    from where it left off if the previous attempt were did not finish
+    completely. Profile move migration migrates profile data from Ash to Lacros
+    after Lacros is enabled.
+  </summary>
+</histogram>
+
+<histogram
+    name="Ash.BrowserDataMigrator.MoveMigrator.SetupLacrosDirCopyTargetItemsTime"
+    units="ms" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The time taken for move migration to copy target items inside
+    SetupLacrosDir(). Recorded once during profile move migration. Profile move
+    migration is a feature to migrate profile data from Ash to Lacros once after
+    Lacros is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.SetupLacrosDirTime"
+    units="ms" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The time taken for move migration to run SetupLacrosDir(). Recorded once
+    during the migration. Profile move migration is a feature to migrate profile
+    data from Ash to Lacros once after Lacros is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.SuccessfulMigrationTime"
+    units="ms" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The time taken for profile move migration to complete in ms. Recorded once
+    at the end of the migration if it is successful. Profile move migration is a
+    feature to migrate profile data from Ash to Lacros once after Lacros is
+    enabled.
+  </summary>
+</histogram>
+
+<histogram name="Ash.BrowserDataMigrator.MoveMigrator.TaskStatus"
+    enum="MoveMigratorTaskStatus" expires_after="M110">
+  <owner>ythjkt@chromium.org</owner>
+  <owner>hidehiko@chromium.org</owner>
+  <summary>
+    The final status of profile move migration. Recorded once at the end of the
+    migration process. Profile move migration is a feature to migrate profile
+    data from Ash to Lacros once after Lacros is enabled.
+  </summary>
+</histogram>
+
 <histogram name="Ash.BrowserDataMigrator.NoCopyDataSizeMB" units="MB"
     expires_after="M110">
   <owner>ythjkt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index ef239bf..1019505 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -778,6 +778,10 @@
 
 <histogram name="Autofill.CreditCard.Number{AutofillMeasurementTime}"
     units="Filled" expires_after="2022-10-31">
+  <obsolete>
+    Deprecated as of M101. Subsumed by
+    Autofill.CreditCard.Seamless{AutofillMeasurementTime}.Bitmask.
+  </obsolete>
   <owner>schwering@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
@@ -822,6 +826,28 @@
   <token key="AutofillMeasurementTime" variants="AutofillMeasurementTime"/>
 </histogram>
 
+<histogram name="Autofill.CreditCard.Seamless{AutofillMeasurementTime}.Bitmask"
+    enum="AutofillCreditCardSeamlessnessBitmask" expires_after="2022-10-31">
+  <owner>schwering@google.com</owner>
+  <owner>chrome-autofill-alerts@google.com</owner>
+  <summary>
+    Records for each credit card form the quality of the fill.
+    {AutofillMeasurementTime}
+
+    The emitted value is a non-zero bitmask whose bits have the following
+    meaning, from highest to lowest bit:
+
+    Bit #4 is true iff a cardholder name was filled.
+
+    Bit #3 is true iff a card number was filled.
+
+    Bit #2 is true iff an expiraton date was filled.
+
+    Bit #1 is true iff a CVC name was filled.
+  </summary>
+  <token key="AutofillMeasurementTime" variants="AutofillMeasurementTime"/>
+</histogram>
+
 <histogram name="Autofill.CreditCardFillingInfoBar"
     enum="AutofillCreditCardInfoBar" expires_after="2022-12-12">
   <owner>battre@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index eb700b4..57643ec 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -961,24 +961,9 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: A new in trial version of this metric exists, please refer to
-    Event.Latency.ScrollJank2.
-
     Tracks janky frames while processing scroll events, which are defined as
     frames taking longer than half of vsync interval compared to previous or
-    next frame, this is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollJank2" enum="Boolean"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Tracks janky frames while processing scroll events, which are defined as
-    frames taking longer than half of vsync interval compared to previous or
-    next frame, this is reported from the renderer compositor's EventMetrics.
+    next frame.
   </summary>
 </histogram>
 
@@ -987,24 +972,9 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: This metric is deprecated, please refer to
-    Event.Latency.ScrollUpdate.JankyDuration2.
-
     Total duration (wall time in milliseconds of potentially concurrent events)
     of LatencyInfo::GestureScrollUpdate events that are detected as janky during
-    a particular scroll, this is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollUpdate.JankyDuration2" units="ms"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Total duration (wall time in milliseconds of potentially concurrent events)
-    of GestureScrollUpdate events that are detected as janky during a particular
-    scroll, this is reported from the renderer compositor's EventMetrics.
+    a particular scroll.
   </summary>
 </histogram>
 
@@ -1013,23 +983,8 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: A new in trial version of this metric exists, please refer to
-    Event.Latency.ScrollUpdate.JankyDurationPercentage2.
-
     Percentage of duration of scroll events that are detected as janky during a
-    particular scroll, this is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollUpdate.JankyDurationPercentage2" units="%"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Percentage of duration of scroll events that are detected as janky during a
-    particular scroll, this is reported from the renderer compositor's
-    EventMetrics.
+    particular scroll.
   </summary>
 </histogram>
 
@@ -1038,23 +993,8 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: A new in trial version of this metric exists, please refer to
-    Event.Latency.ScrollUpdate.JankyEvents2.
-
     Count of LatencyInfo::GestureScrollUpdate events that are detected as janky
-    during a particular scroll, this is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollUpdate.JankyEvents2" units="counts"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Count of GestureScrollUpdate events that are detected as janky during a
-    particular scroll, this is reported from the renderer compositor's
-    EventMetrics.
+    during a particular scroll.
   </summary>
 </histogram>
 
@@ -1219,24 +1159,8 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: A new in trial version of this metric exists, please refer to
-    Event.Latency.ScrollUpdate.TotalDuration2.
-
     Total duration (wall time in milliseconds of potentially concurrent events)
-    of LatencyInfo::GestureScrollUpdate events during a particular scroll, this
-    is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollUpdate.TotalDuration2" units="ms"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Total duration (wall time in milliseconds of potentially concurrent events)
-    of GestureScrollUpdate events during a particular scroll, this is reported
-    from the renderer compositor's EventMetrics.
+    of LatencyInfo::GestureScrollUpdate events during a particular scroll.
   </summary>
 </histogram>
 
@@ -1245,22 +1169,7 @@
   <owner>ddrone@google.com</owner>
   <owner>chrometto-team@google.com</owner>
   <summary>
-    IMPORTANT: A new in trial version of this metric exists, please refer to
-    Event.Latency.ScrollUpdate.TotalEvents2.
-
-    Count of LatencyInfo::GestureScrollUpdate events during a particular scroll,
-    this is reported from the GPU.
-  </summary>
-</histogram>
-
-<histogram name="Event.Latency.ScrollUpdate.TotalEvents2" units="counts"
-    expires_after="2023-03-07">
-  <owner>ddrone@google.com</owner>
-  <owner>mekk@google.com</owner>
-  <owner>chrometto-team@google.com</owner>
-  <summary>
-    Count of GestureScrollUpdate events during a particular scroll, this is
-    reported from the renderer compositor's EventMetrics.
+    Count of LatencyInfo::GestureScrollUpdate events during a particular scroll.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index e731e9a8..33c3323 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -6536,6 +6536,15 @@
   </summary>
 </histogram>
 
+<histogram name="Kiosk.WebApp.InstallError" enum="WebAppInstallResultCode"
+    expires_after="2022-10-01">
+  <owner>yixie@chromium.org</owner>
+  <owner>chromeos-kiosk-eng@google.com</owner>
+  <summary>
+    Records the reason for Web App install error in a Web Kiosk.
+  </summary>
+</histogram>
+
 <histogram name="Launch.FlagsAtStartup" enum="LoginCustomFlags"
     expires_after="never">
 <!-- expires-never: monitors use of all flags. -->
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a4aa27547..b560b5fd 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -14,15 +14,15 @@
         },
         "mac": {
             "hash": "11dfbe81619f06e020f64fd90d2a610cfb5a04ac",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/f4da613d6229df0d6a017448de05d54e7218d58d/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/0d039f99a217e8f872d5dcd8210347fcac684c19/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "c0397e87456ad6c6a7aa0133e5b81c97adbab4ab",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac_arm64/cefb3e0ec3a0580c996f801e854fe02963c03d5c/trace_processor_shell"
         },
         "linux": {
-            "hash": "35df8db1c380d4fc82da571c2cbff5429a501a7e",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f4da613d6229df0d6a017448de05d54e7218d58d/trace_processor_shell"
+            "hash": "03e3ffc9d24b6e13868272bde240984cf22a6994",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/da3eb18b5c1cdaab87292750c2c3dc4138b58874/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index d52b4dd..c4121ea7 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -82,6 +82,7 @@
 crbug.com/879833 loading.desktop/Walgreens_warm [ Skip ]
 crbug.com/921428 [ chromeos ] loading.desktop/TheVerge_cold [ Skip ]
 crbug.com/921428 [ chromeos ] loading.desktop/TheVerge_warm [ Skip ]
+crbug.com/1312923 [ win10 ] loading.desktop/Kenh14_warm [ Skip ]
 
 # Benchmark: loading.mobile
 crbug.com/656861 loading.mobile/G1 [ Skip ]
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index 51eba0eb..253d30a 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -508,15 +508,6 @@
       is_active_ ? ui::kColorNotificationBackgroundActive
                  : ui::kColorNotificationBackgroundInactive);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (ash::features::IsNotificationsRefreshEnabled()) {
-    // These are the same colors provided by AshColorProvider.
-    // See ash/style/ash_color_provider.cc
-    background_color = is_active_ ? SkColorSetA(SK_ColorBLACK, 0x0D)
-                                  : SkColorSetA(SK_ColorWHITE, 0x1A);
-  }
-#endif
-
   SetBackground(views::CreateBackgroundFromPainter(
       std::make_unique<NotificationBackgroundPainter>(
           top_radius_, bottom_radius_, background_color)));
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h
index 6294edf..3381dce 100644
--- a/ui/message_center/views/message_view.h
+++ b/ui/message_center/views/message_view.h
@@ -217,6 +217,9 @@
   // Changes the background color and schedules a paint.
   virtual void SetDrawBackgroundAsActive(bool active);
 
+  // Updates the background painter using the themed background color and radii.
+  virtual void UpdateBackgroundPainter();
+
   void UpdateControlButtonsVisibilityWithNotification(
       const Notification& notification);
 
@@ -243,9 +246,6 @@
   // Returns if the control buttons should be shown.
   bool ShouldShowControlButtons() const;
 
-  // Updates the background painter using the themed background color and radii.
-  void UpdateBackgroundPainter();
-
   void UpdateNestedBorder();
 
   std::string notification_id_;
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc
index f7975dc..1f6ccc4 100644
--- a/ui/ozone/public/ozone_switches.cc
+++ b/ui/ozone/public/ozone_switches.cc
@@ -26,11 +26,6 @@
 // See https://crbug.com/1220274
 const char kUseWaylandExplicitGrab[] = "use-wayland-explicit-grab";
 
-// Use normal priority (ThreadPriority::NORMAL) for Wayland event watcher
-// thread ("wayland-fd"). See https://crbug.com/1262133
-const char kUseWaylandNormalThreadPriority[] =
-    "use-wayland-normal-thread-priority";
-
 // Disable explicit DMA-fences
 const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
 
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h
index 0ab7661..ca63b0d2 100644
--- a/ui/ozone/public/ozone_switches.h
+++ b/ui/ozone/public/ozone_switches.h
@@ -23,9 +23,6 @@
 
 COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kUseWaylandExplicitGrab[];
 
-COMPONENT_EXPORT(OZONE_SWITCHES)
-extern const char kUseWaylandNormalThreadPriority[];
-
 COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kDisableExplicitDmaFences[];
 
 COMPONENT_EXPORT(OZONE_SWITCHES)