diff --git a/DEPS b/DEPS
index 8c0819c1..dd9f399 100644
--- a/DEPS
+++ b/DEPS
@@ -241,7 +241,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:a8b84fba102daff5bf5e65975dcc0887da7ab62a',
+  'luci_go': 'git_revision:f6b5518e872364f59bb17dd5a967270b38331b84',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -299,15 +299,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '99a797d497fe983e63f3fbfe064c270973298b45',
+  'skia_revision': 'db586ebd77a2acd3cadb4427dfc5dda7729849fb',
   # 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': '8256e3617c00bc91937853bf038cb30462b383fb',
+  'v8_revision': 'a41a2e4571ec8847c7042d01f9d0afe2accb9730',
   # 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': 'b6cc575478e27c62500f43192aa602737b2f6257',
+  'angle_revision': '92f26ce30581b0f5494b8e14ad77d2c6109f0c3a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -350,7 +350,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '27b2cd4101dfcf7d03904204e078b2de84cce8c4',
+  'freetype_revision': '4c3916e901ac88243321b7518c023dc8c51a7586',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -382,7 +382,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': '798cf20faa5996e26d4e1d36f63f6cb0c021d173',
+  'devtools_frontend_revision': '6ba2c8dee3953aefca236edf58d668d474363e6a',
   # 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.
@@ -422,7 +422,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '5b50790d707908a3deb2afec01651a4fc80b28b5',
+  'dawn_revision': '132be477374b7e23acfc6e11b3e160af1e92de79',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -458,7 +458,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': '07072d38ddc54369486d61f0c60cd137d51dc37a',
+  'cros_components_revision': '9fec96ff3e3d20b57e8ceb217efcfab081622dd4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -760,7 +760,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '885a039347998fb1c765b87509e85b3e2dde5321',
+    '4ae23a125384eae81dda4f96ec0c083cb50ab03b',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -789,7 +789,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '6ca84fe7c8f22132695ec92a7e069a580261aac9',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '6f2bbf825c4a513ac0842557a1186f75cdbe2954',
       'condition': 'checkout_ios',
   },
 
@@ -1202,13 +1202,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2ec2918216c61bdb2f4ab48bb0e761d0e2fc48fb',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cd2395991f80b66fb3549730c92de7b9fe11e649',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'b648d0eaa0ab60d049f8742673eb8a33aff29384',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'b87886e8c087e3da7f7154550e524bf337d1af1a',
     'condition': 'checkout_src_internal',
   },
 
@@ -1862,7 +1862,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '6c8361e98f1daba65902f5e2fc1297893ac14b67',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'fd4ddd1fb19b5e9678664cd0054d19a841e10220',
+    Var('webrtc_git') + '/src.git' + '@' + 'd8361ee6b7ab231ede75ff0528329b1153d60888',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1889,7 +1889,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': '3N5ZxQ_Vej0R4hY-5r_rn2ks2HvZNKWZVPOF0IQsct8C',
+          'version': 'B3ETgoPk2gSY8aomIHMZNixKf63RvZDpuJhnZFelSl0C',
         },
       ],
       'dep_type': 'cipd',
@@ -1899,7 +1899,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'xY20wb1hbHLqq-NcBK8qSSRjGi_hK-_YmBT4Njm78kUC',
+          'version': '4l2ybbWBlKkcGXEi6Z6MOOanDzH2X3JuwuKW3hlLcq8C',
         },
       ],
       'dep_type': 'cipd',
@@ -1921,7 +1921,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': '0EJSEBdXC6iNCrOFINQw_EHpFey1tj_zSrlCX0N5zxcC',
+          'version': 'xe7SkOafMEH4PikK8N-7c1Wt2rPEVLnTG10xrBCAExYC',
         },
       ],
       'dep_type': 'cipd',
@@ -1932,7 +1932,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6fd469560dc257381fae48a8d9842b04384a8581',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9b7fe0dc2e17093b985ab596871c82fcb3b9acb7',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 332576f2..5e506c0 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1046,6 +1046,8 @@
     "style/option_button_base.h",
     "style/option_button_group.cc",
     "style/option_button_group.h",
+    "style/pagination_view.cc",
+    "style/pagination_view.h",
     "style/pill_button.cc",
     "style/pill_button.h",
     "style/radio_button.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 1a70065..af55c90 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -6215,6 +6215,14 @@
       <message name="IDS_ASH_CURTAIN_DESCRIPTION" desc="Detailed description displayed to inform the user a remote admin has taken control of the ChromeOs device.">
         Your administrator has logged in to look into an issue. You can continue to use the device after the administrator gives the control back to you.
       </message>
-    </messages>
-  </release>
+
+      <!-- pagination view -->
+      <message name="IDS_ASH_PAGINATION_LEFT_ARROW_TOOLTIP" desc="The tooltip text used for pagination left arrow button." >
+        Previous page
+      </message>
+      <message name="IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP" desc="The tooltip text used for pagination right arrow button." >
+        Next page
+      </message>
+     </messages>
+    </release>
 </grit>
diff --git a/ash/ash_strings_grd/IDS_ASH_PAGINATION_LEFT_ARROW_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PAGINATION_LEFT_ARROW_TOOLTIP.png.sha1
new file mode 100644
index 0000000..0da1a8a
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_PAGINATION_LEFT_ARROW_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+4b33cdfc18ffd36296e619dbb131ced8850cc55e
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP.png.sha1
new file mode 100644
index 0000000..10814c6
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+40cb88bb7e2ff881d9b45372b4e8026cdde6ff56
\ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 8811b9b7..199a46c 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1019,6 +1019,9 @@
 // native screen capture tool.
 BASE_FEATURE(kGifRecording, "GifRecording", base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables the displaying of animated gifs in ash.
+BASE_FEATURE(kGifRendering, "GifRendering", base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables a Files banner about Google One offer.
 BASE_FEATURE(kGoogleOneOfferFilesBanner,
              "GoogleOneOfferFilesBanner",
@@ -2574,6 +2577,10 @@
   return base::FeatureList::IsEnabled(kGifRecording);
 }
 
+bool IsGifRenderingEnabled() {
+  return base::FeatureList::IsEnabled(kGifRendering);
+}
+
 bool AreGlanceablesEnabled() {
   return base::FeatureList::IsEnabled(kGlanceables);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 0b3442d0..68925de 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -294,6 +294,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kGesturePropertiesDBusService);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGifRecording);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kGifRendering);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kGoogleOneOfferFilesBanner);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -695,6 +696,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGalleryAppPdfEditNotificationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGameDashboardEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGifRecordingEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGifRenderingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool AreGlanceablesEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHibernateEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideArcMediaNotificationsEnabled();
diff --git a/ash/metrics/ui_metrics_recorder.cc b/ash/metrics/ui_metrics_recorder.cc
index 2863cd10..a133ef6 100644
--- a/ash/metrics/ui_metrics_recorder.cc
+++ b/ash/metrics/ui_metrics_recorder.cc
@@ -43,29 +43,28 @@
 
   DCHECK_EQ(State::kDuringLogin, state_);
   state_ = State::kInSession;
+  user_session_start_time_ = base::TimeTicks::Now();
 }
 
 void UiMetricsRecorder::ReportPercentDroppedFramesInOneSecondWindow(
-    double percentage) {
+    double percent) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   UMA_HISTOGRAM_PERCENTAGE("Ash.Smoothness.PercentDroppedFrames_1sWindow",
-                           percentage);
+                           percent);
 
   switch (state_) {
     case State::kBeforeLogin:
       UMA_HISTOGRAM_PERCENTAGE(
-          "Ash.Smoothness.PercentDroppedFrames_1sWindow.BeforeLogin",
-          percentage);
+          "Ash.Smoothness.PercentDroppedFrames_1sWindow.BeforeLogin", percent);
       break;
     case State::kDuringLogin:
       UMA_HISTOGRAM_PERCENTAGE(
-          "Ash.Smoothness.PercentDroppedFrames_1sWindow.DuringLogin",
-          percentage);
+          "Ash.Smoothness.PercentDroppedFrames_1sWindow.DuringLogin", percent);
       break;
     case State::kInSession:
       UMA_HISTOGRAM_PERCENTAGE(
-          "Ash.Smoothness.PercentDroppedFrames_1sWindow.InSession", percentage);
+          "Ash.Smoothness.PercentDroppedFrames_1sWindow.InSession", percent);
       break;
   }
 
@@ -74,16 +73,16 @@
   // take is as the signal that the user session is full initialized and set
   // `session_initialized_` flag.
   if (check_session_init_) {
-    // Threshold for `percentage` to be considered good.
+    // Threshold for `percent` to be considered good.
     constexpr double kGoodAdf = 20;
-    if (!last_good_dropped_frame_time_.has_value() && percentage <= kGoodAdf) {
+    if (!last_good_dropped_frame_time_.has_value() && percent <= kGoodAdf) {
       last_good_dropped_frame_time_ = base::TimeTicks::Now();
     } else if (last_good_dropped_frame_time_.has_value() &&
-               percentage > kGoodAdf) {
+               percent > kGoodAdf) {
       last_good_dropped_frame_time_.reset();
     }
 
-    // Minimum duration for `percentage` to stay in good before the user session
+    // Minimum duration for `percent` to stay in good before the user session
     // is considered as fully initialized.
     constexpr base::TimeDelta kMinGoodAdfDuration = base::Seconds(5);
     if (last_good_dropped_frame_time_.has_value()) {
@@ -101,7 +100,22 @@
 
   if (session_initialized_) {
     UMA_HISTOGRAM_PERCENTAGE(
-        "Ash.Smoothness.PercentDroppedFrames_1sWindow.InSession2", percentage);
+        "Ash.Smoothness.PercentDroppedFrames_1sWindow.InSession2", percent);
+  }
+}
+
+void UiMetricsRecorder::ReportPercentDroppedFramesInOneSecondWindow2(
+    double percent) {
+  UMA_HISTOGRAM_PERCENTAGE("Ash.Smoothness.PercentDroppedFrames_1sWindow2",
+                           percent);
+
+  // Time to exclude from user session to be reported under "InSession" metric.
+  constexpr base::TimeDelta chopped_user_session_time = base::Minutes(1);
+  if (user_session_start_time_ &&
+      base::TimeTicks::Now() - user_session_start_time_.value() >=
+          chopped_user_session_time) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "Ash.Smoothness.PercentDroppedFrames_1sWindow2.InSession", percent);
   }
 }
 
diff --git a/ash/metrics/ui_metrics_recorder.h b/ash/metrics/ui_metrics_recorder.h
index e13d8021..a634a19 100644
--- a/ash/metrics/ui_metrics_recorder.h
+++ b/ash/metrics/ui_metrics_recorder.h
@@ -30,7 +30,8 @@
   void OnPostLoginAnimationFinish();
 
   // cc::CustomMetricRecorder:
-  void ReportPercentDroppedFramesInOneSecondWindow(double percentage) override;
+  void ReportPercentDroppedFramesInOneSecondWindow(double percent) override;
+  void ReportPercentDroppedFramesInOneSecondWindow2(double percent) override;
   void ReportEventLatency(
       std::vector<cc::EventLatencyTracker::LatencyData> latencies) override;
 
@@ -52,7 +53,10 @@
   // observing good ADF for 5s during login.
   bool session_initialized_ = false;
 
+  // Login time and session start time of the primary user.
   absl::optional<base::TimeTicks> user_logged_in_time_;
+  absl::optional<base::TimeTicks> user_session_start_time_;
+
   absl::optional<base::TimeTicks> last_good_dropped_frame_time_;
 };
 
diff --git a/ash/public/cpp/input_device_settings_controller.h b/ash/public/cpp/input_device_settings_controller.h
index ee47bef1..66a8a5e 100644
--- a/ash/public/cpp/input_device_settings_controller.h
+++ b/ash/public/cpp/input_device_settings_controller.h
@@ -5,6 +5,8 @@
 #ifndef ASH_PUBLIC_CPP_INPUT_DEVICE_SETTINGS_CONTROLLER_H_
 #define ASH_PUBLIC_CPP_INPUT_DEVICE_SETTINGS_CONTROLLER_H_
 
+#include <vector>
+
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/mojom/input_device_settings.mojom-forward.h"
 #include "base/observer_list_types.h"
@@ -13,7 +15,6 @@
 
 // An interface, implemented by ash, which allows chrome to retrieve and update
 // input device settings.
-// TODO(dpad): Add equivalent methods for Touchpads/Mice/Pointing Stick.
 class ASH_PUBLIC_EXPORT InputDeviceSettingsController {
  public:
   using DeviceId = uint32_t;
@@ -22,15 +23,34 @@
    public:
     virtual void OnKeyboardConnected(const mojom::Keyboard& keyboard) {}
     virtual void OnKeyboardDisconnected(const mojom::Keyboard& keyboard) {}
-    virtual void OnKeyboardSettingsUpdated(
-        DeviceId id,
-        const mojom::KeyboardSettings& settings) {}
+    virtual void OnKeyboardSettingsUpdated(const mojom::Keyboard& keyboard) {}
+
+    virtual void OnTouchpadConnected(const mojom::Touchpad& touchpad) {}
+    virtual void OnTouchpadDisconnected(const mojom::Touchpad& touchpad) {}
+    virtual void OnTouchpadSettingsUpdated(const mojom::Touchpad& touchpad) {}
+
+    virtual void OnMouseConnected(const mojom::Mouse& mouse) {}
+    virtual void OnMouseDisconnected(const mojom::Mouse& mouse) {}
+    virtual void OnMouseSettingsUpdated(const mojom::Mouse& mouse) {}
+
+    virtual void OnPointingStickConnected(
+        const mojom::PointingStick& pointing_stick) {}
+    virtual void OnPointingStickDisconnected(
+        const mojom::PointingStick& pointing_stick) {}
+    virtual void OnPointingStickSettingsUpdated(
+        const mojom::PointingStick& pointing_stick) {}
   };
 
   static InputDeviceSettingsController* Get();
 
   // Returns a list of currently connected keyboards and their settings.
   virtual std::vector<mojom::KeyboardPtr> GetConnectedKeyboards() = 0;
+  // Returns a list of currently connected touchpads and their settings.
+  virtual std::vector<mojom::TouchpadPtr> GetConnectedTouchpads() = 0;
+  // Returns a list of currently connected mice and their settings.
+  virtual std::vector<mojom::MousePtr> GetConnectedMice() = 0;
+  // Returns a list of currently connected pointing sticks and their settings.
+  virtual std::vector<mojom::PointingStickPtr> GetConnectedPointingSticks() = 0;
 
   // Configure the settings for keyboard of |id| with the provided |settings|.
   virtual void SetKeyboardSettings(DeviceId id,
diff --git a/ash/public/cpp/wallpaper/wallpaper_controller.h b/ash/public/cpp/wallpaper/wallpaper_controller.h
index 832c94a..0c2d73f 100644
--- a/ash/public/cpp/wallpaper/wallpaper_controller.h
+++ b/ash/public/cpp/wallpaper/wallpaper_controller.h
@@ -256,7 +256,8 @@
 
   // Removes all of the user's saved wallpapers and related info.
   // |account_id|: The user's account id.
-  virtual void RemoveUserWallpaper(const AccountId& account_id) = 0;
+  virtual void RemoveUserWallpaper(const AccountId& account_id,
+                                   base::OnceClosure on_removed) = 0;
 
   // Removes all of the user's saved wallpapers and related info if the
   // wallpaper was set by |SetPolicyWallpaper|. In addition, sets the user's
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 7d5285a..56f7d8e 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -482,6 +482,8 @@
     "unified_menu_locale.icon",
     "unified_menu_lock.icon",
     "unified_menu_managed.icon",
+    "unified_menu_mic_noise_cancel_high.icon",
+    "unified_menu_mic_noise_cancel_off.icon",
     "unified_menu_more.icon",
     "unified_menu_nearby_share_not_visible.icon",
     "unified_menu_nearby_share_visible.icon",
diff --git a/ash/resources/vector_icons/unified_menu_mic_noise_cancel_high.icon b/ash/resources/vector_icons/unified_menu_mic_noise_cancel_high.icon
new file mode 100644
index 0000000..af0c70f7
--- /dev/null
+++ b/ash/resources/vector_icons/unified_menu_mic_noise_cancel_high.icon
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4.6f, 5.4f,
+CUBIC_TO, 7.13f, 7.93f, 7.13f, 12.06f, 4.6f, 14.59f,
+LINE_TO, 5.66f, 15.65f,
+CUBIC_TO, 8.78f, 12.53f, 8.78f, 7.46f, 5.66f, 4.34f,
+LINE_TO, 4.6f, 5.4f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 3.54f, 6.46f,
+LINE_TO, 2.48f, 7.52f,
+CUBIC_TO, 3.84f, 8.88f, 3.84f, 11.1f, 2.48f, 12.47f,
+LINE_TO, 3.54f, 13.53f,
+CUBIC_TO, 5.49f, 11.58f, 5.49f, 8.41f, 3.54f, 6.46f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 10.75f, 2,
+H_LINE_TO, 9.25f,
+V_LINE_TO, 18,
+H_LINE_TO, 10.75f,
+V_LINE_TO, 2,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 14, 9.25f,
+H_LINE_TO, 12.5f,
+V_LINE_TO, 10.75f,
+H_LINE_TO, 14,
+V_LINE_TO, 9.25f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 17, 9.25f,
+H_LINE_TO, 15.5f,
+V_LINE_TO, 10.75f,
+H_LINE_TO, 17,
+V_LINE_TO, 9.25f,
+CLOSE
diff --git a/ash/resources/vector_icons/unified_menu_mic_noise_cancel_off.icon b/ash/resources/vector_icons/unified_menu_mic_noise_cancel_off.icon
new file mode 100644
index 0000000..8a5f761
--- /dev/null
+++ b/ash/resources/vector_icons/unified_menu_mic_noise_cancel_off.icon
@@ -0,0 +1,48 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 14, 10.75f,
+V_LINE_TO, 9.25f,
+H_LINE_TO, 12.5f,
+V_LINE_TO, 10.38f,
+LINE_TO, 12.87f, 10.75f,
+H_LINE_TO, 14,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 17, 9.25f,
+H_LINE_TO, 15.5f,
+V_LINE_TO, 10.75f,
+H_LINE_TO, 17,
+V_LINE_TO, 9.25f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 3.54f, 6.46f,
+LINE_TO, 2.48f, 7.52f,
+CUBIC_TO, 3.84f, 8.88f, 3.84f, 11.11f, 2.48f, 12.47f,
+LINE_TO, 3.54f, 13.53f,
+CUBIC_TO, 5.49f, 11.58f, 5.49f, 8.41f, 3.54f, 6.46f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 10.75f, 2,
+H_LINE_TO, 9.25f,
+V_LINE_TO, 7.13f,
+LINE_TO, 10.75f, 8.63f,
+V_LINE_TO, 2,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 3.06f, 3.06f,
+LINE_TO, 2, 4.12f,
+LINE_TO, 6.3f, 8.41f,
+CUBIC_TO, 6.84f, 10.55f, 6.27f, 12.92f, 4.6f, 14.59f,
+LINE_TO, 5.66f, 15.65f,
+CUBIC_TO, 7.19f, 14.12f, 7.97f, 12.12f, 8, 10.11f,
+LINE_TO, 9.26f, 11.37f,
+V_LINE_TO, 18,
+H_LINE_TO, 10.76f,
+V_LINE_TO, 12.87f,
+LINE_TO, 15.89f, 18,
+LINE_TO, 16.95f, 16.94f,
+LINE_TO, 3.06f, 3.06f,
+CLOSE
diff --git a/ash/shelf/hotseat_widget.cc b/ash/shelf/hotseat_widget.cc
index 6fddd10..7c85738 100644
--- a/ash/shelf/hotseat_widget.cc
+++ b/ash/shelf/hotseat_widget.cc
@@ -913,12 +913,8 @@
   const gfx::Size hotseat_target_size =
       CalculateTargetBoundsSize(hotseat_target_state);
 
-  if (hotseat_target_state == HotseatState::kShownHomeLauncher) {
-    target_size_for_shown_state_ = hotseat_target_size;
-  } else {
-    target_size_for_shown_state_ =
-        CalculateTargetBoundsSize(HotseatState::kShownHomeLauncher);
-  }
+  target_size_for_shown_state_ =
+      CalculateTargetBoundsSize(HotseatState::kShownHomeLauncher);
 
   const gfx::Rect shelf_bounds = shelf_->shelf_widget()->GetTargetBounds();
   const gfx::Rect status_area_bounds =
diff --git a/ash/style/pagination_view.cc b/ash/style/pagination_view.cc
new file mode 100644
index 0000000..4fd3a21
--- /dev/null
+++ b/ash/style/pagination_view.cc
@@ -0,0 +1,585 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/style/pagination_view.h"
+
+#include "ash/public/cpp/pagination/pagination_model.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/style/style_util.h"
+#include "base/i18n/number_formatting.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/layout/box_layout_view.h"
+#include "ui/views/view_class_properties.h"
+
+namespace ash {
+
+namespace {
+
+// Attributes of arrow buttons.
+constexpr int kArrowButtonIconSize = 20;
+constexpr ui::ColorId kArrowButtonColorId = cros_tokens::kCrosSysSecondary;
+constexpr int kArrowIndicatorSpacing = 2;
+
+// Attributes of indicator.
+constexpr int kIndicatorButtonSize = 20;
+constexpr int kIndicatorRadius = 4;
+constexpr int kIndicatorStrokeWidth = 1;
+constexpr int kIndicatorSpacing = 2;
+constexpr ui::ColorId kIndicatorColorId = cros_tokens::kCrosSysPrimary;
+constexpr int kMaxNumVisibleIndicators = 5;
+
+// A structure holds the info needed by interpolation.
+template <typename T>
+struct InterpolationInterval {
+  // The start time and value.
+  double start_time;
+  T start_value;
+  // The end time and value.
+  double end_time;
+  T target_value;
+};
+
+// IndicatorButton:
+// A button with a hollow circle in the center.
+class IndicatorButton : public views::Button {
+ public:
+  METADATA_HEADER(IndicatorButton);
+
+  IndicatorButton(PressedCallback callback,
+                  const std::u16string& accessible_name)
+      : views::Button(callback) {
+    SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
+    SetAccessibleName(accessible_name);
+  }
+
+  IndicatorButton(const IndicatorButton&) = delete;
+  IndicatorButton& operator=(const IndicatorButton&) = delete;
+  ~IndicatorButton() override = default;
+
+  // Gets the bounds of the circle in the center.
+  gfx::Rect GetIndicatorBounds() const {
+    gfx::Rect indicator_bounds = bounds();
+    indicator_bounds.Inset(
+        gfx::Insets(0.5 * kIndicatorButtonSize - kIndicatorRadius));
+    return indicator_bounds;
+  }
+
+  // views::Button:
+  gfx::Size CalculatePreferredSize() const override {
+    return gfx::Size(kIndicatorButtonSize, kIndicatorButtonSize);
+  }
+
+  void PaintButtonContents(gfx::Canvas* canvas) override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setColor(GetColorProvider()->GetColor(kIndicatorColorId));
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kIndicatorStrokeWidth);
+    // Do inner stroke.
+    canvas->DrawCircle(GetLocalBounds().CenterPoint(),
+                       kIndicatorRadius - 0.5f * kIndicatorStrokeWidth, flags);
+  }
+};
+
+BEGIN_METADATA(IndicatorButton, views::Button)
+END_METADATA
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// PaginationView::SelectorDotView:
+// A solid circle that performs deformation with the pace of page transition.
+class PaginationView::SelectorDotView : public views::View {
+ public:
+  METADATA_HEADER(SelectorDotView);
+
+  using DeformInterval = InterpolationInterval<gfx::Rect>;
+
+  SelectorDotView() {
+    SetBackground(
+        StyleUtil::CreateThemedFullyRoundedRectBackground(kIndicatorColorId));
+    SetPaintToLayer();
+    layer()->SetFillsBoundsOpaquely(false);
+    // Set selector dot ignored by layout since it will follow selected
+    // indicator and deform on page transition.
+    SetProperty(views::kViewIgnoredByLayoutKey, true);
+  }
+
+  SelectorDotView(const SelectorDotView&) = delete;
+  SelectorDotView& operator=(const SelectorDotView&) = delete;
+  ~SelectorDotView() override = default;
+
+  // Adds a new deform interval.
+  void AddDeformInterval(DeformInterval interval) {
+    DCHECK_LT(interval.start_time, interval.end_time);
+    deform_intervals_.push_back(interval);
+    // Sort the intervals according to the start time in ascending order.
+    std::sort(
+        deform_intervals_.begin(), deform_intervals_.end(),
+        [](const DeformInterval& interval_1, const DeformInterval& interval_2) {
+          return interval_1.start_time < interval_2.start_time;
+        });
+  }
+
+  // Performs deformation according to the given progress within deform
+  // intervals.
+  void Deform(double progress) {
+    if (deform_intervals_.empty()) {
+      return;
+    }
+
+    auto iter = std::find_if(deform_intervals_.begin(), deform_intervals_.end(),
+                             [&](DeformInterval& interval) {
+                               return interval.start_time <= progress &&
+                                      interval.end_time >= progress;
+                             });
+
+    if (iter == deform_intervals_.end()) {
+      return;
+    }
+
+    // Get intermediate bounds by interpolating the origin and target bounds.
+    const gfx::Rect intermediate_bounds = gfx::Tween::RectValueBetween(
+        (progress - iter->start_time) / (iter->end_time - iter->start_time),
+        iter->start_value, iter->target_value);
+    SetBoundsRect(intermediate_bounds);
+  }
+
+  void ResetDeform(bool canceled) {
+    if (!deform_intervals_.empty()) {
+      SetBoundsRect(canceled ? deform_intervals_.front().start_value
+                             : deform_intervals_.back().target_value);
+    }
+    deform_intervals_.clear();
+  }
+
+  // Returns true if deformation is still in progress.
+  bool DeformingInProgress() const { return !deform_intervals_.empty(); }
+
+ private:
+  std::vector<DeformInterval> deform_intervals_;
+};
+
+BEGIN_METADATA(PaginationView, SelectorDotView, views::View)
+END_METADATA
+
+//------------------------------------------------------------------------------
+// PaginationView::IndicatorContainer:
+// The container of indicators. If the indicator to be selected is not visible,
+// the container will scroll with the pace of pagination transition.
+class PaginationView::IndicatorContainer : public views::BoxLayoutView {
+ public:
+  METADATA_HEADER(IndicatorContainer);
+
+  IndicatorContainer() {
+    SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kCenter);
+    SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kCenter);
+    SetBetweenChildSpacing(kIndicatorSpacing);
+  }
+
+  IndicatorContainer(const IndicatorContainer&) = delete;
+  IndicatorContainer& operator=(const IndicatorContainer&) = delete;
+  ~IndicatorContainer() override = default;
+
+  // Attaches an indicator to the end of container.
+  void PushIndicator(PaginationModel* model) {
+    const int page = buttons_.size();
+    // Since the selector dot will also be added in the container, we should use
+    // `AddChildViewAt` to ensure the indicator is in the expected position in
+    // the child views.
+    auto* indicator_button = AddChildViewAt(
+        std::make_unique<IndicatorButton>(
+            base::BindRepeating(
+                [](PaginationModel* model, int page, const ui::Event& event) {
+                  model->SelectPage(page, /*animate=*/true);
+                },
+                model, page),
+            l10n_util::GetStringFUTF16(
+                IDS_APP_LIST_PAGE_SWITCHER, base::FormatNumber(page + 1),
+                base::FormatNumber(model->total_pages()))),
+        page);
+    buttons_.emplace_back(indicator_button);
+  }
+
+  // Discards the indicator at the end of the container.
+  void PopIndicator() {
+    DCHECK(buttons_.size());
+    auto indicator_button = buttons_.back();
+    buttons_.pop_back();
+    RemoveChildViewT(indicator_button);
+  }
+
+  // Gets indicator corresponding to the given page.
+  IndicatorButton* GetIndicatorByPage(int page) {
+    DCHECK_GE(page, 0);
+    DCHECK_LT(page, static_cast<int>(buttons_.size()));
+    return buttons_[page].get();
+  }
+
+  // Sets up scrolling if an invisible page is selected.
+  void StartScroll(int start_page, int target_page) {
+    // Scroll the indicator container by the distance of a indicator button size
+    // plus button spacing to reveal the next/previous indicator.
+    // TODO(zxdan): settings bounds at each step will cause repainting which is
+    // expensive. However, using transform sometimes makes the stroke of
+    // indicator circle become thicker. Will investigate the cause latter.
+    const bool left = start_page < target_page;
+    const int start_page_offset =
+        left ? kMaxNumVisibleIndicators - start_page - 1 : -start_page;
+    const int target_page_offset =
+        left ? kMaxNumVisibleIndicators - target_page - 1 : -target_page;
+    const int scroll_unit = kIndicatorButtonSize + kIndicatorSpacing;
+    scroll_interval_ = {0.0, start_page_offset * scroll_unit, 1.0,
+                        target_page_offset * scroll_unit};
+  }
+
+  // Scrolls the indicator container according to the given progress value.
+  void Scroll(double progress) {
+    if (!scroll_interval_) {
+      return;
+    }
+
+    // Interpolate the scroll interval to get current container bounds.
+    SetX(gfx::Tween::IntValueBetween(progress, scroll_interval_->start_value,
+                                     scroll_interval_->target_value));
+  }
+
+  void ResetScroll(bool canceled) {
+    if (scroll_interval_) {
+      SetX(canceled ? scroll_interval_->start_value
+                    : scroll_interval_->target_value);
+    }
+    scroll_interval_ = absl::nullopt;
+  }
+
+  // Returns true if the scrolling is in progress.
+  bool ScrollingInProgress() { return !!scroll_interval_; }
+
+ private:
+  std::vector<base::raw_ptr<IndicatorButton>> buttons_;
+  absl::optional<InterpolationInterval<int>> scroll_interval_;
+};
+
+BEGIN_METADATA(PaginationView, IndicatorContainer, views::BoxLayoutView)
+END_METADATA
+
+//------------------------------------------------------------------------------
+// PaginationView:
+PaginationView::PaginationView(PaginationModel* model)
+    : model_(model),
+      indicator_scroll_view_(
+          AddChildView(std::make_unique<views::ScrollView>())),
+      indicator_container_(indicator_scroll_view_->SetContents(
+          std::make_unique<IndicatorContainer>())) {
+  DCHECK(model_);
+
+  model_observation_.Observe(model_.get());
+
+  // The scroll view does not accept scroll event.
+  indicator_scroll_view_->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
+  indicator_scroll_view_->SetVerticalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
+
+  TotalPagesChanged(0, model_->total_pages());
+
+  if (model_->is_valid_page(model_->selected_page())) {
+    CreateSelectorDot();
+  }
+}
+
+PaginationView::~PaginationView() = default;
+
+gfx::Size PaginationView::CalculatePreferredSize() const {
+  const int total_pages = model_->total_pages();
+  const int visible_num = std::min(total_pages, kMaxNumVisibleIndicators);
+  const int container_width = visible_num * kIndicatorButtonSize +
+                              (visible_num - 1) * kIndicatorSpacing;
+
+  // If the number of total pages does not exceed visible maximum, only show
+  // indicator container.
+  if (total_pages <= visible_num) {
+    return gfx::Size(container_width, kIndicatorButtonSize);
+  }
+
+  // Otherwise, show indicator container and arrow buttons.
+  return gfx::Size(
+      container_width + 2 * (kArrowButtonIconSize + kArrowIndicatorSpacing),
+      kIndicatorButtonSize);
+}
+
+void PaginationView::Layout() {
+  int offset_x = 0;
+  // Set the left arrow button if exists.
+  if (left_arrow_button_) {
+    left_arrow_button_->SetBounds(offset_x, 0, kArrowButtonIconSize,
+                                  kArrowButtonIconSize);
+    offset_x += left_arrow_button_->width() + kArrowIndicatorSpacing;
+  }
+
+  // Set the indicator container.
+  indicator_container_->SizeToPreferredSize();
+  const int visible_num =
+      std::min(model_->total_pages(), kMaxNumVisibleIndicators);
+  indicator_scroll_view_->SetBounds(offset_x, 0,
+                                    visible_num * kIndicatorButtonSize +
+                                        (visible_num - 1) * kIndicatorSpacing,
+                                    kIndicatorButtonSize);
+
+  offset_x += indicator_scroll_view_->width() + kArrowIndicatorSpacing;
+
+  // Set the right arrow button if exists.
+  if (right_arrow_button_) {
+    right_arrow_button_->SetBounds(offset_x, 0, kIndicatorButtonSize,
+                                   kIndicatorButtonSize);
+  }
+
+  // Update arrow button visibility and selector dot position.
+  UpdateArrowButtonsVisiblity();
+  UpdateSelectorDot();
+}
+
+void PaginationView::CreateArrowButtons() {
+  for (bool left : {true, false}) {
+    auto arrow_button = std::make_unique<views::ImageButton>(
+        base::BindRepeating(&PaginationView::OnArrowButtonPressed,
+                            base::Unretained(this), left));
+
+    arrow_button->SetImageModel(
+        views::ImageButton::ButtonState::STATE_NORMAL,
+        ui::ImageModel::FromVectorIcon(
+            left ? kOverflowShelfLeftIcon : kOverflowShelfRightIcon,
+            kArrowButtonColorId, kArrowButtonIconSize));
+
+    if (left) {
+      arrow_button->SetTooltipText(
+          l10n_util::GetStringUTF16(IDS_ASH_PAGINATION_LEFT_ARROW_TOOLTIP));
+      left_arrow_button_ = AddChildView(std::move(arrow_button));
+    } else {
+      arrow_button->SetTooltipText(
+          l10n_util::GetStringUTF16(IDS_ASH_PAGINATION_RIGHT_ARROW_TOOLTIP));
+      right_arrow_button_ = AddChildView(std::move(arrow_button));
+    }
+  }
+}
+
+void PaginationView::RemoveArrowButtons() {
+  RemoveChildViewT(left_arrow_button_);
+  left_arrow_button_ = nullptr;
+
+  RemoveChildViewT(right_arrow_button_);
+  right_arrow_button_ = nullptr;
+}
+
+void PaginationView::UpdateArrowButtonsVisiblity() {
+  // If the first page indicator is visible, hide the left arrow button.
+  if (left_arrow_button_) {
+    left_arrow_button_->SetVisible(!IsIndicatorVisible(0));
+  }
+
+  // If the last page indicator is visible, hide the right arrow button.
+  if (right_arrow_button_) {
+    right_arrow_button_->SetVisible(
+        !IsIndicatorVisible(model_->total_pages() - 1));
+  }
+}
+
+void PaginationView::OnArrowButtonPressed(bool left, const ui::Event& event) {
+  const int page_offset = left ? -1 : 1;
+  model_->SelectPage(model_->selected_page() + page_offset, /*animate=*/true);
+}
+
+void PaginationView::MaybeSetUpScroll() {
+  const int current_page = model_->selected_page();
+  const int target_page = model_->transition().target_page;
+  if (!model_->is_valid_page(current_page) ||
+      !model_->is_valid_page(target_page)) {
+    return;
+  }
+
+  // If the target page indicator is not in visible area, scroll the container.
+  if (!IsIndicatorVisible(target_page)) {
+    indicator_container_->StartScroll(current_page, target_page);
+  }
+}
+
+void PaginationView::CreateSelectorDot() {
+  if (selector_dot_) {
+    return;
+  }
+
+  selector_dot_ =
+      indicator_container_->AddChildView(std::make_unique<SelectorDotView>());
+  UpdateSelectorDot();
+}
+
+void PaginationView::RemoveSelectorDot() {
+  if (!selector_dot_) {
+    return;
+  }
+
+  indicator_container_->RemoveChildViewT(selector_dot_);
+  selector_dot_ = nullptr;
+}
+
+void PaginationView::UpdateSelectorDot() {
+  if (!selector_dot_) {
+    return;
+  }
+
+  // Move the selector dot to the position of selected page indicator if the
+  // selector dot is not deforming.
+  const int selected_page = model_->selected_page();
+  DCHECK(model_->is_valid_page(selected_page));
+  if (!selector_dot_->DeformingInProgress()) {
+    selector_dot_->SetBoundsRect(
+        indicator_container_->GetIndicatorByPage(selected_page)
+            ->GetIndicatorBounds());
+  }
+}
+
+void PaginationView::SetUpSelectorDotDeformation() {
+  DCHECK(!selector_dot_->DeformingInProgress());
+
+  const int current_page = model_->selected_page();
+  const int target_page = model_->transition().target_page;
+
+  if (!model_->is_valid_page(current_page) ||
+      !model_->is_valid_page(target_page)) {
+    return;
+  }
+
+  const gfx::Rect current_bounds =
+      indicator_container_->GetIndicatorByPage(current_page)
+          ->GetIndicatorBounds();
+  const gfx::Rect target_bounds =
+      indicator_container_->GetIndicatorByPage(target_page)
+          ->GetIndicatorBounds();
+  // If moves to a neighbor page, the selector dot will first be stretched into
+  // a pill shape until it connects the current indicator to the target
+  // indicator, and then shrink back to a circle at the target indicator
+  // position.
+  if (std::abs(target_page - current_page) == 1) {
+    const gfx::Rect intermediate_bounds =
+        gfx::UnionRects(current_bounds, target_bounds);
+    selector_dot_->AddDeformInterval(
+        {0.0, current_bounds, 0.5, intermediate_bounds});
+    selector_dot_->AddDeformInterval(
+        {0.5, intermediate_bounds, 1.0, target_bounds});
+    return;
+  }
+
+  // If jumps across multiple pages, the selector dot will first shrink at the
+  // current indicator position, and then expand at the target indicator
+  // position.
+  selector_dot_->AddDeformInterval(
+      {0.0, current_bounds, 0.5,
+       gfx::Rect(current_bounds.CenterPoint(), gfx::Size())});
+  selector_dot_->AddDeformInterval(
+      {0.5, gfx::Rect(target_bounds.CenterPoint(), gfx::Size()), 1.0,
+       target_bounds});
+}
+
+bool PaginationView::IsIndicatorVisible(int page) const {
+  // Check if the indicator is in the visible rect of the scroll view.
+  return indicator_scroll_view_->GetVisibleRect().Contains(
+      indicator_container_->GetIndicatorByPage(page)->bounds());
+}
+
+void PaginationView::SelectedPageChanged(int old_selected, int new_selected) {
+  // Update selector dot position and arrow buttons visibility.
+  if (model_->is_valid_page(new_selected)) {
+    if (!selector_dot_) {
+      CreateSelectorDot();
+    } else {
+      // Finish and reset ongoing deformation.
+      selector_dot_->ResetDeform(/*canceled=*/false);
+    }
+  } else {
+    RemoveSelectorDot();
+  }
+
+  // Finish and reset ongoing indicator container scrolling.
+  if (indicator_container_->ScrollingInProgress()) {
+    indicator_container_->ResetScroll(/*canceled=*/false);
+    UpdateArrowButtonsVisiblity();
+  }
+}
+
+void PaginationView::TotalPagesChanged(int previous_page_count,
+                                       int new_page_count) {
+  if (previous_page_count < new_page_count) {
+    // Add more indicators at the end of container.
+    for (int i = previous_page_count; i < new_page_count; i++) {
+      indicator_container_->PushIndicator(model_.get());
+    }
+
+    // Add arrow buttons if the number of total pages exceeds the visible
+    // maximum.
+    if (previous_page_count <= kMaxNumVisibleIndicators &&
+        new_page_count > kMaxNumVisibleIndicators) {
+      CreateArrowButtons();
+    }
+  } else {
+    // Remove indicators from the end of the container.
+    for (int i = previous_page_count; i > new_page_count; i--) {
+      indicator_container_->PopIndicator();
+    }
+
+    // Remove arrow buttons if the number of total pages does not exceed the
+    // visible maximum.
+    if (previous_page_count > kMaxNumVisibleIndicators &&
+        new_page_count <= kMaxNumVisibleIndicators) {
+      RemoveArrowButtons();
+    }
+
+    // Remove the selector dot if there is no pages.
+    if (new_page_count == 0) {
+      RemoveSelectorDot();
+    }
+  }
+
+  Layout();
+}
+
+void PaginationView::TransitionChanged() {
+  // If there is no transition, reset and cancel current selector dot
+  // deformation and indicator container scrolling.
+  if (!model_->has_transition()) {
+    selector_dot_->ResetDeform(/*canceled=*/true);
+    indicator_container_->ResetScroll(/*canceled=*/true);
+    return;
+  }
+
+  const double progress = model_->transition().progress;
+
+  // Scroll the indicator container if needed.
+  if (!indicator_container_->ScrollingInProgress()) {
+    MaybeSetUpScroll();
+  }
+  indicator_container_->Scroll(progress);
+
+  // Deform the selector dot.
+  if (!selector_dot_->DeformingInProgress()) {
+    SetUpSelectorDotDeformation();
+  }
+  // Deform the selector dot.
+  selector_dot_->Deform(progress);
+}
+
+BEGIN_METADATA(PaginationView, views::View)
+END_METADATA
+}  // namespace ash
diff --git a/ash/style/pagination_view.h b/ash/style/pagination_view.h
new file mode 100644
index 0000000..df44fb64
--- /dev/null
+++ b/ash/style/pagination_view.h
@@ -0,0 +1,106 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_STYLE_PAGINATION_VIEW_H_
+#define ASH_STYLE_PAGINATION_VIEW_H_
+
+#include "ash/ash_export.h"
+#include "ash/public/cpp/pagination/pagination_model_observer.h"
+#include "base/scoped_observation.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/view.h"
+
+namespace views {
+class ImageButton;
+class ScrollView;
+}  // namespace views
+
+namespace ash {
+
+class PaginationModel;
+
+// PaginationView is used to paginate the UI surface with multiple pages of
+// contents. It has as many indicators as pages. Pressing an indicator will jump
+// to the corresponding page. There is a maximum number of visible indicators.
+// If the number of total pages exceeds the visible maximum, two arrow-shaped
+// overflow buttons will be shown on both sides. The arrow buttons can also
+// control pagination. The layout of a pagination view with arrow buttons is
+// like below:
+//                   +---+---+---+---+---+---+---+
+//                   | < | o | o | o | o | o | > |
+//                   +-|-+---+---+-|-+---+---+-|-+
+//            left arrow button    |    right arrow button
+//                             indicator
+//
+// When a page is selected, a selector dot (a solid circle) will move to the
+// corresponding indicator. The selector dot has two motion effects:
+// - If moves to a neighbor page, the selector dot will first be stretched into
+// a pill shape until it connects the current indicator to the target indicator,
+// and then shrink back to a circle at the target indicator position.
+// - If jumps across multiple pages, the selector dot will first shrink at the
+// current indicator position, and then expand at the target indicator position.
+class ASH_EXPORT PaginationView : public views::View,
+                                  public PaginationModelObserver {
+ public:
+  METADATA_HEADER(PaginationView);
+
+  // A paginaition view only binds with one pagination model, but the pagination
+  // model may control multiple views. Therefore, pagination model should
+  // outlive the pagination view.
+  explicit PaginationView(PaginationModel* model);
+  PaginationView(const PaginationView&) = delete;
+  PaginationView& operator=(const PaginationView*) = delete;
+  ~PaginationView() override;
+
+  // views::View:
+  gfx::Size CalculatePreferredSize() const override;
+  void Layout() override;
+
+ private:
+  // A filled circle with pagination motion effects.
+  class SelectorDotView;
+  // The container of indicators.
+  class IndicatorContainer;
+
+  void CreateArrowButtons();
+  void RemoveArrowButtons();
+  void UpdateArrowButtonsVisiblity();
+  void OnArrowButtonPressed(bool left, const ui::Event& event);
+  void MaybeSetUpScroll();
+
+  void CreateSelectorDot();
+  void RemoveSelectorDot();
+  void UpdateSelectorDot();
+  void SetUpSelectorDotDeformation();
+
+  // Returns true if the indicator button corresponding to the given page is
+  // currently visible.
+  bool IsIndicatorVisible(int page) const;
+
+  // PaginationModelObserver:
+  void TotalPagesChanged(int previous_page_count, int new_page_count) override;
+  void SelectedPageChanged(int old_selected, int new_selected) override;
+  void TransitionChanged() override;
+
+  base::raw_ptr<PaginationModel> const model_;
+
+  // The scroll view with an indicator container as its contents. The scroll
+  // view is owned by this and the container is owned by the scroll view.
+  base::raw_ptr<views::ScrollView> indicator_scroll_view_ = nullptr;
+  base::raw_ptr<IndicatorContainer> indicator_container_ = nullptr;
+
+  // The selector dot view which is owned by this.
+  base::raw_ptr<SelectorDotView> selector_dot_ = nullptr;
+
+  // The arrow buttons owned by this.
+  base::raw_ptr<views::ImageButton> left_arrow_button_ = nullptr;
+  base::raw_ptr<views::ImageButton> right_arrow_button_ = nullptr;
+
+  base::ScopedObservation<PaginationModel, PaginationModelObserver>
+      model_observation_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_STYLE_PAGINATION_VIEW_H_
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc
index 60045510..22b08a4d 100644
--- a/ash/system/audio/audio_detailed_view.cc
+++ b/ash/system/audio/audio_detailed_view.cc
@@ -41,6 +41,7 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/vector_icon_types.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/toggle_button.h"
 #include "ui/views/controls/focus_ring.h"
@@ -61,6 +62,11 @@
 constexpr auto kLiveCaptionContainerMargins = gfx::Insets::TLBR(0, 0, 8, 0);
 constexpr auto kToggleButtonRowLabelPadding = gfx::Insets::TLBR(16, 0, 15, 0);
 constexpr auto kToggleButtonRowViewPadding = gfx::Insets::TLBR(0, 56, 8, 0);
+constexpr auto kQsToggleButtonRowViewPadding = gfx::Insets::VH(0, 32);
+constexpr auto kQsToggleButtonRowPreferredSize = gfx::Size(0, 32);
+constexpr auto kQsToggleButtonRowLabelPadding = gfx::Insets::VH(8, 12);
+constexpr auto kQsToggleButtonRowMargins = gfx::Insets::VH(4, 0);
+constexpr auto kSeparatorMargins = gfx::Insets::TLBR(4, 32, 12, 32);
 constexpr auto kTextRowInsets = gfx::Insets::VH(8, 24);
 constexpr auto kDevicesNameViewPreferredSize = gfx::Size(0, 44);
 constexpr auto kDevicesTriViewInsets = gfx::Insets::TLBR(0, 24, 0, 32);
@@ -317,7 +323,7 @@
       live_caption_enabled ? kUnifiedMenuLiveCaptionIcon
                            : kUnifiedMenuLiveCaptionOffIcon,
       cros_tokens::kCrosSysOnSurface, kQsSliderIconSize));
-  toggle_icon_ = toggle_icon.get();
+  live_caption_icon_ = toggle_icon.get();
   // TODO(b/262281693): Update the font and color for `live_caption_view_` text.
   live_caption_view_->AddViewAndLabel(
       std::move(toggle_icon),
@@ -338,7 +344,7 @@
                 IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP);
   toggle->SetTooltipText(l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP, toggle_tooltip));
-  toggle_button_ = toggle.get();
+  live_caption_button_ = toggle.get();
   live_caption_view_->AddRightView(toggle.release());
 
   // Allows the row to be taller than a typical tray menu item.
@@ -396,6 +402,65 @@
   return noise_cancellation_toggle_row;
 }
 
+std::unique_ptr<HoverHighlightView>
+AudioDetailedView::CreateQsNoiseCancellationToggleRow(
+    const AudioDevice& device) {
+  bool noise_cancellation_state =
+      CrasAudioHandler::Get()->GetNoiseCancellationState();
+
+  auto noise_cancellation_view =
+      std::make_unique<HoverHighlightView>(/*listener=*/this);
+
+  auto toggle_icon =
+      std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon(
+          noise_cancellation_state ? kUnifiedMenuMicNoiseCancelHighIcon
+                                   : kUnifiedMenuMicNoiseCancelOffIcon,
+          cros_tokens::kCrosSysOnSurface, kQsSliderIconSize));
+  noise_cancellation_icon_ = toggle_icon.get();
+
+  noise_cancellation_view->AddViewAndLabel(
+      std::move(toggle_icon),
+      l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_AUDIO_INPUT_NOISE_CANCELLATION));
+
+  // Create a non-clickable non-focusable toggle button on the right. The events
+  // and focus behavior should be handled by `noise_cancellation_view_` instead.
+  auto toggle =
+      std::make_unique<TrayToggleButton>(views::Button::PressedCallback(),
+                                         /*accessible_name_id=*/absl::nullopt,
+                                         /*use_empty_border=*/true);
+  toggle->SetIsOn(noise_cancellation_state);
+  toggle->SetCanProcessEventsWithinSubtree(false);
+  toggle->SetFocusBehavior(views::View::FocusBehavior::NEVER);
+  // Ignore the toggle for accessibility.
+  auto& view_accessibility = toggle->GetViewAccessibility();
+  view_accessibility.OverrideIsLeaf(true);
+  view_accessibility.OverrideIsIgnored(true);
+  noise_cancellation_button_ = toggle.get();
+  noise_cancellation_view->AddRightView(toggle.release());
+
+  noise_cancellation_view->tri_view()->SetInsets(kQsToggleButtonRowViewPadding);
+  noise_cancellation_view->tri_view()->SetContainerLayout(
+      TriView::Container::CENTER, std::make_unique<views::BoxLayout>(
+                                      views::BoxLayout::Orientation::kVertical,
+                                      kQsToggleButtonRowLabelPadding));
+  noise_cancellation_view->SetPreferredSize(kQsToggleButtonRowPreferredSize);
+  noise_cancellation_view->SetProperty(views::kMarginsKey,
+                                       kQsToggleButtonRowMargins);
+  noise_cancellation_view->SetAccessibilityState(
+      noise_cancellation_state
+          ? HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX
+          : HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
+
+  // This is only used for testing.
+  if (g_noise_cancellation_toggle_callback) {
+    g_noise_cancellation_toggle_callback->Run(device.id,
+                                              noise_cancellation_view.get());
+  }
+
+  return noise_cancellation_view;
+}
+
 void AudioDetailedView::MaybeShowSodaMessage(speech::LanguageCode language_code,
                                              std::u16string message) {
   AccessibilityControllerImpl* controller =
@@ -421,6 +486,13 @@
   const bool new_state = !audio_handler->GetNoiseCancellationState();
   audio_handler->SetNoiseCancellationState(new_state);
   audio_handler->SetNoiseCancellationPrefState(new_state);
+  if (features::IsQsRevampEnabled()) {
+    noise_cancellation_icon_->SetImage(ui::ImageModel::FromVectorIcon(
+        new_state ? kUnifiedMenuMicNoiseCancelHighIcon
+                  : kUnifiedMenuMicNoiseCancelOffIcon,
+        cros_tokens::kCrosSysOnSurface, kQsSliderIconSize));
+    noise_cancellation_button_->SetIsOn(new_state);
+  }
 }
 
 void AudioDetailedView::ToggleLiveCaptionState() {
@@ -431,7 +503,7 @@
 }
 
 void AudioDetailedView::UpdateLiveCaptionView(bool is_enabled) {
-  toggle_icon_->SetImage(ui::ImageModel::FromVectorIcon(
+  live_caption_icon_->SetImage(ui::ImageModel::FromVectorIcon(
       is_enabled ? kUnifiedMenuLiveCaptionIcon : kUnifiedMenuLiveCaptionOffIcon,
       cros_tokens::kCrosSysOnSurface, kQsSliderIconSize));
 
@@ -441,12 +513,12 @@
                        IDS_ASH_STATUS_TRAY_LIVE_CAPTION_ENABLED_STATE_TOOLTIP)
                  : l10n_util::GetStringUTF16(
                        IDS_ASH_STATUS_TRAY_LIVE_CAPTION_DISABLED_STATE_TOOLTIP);
-  toggle_button_->SetTooltipText(l10n_util::GetStringFUTF16(
+  live_caption_button_->SetTooltipText(l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_LIVE_CAPTION_TOGGLE_TOOLTIP, toggle_tooltip));
 
   // Ensures the toggle button is in sync with the current Live Caption state.
-  if (toggle_button_->GetIsOn() != is_enabled) {
-    toggle_button_->SetIsOn(is_enabled);
+  if (live_caption_button_->GetIsOn() != is_enabled) {
+    live_caption_button_->SetIsOn(is_enabled);
   }
 
   InvalidateLayout();
@@ -587,8 +659,22 @@
     if (audio_handler->GetPrimaryActiveInputNode() == device.id &&
         audio_handler->noise_cancellation_supported() &&
         (device.audio_effect & cras::EFFECT_TYPE_NOISE_CANCELLATION)) {
-      container->AddChildView(
-          AudioDetailedView::CreateNoiseCancellationToggleRow(device));
+      if (features::IsQsRevampEnabled()) {
+        noise_cancellation_view_ = container->AddChildView(
+            AudioDetailedView::CreateQsNoiseCancellationToggleRow(device));
+
+        // Adds a `Separator` if this input device is not the last one.
+        if (&device != &input_devices_.back()) {
+          auto* separator =
+              container->AddChildView(std::make_unique<views::Separator>());
+          separator->SetColorId(cros_tokens::kCrosSysSeparator);
+          separator->SetOrientation(views::Separator::Orientation::kHorizontal);
+          separator->SetProperty(views::kMarginsKey, kSeparatorMargins);
+        }
+      } else {
+        container->AddChildView(
+            AudioDetailedView::CreateNoiseCancellationToggleRow(device));
+      }
     }
 
     if (!features::IsQsRevampEnabled()) {
@@ -607,6 +693,11 @@
     return;
   }
 
+  if (noise_cancellation_view_ && view == noise_cancellation_view_) {
+    OnInputNoiseCancellationTogglePressed();
+    return;
+  }
+
   AudioDeviceMap::iterator iter = device_map_.find(view);
   if (iter == device_map_.end())
     return;
diff --git a/ash/system/audio/audio_detailed_view.h b/ash/system/audio/audio_detailed_view.h
index 28463b7..2763002 100644
--- a/ash/system/audio/audio_detailed_view.h
+++ b/ash/system/audio/audio_detailed_view.h
@@ -11,6 +11,7 @@
 
 #include "ash/accessibility/accessibility_observer.h"
 #include "ash/ash_export.h"
+#include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/tray_detailed_view.h"
 #include "chromeos/ash/components/audio/audio_device.h"
 #include "components/soda/soda_installer.h"
@@ -77,6 +78,11 @@
   std::unique_ptr<views::View> CreateNoiseCancellationToggleRow(
       const AudioDevice& device);
 
+  // For QsRevamp: Creates the noise cancellation toggle row in the input
+  // subsection.
+  std::unique_ptr<HoverHighlightView> CreateQsNoiseCancellationToggleRow(
+      const AudioDevice& device);
+
   // Sets the subtext for `live_caption_view_` based on whether live caption has
   // updated if this feature is enabled and visible in tray.
   void MaybeShowSodaMessage(speech::LanguageCode language_code,
@@ -119,8 +125,11 @@
   uint64_t focused_device_id_ = -1;
   // Owned by the views hierarchy.
   HoverHighlightView* live_caption_view_ = nullptr;
-  views::ImageView* toggle_icon_ = nullptr;
-  views::ToggleButton* toggle_button_ = nullptr;
+  views::ImageView* live_caption_icon_ = nullptr;
+  views::ToggleButton* live_caption_button_ = nullptr;
+  HoverHighlightView* noise_cancellation_view_ = nullptr;
+  views::ImageView* noise_cancellation_icon_ = nullptr;
+  views::ToggleButton* noise_cancellation_button_ = nullptr;
 
   base::WeakPtrFactory<AudioDetailedView> weak_factory_{this};
 };
diff --git a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
index 16b9108..5bfb535 100644
--- a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
+++ b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
@@ -200,7 +200,13 @@
   }
 
   void ToggleLiveCaption() {
-    audio_detailed_view()->HandleViewClicked(live_caption_view());
+    GetAudioDetailedView()->HandleViewClicked(live_caption_view());
+  }
+
+  // Toggles the noise cancellation button for QsRevamp.
+  void ToggleNoiseCancellation() {
+    GetAudioDetailedView()->HandleViewClicked(
+        GetAudioDetailedView()->noise_cancellation_view_);
   }
 
  protected:
@@ -208,7 +214,7 @@
     return FakeCrasAudioClient::Get();
   }
 
-  AudioDetailedView* audio_detailed_view() {
+  AudioDetailedView* GetAudioDetailedView() {
     if (!audio_detailed_view_) {
       audio_detailed_view_ = base::WrapUnique(static_cast<AudioDetailedView*>(
           audio_detailed_view_controller_->CreateView().release()));
@@ -217,7 +223,11 @@
   }
 
   HoverHighlightView* live_caption_view() {
-    return audio_detailed_view()->live_caption_view_;
+    return GetAudioDetailedView()->live_caption_view_;
+  }
+
+  views::ToggleButton* noise_cancellation_button() {
+    return GetAudioDetailedView()->noise_cancellation_button_;
   }
 
   bool live_caption_enabled() {
@@ -420,13 +430,18 @@
   cras_audio_handler_->SwitchToDevice(internal_mic, true,
                                       CrasAudioHandler::ACTIVATE_BY_USER);
 
-  std::unique_ptr<views::View> view =
-      audio_detailed_view_controller_->CreateView();
+  // If `audio_detailed_view_` doesn't exist, this getter method will create the
+  // view first.
+  GetAudioDetailedView();
   EXPECT_EQ(1u, toggles_map_.size());
 
-  views::ToggleButton* toggle =
-      (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1];
-  EXPECT_TRUE(toggle->GetIsOn());
+  if (!IsQsRevampEnabled()) {
+    views::ToggleButton* toggle =
+        (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1];
+    EXPECT_TRUE(toggle->GetIsOn());
+  } else {
+    EXPECT_TRUE(noise_cancellation_button());
+  }
 }
 
 TEST_P(UnifiedAudioDetailedViewControllerTest,
@@ -442,31 +457,47 @@
   cras_audio_handler_->SwitchToDevice(internal_mic, true,
                                       CrasAudioHandler::ACTIVATE_BY_USER);
 
-  std::unique_ptr<views::View> view =
-      audio_detailed_view_controller_->CreateView();
+  // If `audio_detailed_view_` doesn't exist, this getter method will create the
+  // view first.
+  GetAudioDetailedView();
   EXPECT_EQ(1u, toggles_map_.size());
 
-  views::ToggleButton* toggle =
-      (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1];
-  auto widget = CreateFramelessTestWidget();
-  widget->SetContentsView(toggle);
+  if (!IsQsRevampEnabled()) {
+    views::ToggleButton* toggle =
+        (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1];
+    auto widget = CreateFramelessTestWidget();
+    widget->SetContentsView(toggle);
 
-  // The toggle loaded the pref correctly.
-  EXPECT_FALSE(toggle->GetIsOn());
-  EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+    // The toggle loaded the pref correctly.
+    EXPECT_FALSE(toggle->GetIsOn());
+    EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+    ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::PointF(), gfx::PointF(),
+                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                         ui::EF_NONE);
 
-  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::PointF(), gfx::PointF(),
-                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                       ui::EF_NONE);
+    // Flipping the toggle.
+    views::test::ButtonTestApi(toggle).NotifyClick(press);
+    // The new state of the toggle must be saved to the prefs.
+    EXPECT_TRUE(audio_pref_handler_->GetNoiseCancellationState());
 
-  // Flipping the toggle.
-  views::test::ButtonTestApi(toggle).NotifyClick(press);
-  // The new state of the toggle must be saved to the prefs.
-  EXPECT_TRUE(audio_pref_handler_->GetNoiseCancellationState());
+    // Flipping back and checking the prefs again.
+    views::test::ButtonTestApi(toggle).NotifyClick(press);
+    EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+  } else {
+    auto widget = CreateFramelessTestWidget();
+    widget->SetContentsView(noise_cancellation_button());
 
-  // Flipping back and checking the prefs again.
-  views::test::ButtonTestApi(toggle).NotifyClick(press);
-  EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+    // The toggle loaded the pref correctly.
+    EXPECT_FALSE(noise_cancellation_button()->GetIsOn());
+    EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+
+    // For QsRevamp, the entire row of `noise_cancellation_view_` is clickable.
+    ToggleNoiseCancellation();
+    EXPECT_TRUE(audio_pref_handler_->GetNoiseCancellationState());
+
+    ToggleNoiseCancellation();
+    EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState());
+  }
 }
 
 TEST_P(UnifiedAudioDetailedViewControllerTest,
diff --git a/ash/system/input_device_settings/input_device_notifier.cc b/ash/system/input_device_settings/input_device_notifier.cc
index 9c9251d..19c11fb 100644
--- a/ash/system/input_device_settings/input_device_notifier.cc
+++ b/ash/system/input_device_settings/input_device_notifier.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/system/input_device_settings/input_device_notifier.h"
+
 #include "ash/public/cpp/input_device_settings_controller.h"
 #include "ash/public/mojom/input_device_settings.mojom.h"
 #include "base/containers/flat_map.h"
@@ -119,8 +120,32 @@
   return ui::DeviceDataManager::GetInstance()->GetKeyboardDevices();
 }
 
+template <>
+std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::TouchpadPtr>::GetUpdatedDeviceList() {
+  return ui::DeviceDataManager::GetInstance()->GetTouchpadDevices();
+}
+
+template <>
+std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::MousePtr>::GetUpdatedDeviceList() {
+  return ui::DeviceDataManager::GetInstance()->GetMouseDevices();
+}
+
+template <>
+std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::PointingStickPtr>::GetUpdatedDeviceList() {
+  return ui::DeviceDataManager::GetInstance()->GetPointingStickDevices();
+}
+
 // Explicit instantiations for each device type.
 template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
     InputDeviceNotifier<mojom::KeyboardPtr>;
+template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::TouchpadPtr>;
+template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::MousePtr>;
+template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::PointingStickPtr>;
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_notifier.h b/ash/system/input_device_settings/input_device_notifier.h
index ee3e48d..d0bb480 100644
--- a/ash/system/input_device_settings/input_device_notifier.h
+++ b/ash/system/input_device_settings/input_device_notifier.h
@@ -58,9 +58,24 @@
 template <>
 ASH_EXPORT std::vector<ui::InputDevice>
 InputDeviceNotifier<mojom::KeyboardPtr>::GetUpdatedDeviceList();
+template <>
+ASH_EXPORT std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::TouchpadPtr>::GetUpdatedDeviceList();
+template <>
+ASH_EXPORT std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::MousePtr>::GetUpdatedDeviceList();
+template <>
+ASH_EXPORT std::vector<ui::InputDevice>
+InputDeviceNotifier<mojom::PointingStickPtr>::GetUpdatedDeviceList();
 
 extern template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
     InputDeviceNotifier<mojom::KeyboardPtr>;
+extern template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::TouchpadPtr>;
+extern template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::MousePtr>;
+extern template class EXPORT_TEMPLATE_DECLARE(ASH_EXPORT)
+    InputDeviceNotifier<mojom::PointingStickPtr>;
 
 }  // namespace ash
 
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
index 5971086..cd3983d 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -8,9 +8,11 @@
 #include <memory>
 #include <vector>
 
+#include "ash/public/cpp/input_device_settings_controller.h"
 #include "ash/public/mojom/input_device_settings.mojom.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_notifier.h"
 #include "ash/system/input_device_settings/input_device_settings_pref_names.h"
 #include "ash/system/input_device_settings/input_device_settings_utils.h"
 #include "ash/system/input_device_settings/pref_handlers/keyboard_pref_handler_impl.h"
@@ -32,6 +34,34 @@
   mojom_keyboard->device_key = BuildDeviceKey(keyboard);
   return mojom_keyboard;
 }
+
+mojom::MousePtr BuildMojomMouse(const ui::InputDevice& mouse) {
+  // TODO(dpad): Fully initialize the objects.
+  mojom::MousePtr mojom_mouse = mojom::Mouse::New();
+  mojom_mouse->id = mouse.id;
+  mojom_mouse->name = mouse.name;
+  mojom_mouse->device_key = BuildDeviceKey(mouse);
+  return mojom_mouse;
+}
+
+mojom::TouchpadPtr BuildMojomTouchpad(const ui::InputDevice& touchpad) {
+  // TODO(dpad): Fully initialize the objects.
+  mojom::TouchpadPtr mojom_touchpad = mojom::Touchpad::New();
+  mojom_touchpad->id = touchpad.id;
+  mojom_touchpad->name = touchpad.name;
+  mojom_touchpad->device_key = BuildDeviceKey(touchpad);
+  return mojom_touchpad;
+}
+
+mojom::PointingStickPtr BuildMojomPointingStick(
+    const ui::InputDevice& touchpad) {
+  // TODO(dpad): Fully initialize the objects.
+  mojom::PointingStickPtr mojom_pointing_stick = mojom::PointingStick::New();
+  mojom_pointing_stick->id = touchpad.id;
+  mojom_pointing_stick->name = touchpad.name;
+  mojom_pointing_stick->device_key = BuildDeviceKey(touchpad);
+  return mojom_pointing_stick;
+}
 }  // namespace
 
 InputDeviceSettingsControllerImpl::InputDeviceSettingsControllerImpl()
@@ -55,15 +85,28 @@
           base::BindRepeating(
               &InputDeviceSettingsControllerImpl::OnKeyboardListUpdated,
               base::Unretained(this)));
+  mouse_notifier_ = std::make_unique<InputDeviceNotifier<mojom::MousePtr>>(
+      &mice_, base::BindRepeating(
+                  &InputDeviceSettingsControllerImpl::OnMouseListUpdated,
+                  base::Unretained(this)));
+  touchpad_notifier_ =
+      std::make_unique<InputDeviceNotifier<mojom::TouchpadPtr>>(
+          &touchpads_,
+          base::BindRepeating(
+              &InputDeviceSettingsControllerImpl::OnTouchpadListUpdated,
+              base::Unretained(this)));
+  pointing_stick_notifier_ =
+      std::make_unique<InputDeviceNotifier<mojom::PointingStickPtr>>(
+          &pointing_sticks_,
+          base::BindRepeating(
+              &InputDeviceSettingsControllerImpl::OnPointingStickListUpdated,
+              base::Unretained(this)));
 }
 
 InputDeviceSettingsControllerImpl::~InputDeviceSettingsControllerImpl() {
   if (features::IsInputDeviceSettingsSplitEnabled()) {
     Shell::Get()->session_controller()->RemoveObserver(this);
   }
-  // Manually reset `keyboard_notifier_` to avoid any race conditions between
-  // `keyboard_notifier_` and `keyboards_`.
-  keyboard_notifier_.reset();
 }
 
 void InputDeviceSettingsControllerImpl::RegisterProfilePrefs(
@@ -93,6 +136,42 @@
   return keyboard_vector;
 }
 
+std::vector<mojom::TouchpadPtr>
+InputDeviceSettingsControllerImpl::GetConnectedTouchpads() {
+  std::vector<mojom::TouchpadPtr> mouse_vector;
+  mouse_vector.reserve(touchpads_.size());
+
+  for (const auto& [_, touchpad] : touchpads_) {
+    mouse_vector.push_back(touchpad->Clone());
+  }
+
+  return mouse_vector;
+}
+
+std::vector<mojom::MousePtr>
+InputDeviceSettingsControllerImpl::GetConnectedMice() {
+  std::vector<mojom::MousePtr> mouse_vector;
+  mouse_vector.reserve(mice_.size());
+
+  for (const auto& [_, mouse] : mice_) {
+    mouse_vector.push_back(mouse->Clone());
+  }
+
+  return mouse_vector;
+}
+
+std::vector<mojom::PointingStickPtr>
+InputDeviceSettingsControllerImpl::GetConnectedPointingSticks() {
+  std::vector<mojom::PointingStickPtr> pointing_stick_vector;
+  pointing_stick_vector.reserve(mice_.size());
+
+  for (const auto& [_, pointing_stick] : pointing_sticks_) {
+    pointing_stick_vector.push_back(pointing_stick->Clone());
+  }
+
+  return pointing_stick_vector;
+}
+
 // TODO(dpad): Implement updating of keyboard settings.
 void InputDeviceSettingsControllerImpl::SetKeyboardSettings(
     DeviceId id,
@@ -125,13 +204,64 @@
   }
 }
 
+void InputDeviceSettingsControllerImpl::DispatchTouchpadConnected(DeviceId id) {
+  DCHECK(base::Contains(touchpads_, id));
+  const auto& touchpad = *touchpads_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnTouchpadConnected(touchpad);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::DispatchTouchpadDisconnected(
+    DeviceId id) {
+  DCHECK(base::Contains(touchpads_, id));
+  const auto& touchpad = *touchpads_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnTouchpadDisconnected(touchpad);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::DispatchMouseConnected(DeviceId id) {
+  DCHECK(base::Contains(mice_, id));
+  const auto& mouse = *mice_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnMouseConnected(mouse);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::DispatchMouseDisconnected(DeviceId id) {
+  DCHECK(base::Contains(mice_, id));
+  const auto& mouse = *mice_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnMouseDisconnected(mouse);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::DispatchPointingStickConnected(
+    DeviceId id) {
+  DCHECK(base::Contains(pointing_sticks_, id));
+  const auto& pointing_stick = *pointing_sticks_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnPointingStickConnected(pointing_stick);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::DispatchPointingStickDisconnected(
+    DeviceId id) {
+  DCHECK(base::Contains(pointing_sticks_, id));
+  const auto& pointing_stick = *pointing_sticks_.at(id);
+  for (auto& observer : observers_) {
+    observer.OnPointingStickDisconnected(pointing_stick);
+  }
+}
+
 void InputDeviceSettingsControllerImpl::OnKeyboardListUpdated(
     std::vector<ui::InputDevice> keyboards_to_add,
     std::vector<DeviceId> keyboard_ids_to_remove) {
   for (const auto& keyboard : keyboards_to_add) {
     // Get initial settings from the pref manager and generate our local storage
     // of the device.
-    mojom::KeyboardPtr mojom_keyboard = BuildMojomKeyboard(keyboard);
+    auto mojom_keyboard = BuildMojomKeyboard(keyboard);
     if (active_pref_service_) {
       keyboard_pref_handler_->InitializeKeyboardSettings(active_pref_service_,
                                                          mojom_keyboard.get());
@@ -146,6 +276,52 @@
   }
 }
 
+void InputDeviceSettingsControllerImpl::OnTouchpadListUpdated(
+    std::vector<ui::InputDevice> touchpads_to_add,
+    std::vector<DeviceId> touchpad_ids_to_remove) {
+  for (const auto& touchpad : touchpads_to_add) {
+    auto mojom_touchpad = BuildMojomTouchpad(touchpad);
+    touchpads_.insert_or_assign(touchpad.id, std::move(mojom_touchpad));
+    DispatchTouchpadConnected(touchpad.id);
+  }
+
+  for (const auto id : touchpad_ids_to_remove) {
+    DispatchTouchpadDisconnected(id);
+    touchpads_.erase(id);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::OnMouseListUpdated(
+    std::vector<ui::InputDevice> mice_to_add,
+    std::vector<DeviceId> mouse_ids_to_remove) {
+  for (const auto& mouse : mice_to_add) {
+    auto mojom_mouse = BuildMojomMouse(mouse);
+    mice_.insert_or_assign(mouse.id, std::move(mojom_mouse));
+    DispatchMouseConnected(mouse.id);
+  }
+
+  for (const auto id : mouse_ids_to_remove) {
+    DispatchMouseDisconnected(id);
+    mice_.erase(id);
+  }
+}
+
+void InputDeviceSettingsControllerImpl::OnPointingStickListUpdated(
+    std::vector<ui::InputDevice> pointing_sticks_to_add,
+    std::vector<DeviceId> pointing_stick_ids_to_remove) {
+  for (const auto& pointing_stick : pointing_sticks_to_add) {
+    auto mojom_pointing_stick = BuildMojomPointingStick(pointing_stick);
+    pointing_sticks_.insert_or_assign(pointing_stick.id,
+                                      std::move(mojom_pointing_stick));
+    DispatchPointingStickConnected(pointing_stick.id);
+  }
+
+  for (const auto id : pointing_stick_ids_to_remove) {
+    DispatchPointingStickDisconnected(id);
+    pointing_sticks_.erase(id);
+  }
+}
+
 void InputDeviceSettingsControllerImpl::SetPrefHandlersForTesting(
     std::unique_ptr<KeyboardPrefHandler> keyboard_pref_handler) {
   keyboard_pref_handler_ = std::move(keyboard_pref_handler);
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.h b/ash/system/input_device_settings/input_device_settings_controller_impl.h
index 96b96230..ef616a7 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.h
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.h
@@ -5,6 +5,8 @@
 #ifndef ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_CONTROLLER_IMPL_H_
 #define ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_CONTROLLER_IMPL_H_
 
+#include <memory>
+
 #include "ash/ash_export.h"
 #include "ash/public/cpp/input_device_settings_controller.h"
 #include "ash/public/cpp/session/session_observer.h"
@@ -38,6 +40,9 @@
 
   // InputDeviceSettingsController:
   std::vector<mojom::KeyboardPtr> GetConnectedKeyboards() override;
+  std::vector<mojom::TouchpadPtr> GetConnectedTouchpads() override;
+  std::vector<mojom::MousePtr> GetConnectedMice() override;
+  std::vector<mojom::PointingStickPtr> GetConnectedPointingSticks() override;
   void SetKeyboardSettings(DeviceId id,
                            const mojom::KeyboardSettings& settings) override;
   void AddObserver(Observer* observer) override;
@@ -45,6 +50,13 @@
 
   void OnKeyboardListUpdated(std::vector<ui::InputDevice> keyboards_to_add,
                              std::vector<DeviceId> keyboard_ids_to_remove);
+  void OnTouchpadListUpdated(std::vector<ui::InputDevice> touchpads_to_add,
+                             std::vector<DeviceId> touchpad_ids_to_remove);
+  void OnMouseListUpdated(std::vector<ui::InputDevice> mice_to_add,
+                          std::vector<DeviceId> mouse_ids_to_remove);
+  void OnPointingStickListUpdated(
+      std::vector<ui::InputDevice> pointing_sticks_to_add,
+      std::vector<DeviceId> pointing_stick_ids_to_remove);
 
   // SessionObserver:
   void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
@@ -58,11 +70,31 @@
   void DispatchKeyboardConnected(DeviceId id);
   void DispatchKeyboardDisconnected(DeviceId id);
 
-  std::unique_ptr<KeyboardPrefHandler> keyboard_pref_handler_;
-  base::flat_map<DeviceId, mojom::KeyboardPtr> keyboards_;
+  void DispatchTouchpadConnected(DeviceId id);
+  void DispatchTouchpadDisconnected(DeviceId id);
+
+  void DispatchMouseConnected(DeviceId id);
+  void DispatchMouseDisconnected(DeviceId id);
+
+  void DispatchPointingStickConnected(DeviceId id);
+  void DispatchPointingStickDisconnected(DeviceId id);
+
   base::ObserverList<InputDeviceSettingsController::Observer> observers_;
 
+  std::unique_ptr<KeyboardPrefHandler> keyboard_pref_handler_;
+
+  base::flat_map<DeviceId, mojom::KeyboardPtr> keyboards_;
+  base::flat_map<DeviceId, mojom::TouchpadPtr> touchpads_;
+  base::flat_map<DeviceId, mojom::MousePtr> mice_;
+  base::flat_map<DeviceId, mojom::PointingStickPtr> pointing_sticks_;
+
+  // Notifiers must be declared after the `flat_map` objects as the notifiers
+  // depend on these objects.
   std::unique_ptr<InputDeviceNotifier<mojom::KeyboardPtr>> keyboard_notifier_;
+  std::unique_ptr<InputDeviceNotifier<mojom::TouchpadPtr>> touchpad_notifier_;
+  std::unique_ptr<InputDeviceNotifier<mojom::MousePtr>> mouse_notifier_;
+  std::unique_ptr<InputDeviceNotifier<mojom::PointingStickPtr>>
+      pointing_stick_notifier_;
 
   raw_ptr<PrefService> active_pref_service_ = nullptr;  // Not owned.
 };
diff --git a/ash/system/input_device_settings/input_device_tracker.cc b/ash/system/input_device_settings/input_device_tracker.cc
index 0d6446a..9dbd903 100644
--- a/ash/system/input_device_settings/input_device_tracker.cc
+++ b/ash/system/input_device_settings/input_device_tracker.cc
@@ -52,6 +52,20 @@
   RecordDeviceConnected(InputDeviceCategory::kKeyboard, keyboard.device_key);
 }
 
+void InputDeviceTracker::OnTouchpadConnected(const mojom::Touchpad& touchpad) {
+  RecordDeviceConnected(InputDeviceCategory::kTouchpad, touchpad.device_key);
+}
+
+void InputDeviceTracker::OnMouseConnected(const mojom::Mouse& mouse) {
+  RecordDeviceConnected(InputDeviceCategory::kMouse, mouse.device_key);
+}
+
+void InputDeviceTracker::OnPointingStickConnected(
+    const mojom::PointingStick& pointing_stick) {
+  RecordDeviceConnected(InputDeviceCategory::kPointingStick,
+                        pointing_stick.device_key);
+}
+
 void InputDeviceTracker::OnActiveUserPrefServiceChanged(
     PrefService* pref_service) {
   // When the user's `pref_service` changes, we need to re-initialize our
@@ -76,6 +90,25 @@
   for (const auto& keyboard : keyboards) {
     OnKeyboardConnected(*keyboard);
   }
+
+  const auto touchpads =
+      Shell::Get()->input_device_settings_controller()->GetConnectedTouchpads();
+  for (const auto& touchpad : touchpads) {
+    OnTouchpadConnected(*touchpad);
+  }
+
+  const auto mice =
+      Shell::Get()->input_device_settings_controller()->GetConnectedMice();
+  for (const auto& mouse : mice) {
+    OnMouseConnected(*mouse);
+  }
+
+  const auto pointing_sticks = Shell::Get()
+                                   ->input_device_settings_controller()
+                                   ->GetConnectedPointingSticks();
+  for (const auto& pointing_stick : pointing_sticks) {
+    OnPointingStickConnected(*pointing_stick);
+  }
 }
 
 void InputDeviceTracker::Init(PrefService* pref_service) {
diff --git a/ash/system/input_device_settings/input_device_tracker.h b/ash/system/input_device_settings/input_device_tracker.h
index d021dc8..e7f128e 100644
--- a/ash/system/input_device_settings/input_device_tracker.h
+++ b/ash/system/input_device_settings/input_device_tracker.h
@@ -42,6 +42,10 @@
 
   // InputDeviceSettingsController::Observer:
   void OnKeyboardConnected(const mojom::Keyboard& keyboard) override;
+  void OnTouchpadConnected(const mojom::Touchpad& touchpad) override;
+  void OnMouseConnected(const mojom::Mouse& mouse) override;
+  void OnPointingStickConnected(
+      const mojom::PointingStick& pointing_stick) override;
 
   // SessionObserver:
   void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
diff --git a/ash/system/input_device_settings/input_device_tracker_unittest.cc b/ash/system/input_device_settings/input_device_tracker_unittest.cc
index 0aa17c22..11b4092f 100644
--- a/ash/system/input_device_settings/input_device_tracker_unittest.cc
+++ b/ash/system/input_device_settings/input_device_tracker_unittest.cc
@@ -9,7 +9,6 @@
 #include "ash/system/input_device_settings/input_device_settings_pref_names.h"
 #include "ash/test/ash_test_base.h"
 #include "base/containers/contains.h"
-#include "base/notreached.h"
 #include "base/strings/string_piece_forward.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
@@ -65,8 +64,6 @@
     }
   }
 
-  // TODO(dpad): Implement for mouse/touchpad/pointing stick once mojo objects
-  // are available.
   void CallOnDeviceConnected(base::StringPiece device_key) {
     switch (category_) {
       case InputDeviceCategory::kKeyboard: {
@@ -75,10 +72,22 @@
         tracker_->OnKeyboardConnected(keyboard);
         break;
       }
-      case InputDeviceCategory::kMouse:
-      case InputDeviceCategory::kTouchpad:
+      case InputDeviceCategory::kMouse: {
+        mojom::Mouse mouse;
+        mouse.device_key = std::string(device_key);
+        tracker_->OnMouseConnected(mouse);
+        break;
+      }
+      case InputDeviceCategory::kTouchpad: {
+        mojom::Touchpad touchpad;
+        touchpad.device_key = std::string(device_key);
+        tracker_->OnTouchpadConnected(touchpad);
+        break;
+      }
       case InputDeviceCategory::kPointingStick:
-        NOTIMPLEMENTED();
+        mojom::PointingStick pointing_stick;
+        pointing_stick.device_key = std::string(device_key);
+        tracker_->OnPointingStickConnected(pointing_stick);
         break;
     }
   }
@@ -91,14 +100,18 @@
   base::StringPiece pref_path_;
 };
 
-// TODO(dpad): Add in mouse/touchpad/pointing stick once implemented.
 INSTANTIATE_TEST_SUITE_P(
     ,
     InputDeviceTrackerTest,
     testing::ValuesIn(
         std::vector<std::pair<InputDeviceCategory, base::StringPiece>>{
             {InputDeviceCategory::kKeyboard,
-             prefs::kKeyboardObservedDevicesPref}}));
+             prefs::kKeyboardObservedDevicesPref},
+            {InputDeviceCategory::kMouse, prefs::kMouseObservedDevicesPref},
+            {InputDeviceCategory::kTouchpad,
+             prefs::kTouchpadObservedDevicesPref},
+            {InputDeviceCategory::kPointingStick,
+             prefs::kPointingStickObservedDevicesPref}}));
 
 TEST_P(InputDeviceTrackerTest, RecordDevices) {
   CallOnDeviceConnected(kDeviceKey1);
@@ -145,9 +158,6 @@
 TEST_P(InputDeviceTrackerTest, WasDevicePreviouslyConnected) {
   EXPECT_FALSE(tracker_->WasDevicePreviouslyConnected(category_, kDeviceKey1));
   CallOnDeviceConnected(kDeviceKey1);
-  // Device key is present and added to the correct prf list.
-  EXPECT_FALSE(tracker_->WasDevicePreviouslyConnected(
-      InputDeviceCategory::kMouse, kDeviceKey1));
   EXPECT_TRUE(tracker_->WasDevicePreviouslyConnected(category_, kDeviceKey1));
 }
 
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index 6fd2f17..4133591f 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -1152,7 +1152,7 @@
 
   update_wallpaper_timer_.Stop();
 
-  RemoveUserWallpaper(account_id);
+  RemoveUserWallpaper(account_id, /*on_removed=*/base::DoNothing());
   if (!SetDefaultWallpaperInfo(account_id, base::Time::Now())) {
     LOG(ERROR) << "Initializing user wallpaper info fails. This should never "
                   "happen except in tests.";
@@ -1476,11 +1476,13 @@
   ReloadWallpaper(/*clear_cache=*/false);
 }
 
-void WallpaperControllerImpl::RemoveUserWallpaper(const AccountId& account_id) {
+void WallpaperControllerImpl::RemoveUserWallpaper(
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   if (base::Contains(wallpaper_cache_map_, account_id))
     wallpaper_cache_map_.erase(account_id);
   pref_manager_->RemoveUserWallpaperInfo(account_id);
-  RemoveUserWallpaperImpl(account_id);
+  RemoveUserWallpaperImpl(account_id, std::move(on_removed));
 }
 
 void WallpaperControllerImpl::RemovePolicyWallpaper(
@@ -1898,13 +1900,14 @@
 }
 
 void WallpaperControllerImpl::RemoveUserWallpaperImpl(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   if (wallpaper_controller_client_) {
     wallpaper_controller_client_->GetFilesId(
         account_id,
         base::BindOnce(
             &WallpaperControllerImpl::RemoveUserWallpaperImplWithFilesId,
-            weak_factory_.GetWeakPtr(), account_id));
+            weak_factory_.GetWeakPtr(), account_id, std::move(on_removed)));
   } else {
     LOG(ERROR) << "Failed to remove wallpaper. wallpaper_controller_client_ no "
                   "longer exists.";
@@ -1913,6 +1916,7 @@
 
 void WallpaperControllerImpl::RemoveUserWallpaperImplWithFilesId(
     const AccountId& account_id,
+    base::OnceClosure on_removed,
     const std::string& wallpaper_files_id) {
   if (wallpaper_files_id.empty())
     return;
@@ -1931,11 +1935,12 @@
   wallpaper_path = GetCustomWallpaperDir(kOriginalWallpaperSubDir);
   files_to_remove.push_back(wallpaper_path.Append(wallpaper_files_id));
 
-  base::ThreadPool::PostTask(
+  base::ThreadPool::PostTaskAndReply(
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&DeleteWallpaperInList, std::move(files_to_remove)));
+      base::BindOnce(&DeleteWallpaperInList, std::move(files_to_remove)),
+      std::move(on_removed));
 }
 
 void WallpaperControllerImpl::SetDefaultWallpaperImpl(
diff --git a/ash/wallpaper/wallpaper_controller_impl.h b/ash/wallpaper/wallpaper_controller_impl.h
index 4e38f76..c4ea896f 100644
--- a/ash/wallpaper/wallpaper_controller_impl.h
+++ b/ash/wallpaper/wallpaper_controller_impl.h
@@ -293,7 +293,8 @@
   void ShowOneShotWallpaper(const gfx::ImageSkia& image) override;
   void ShowAlwaysOnTopWallpaper(const base::FilePath& image_path) override;
   void RemoveAlwaysOnTopWallpaper() override;
-  void RemoveUserWallpaper(const AccountId& account_id) override;
+  void RemoveUserWallpaper(const AccountId& account_id,
+                           base::OnceClosure on_removed) override;
   void RemovePolicyWallpaper(const AccountId& account_id) override;
   void SetAnimationDuration(base::TimeDelta animation_duration) override;
   void OpenWallpaperPickerIfAllowed() override;
@@ -424,10 +425,12 @@
 
   // Implementation of |RemoveUserWallpaper|, which deletes |account_id|'s
   // custom wallpapers and directories.
-  void RemoveUserWallpaperImpl(const AccountId& account_id);
+  void RemoveUserWallpaperImpl(const AccountId& account_id,
+                               base::OnceClosure on_removed);
 
   void RemoveUserWallpaperImplWithFilesId(
       const AccountId& account_id,
+      base::OnceClosure on_removed,
       const std::string& wallpaper_files_id);
 
   // Implementation of |SetDefaultWallpaper|. Sets wallpaper to default if
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index ee25b4c..2095f11 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -2136,7 +2136,7 @@
   EXPECT_TRUE(controller_->GetPathFromCache(kAccountId1, &path));
 
   // Verify |RemoveUserWallpaper| clears wallpaper cache.
-  controller_->RemoveUserWallpaper(kAccountId1);
+  controller_->RemoveUserWallpaper(kAccountId1, base::DoNothing());
   EXPECT_FALSE(
       controller_->GetWallpaperFromCache(kAccountId1, &cached_wallpaper));
   EXPECT_FALSE(controller_->GetPathFromCache(kAccountId1, &path));
@@ -2425,7 +2425,7 @@
   EXPECT_TRUE(base::PathExists(small_wallpaper_path_2));
 
   // Simulate the removal of |kUser2|.
-  controller_->RemoveUserWallpaper(kAccountId2);
+  controller_->RemoveUserWallpaper(kAccountId2, base::DoNothing());
   // Wait until all files under the user's custom wallpaper directory are
   // removed.
   WaitUntilCustomWallpapersDeleted(kAccountId2);
@@ -2452,12 +2452,30 @@
                                    base::DoNothing());
 
   // Simulate the removal of |kUser2|.
-  controller_->RemoveUserWallpaper(kAccountId2);
+  controller_->RemoveUserWallpaper(kAccountId2,
+                                   /*on_removed=*/base::DoNothing());
 
   // Verify that the other user's wallpaper is not affected.
   EXPECT_TRUE(base::PathExists(small_wallpaper_path_1));
 }
 
+// Tests that when a user who has a default wallpaper is removed from the
+// device, the `on_remove` callback is called.
+TEST_F(WallpaperControllerTest, RemoveUserWallpaperOnRemoveCallbackCalled) {
+  SimulateUserLogin(kAccountId1);
+  controller_->SetDefaultWallpaper(kAccountId1, /*show_wallpaper=*/true,
+                                   /*callback=*/base::DoNothing());
+
+  base::test::TestFuture<void> remove_was_called;
+
+  // Simulate the removal of |kUser1|.
+  controller_->RemoveUserWallpaper(kAccountId1,
+                                   remove_was_called.GetCallback());
+
+  // Assert that the `on_remove` callback is called
+  ASSERT_TRUE(remove_was_called.Wait());
+}
+
 TEST_F(WallpaperControllerTest, IsActiveUserWallpaperControlledByPolicy) {
   SetBypassDecode();
   // Simulate the login screen. Verify that it returns false since there's no
diff --git a/ash/webui/personalization_app/resources/css/common.css b/ash/webui/personalization_app/resources/css/common.css
index 3a0cde7..435fbe9b 100644
--- a/ash/webui/personalization_app/resources/css/common.css
+++ b/ash/webui/personalization_app/resources/css/common.css
@@ -4,7 +4,9 @@
 
 /* #css_wrapper_metadata_start
  * #type=style
+ * #import=chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js
  * #import=chrome://resources/cr_elements/cr_shared_vars.css.js
+ * #include=cros-color-overrides
  * #css_wrapper_metadata_end */
 
 [hidden] {
@@ -269,6 +271,19 @@
   background-color: var(--cros-bg-color);
 }
 
+:host-context(body.jelly-enabled) .ambient-toggle-row-container {
+  border: none;
+}
+
+:host-context(body.jelly-enabled) .ambient-toggle-row {
+  margin: 0;
+}
+
+:host-context(body.jelly-enabled) .ambient-toggle-row > p {
+  color: var(--cros-text-color-secondary);
+  font: var(--cros-body-2-font);
+}
+
 :host-context([dir=rtl]) iron-icon[icon='cr:chevron-right'] {
   transform: scaleX(-1);
 }
diff --git a/ash/webui/personalization_app/resources/css/wallpaper.css b/ash/webui/personalization_app/resources/css/wallpaper.css
index 7f270dc..365fed9 100644
--- a/ash/webui/personalization_app/resources/css/wallpaper.css
+++ b/ash/webui/personalization_app/resources/css/wallpaper.css
@@ -4,9 +4,7 @@
 
 /* #css_wrapper_metadata_start
  * #type=style
- * import=chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js
- * import=chrome://resources/cr_elements/cr_shared_vars.css.js
- * import=chrome://resources/polymer/v3_0/paper-styles/color.js
+ * #import=chrome://resources/polymer/v3_0/paper-styles/color.js
  * #css_wrapper_metadata_end */
 
 main {
diff --git a/ash/webui/personalization_app/resources/index.html b/ash/webui/personalization_app/resources/index.html
index 48d7578..331370d 100644
--- a/ash/webui/personalization_app/resources/index.html
+++ b/ash/webui/personalization_app/resources/index.html
@@ -2,7 +2,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 <!DOCTYPE html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}" cros>
   <head>
     <title>$i18n{personalizationTitle}</title>
     <link rel="icon" type="image/png" sizes="192x192" href="/icon_192.png">
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html
index 3c5002b1..8a219f5 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html
@@ -96,6 +96,7 @@
     font: var(--cros-body-1-font);
     line-height: 1.5;
     margin-top: 56px;
+    position: relative;
     text-align: center;
     width: 128px;
   }
@@ -107,7 +108,6 @@
 
   ambient-zero-state-svg {
     position: absolute;
-    z-index: -10000;
   }
 
   #messageContainer.jelly-disabled cr-button {
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
index cc9553d..d1119f6 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
@@ -5,6 +5,15 @@
   #container {
     display: grid;
     grid-template-areas:
+      '. . content . .';
+    grid-template-columns: 1fr 16px minmax(568px, 920px) 16px 1fr;
+    grid-template-rows: minmax(0, 1fr);
+    height: 100%;
+    margin-block-end: 48px;
+  }
+  :host-context(body.jelly-enabled) #container {
+    display: grid;
+    grid-template-areas:
       '. . preview . .'
       '. . content . .';
     grid-template-columns: 1fr 16px minmax(568px, 920px) 16px 1fr;
@@ -19,11 +28,12 @@
   }
   toggle-row,
   #toggleRowPlaceholder {
-    grid-area: toggles;
     margin: 0 8px;
   }
-  ambient-zero-state {
-    grid-area: zeroState;
+  .ambient-toggle-label-placeholder {
+    height: 20px;
+    margin: 34px 0 2px 0;
+    width: 10%;
   }
   /* TODO(b/253470553): Remove after Ambient subpage UI change is released. */
   ambient-preview-small.jelly-disabled {
@@ -71,7 +81,6 @@
     justify-content: center;
     overflow: hidden;
     padding-inline: var(--cr-section-padding) var(--cr-icon-ripple-padding);
-    position: relative;
     width: 100%;
   }
   #topicSourceTextPlaceholder {
@@ -98,28 +107,18 @@
 <div id="container">
   <template is="dom-if" if="[[isPersonalizationJellyEnabled_]]">
     <ambient-preview-small></ambient-preview-small>
-  </template>
-  <!-- restamp to avoid layout issues with iron-list resizing while hidden -->
-  <template is="dom-if" if="[[shouldShowMainSettings_(path)]]" restamp>
-    <div id="mainSettings">
-      <template is="dom-if" if="[[isLoadingAmbientMode_(ambientModeEnabled_)]]">
-        <div id="toggleRowPlaceholder" class="ambient-toggle-row-container">
-          <div class="ambient-toggle-row">
-            <div class="ambient-primary-text-placeholder placeholder"></div>
+    <!-- restamp to avoid layout issues with iron-list resizing while hidden -->
+    <template is="dom-if" if="[[shouldShowMainSettings_(path)]]" restamp>
+      <div id="mainSettings">
+        <template is="dom-if" if="[[loading_]]">
+          <div id="toggleRowPlaceholder">
+            <div class="ambient-toggle-label-placeholder placeholder"></div>
+            <div class="ambient-toggle-row-container">
+              <div class="ambient-toggle-row">
+                <div class="ambient-primary-text-placeholder placeholder"></div>
+              </div>
+            </div>
           </div>
-        </div>
-      </template>
-      <template is="dom-if" if="[[!isLoadingAmbientMode_(ambientModeEnabled_)]]">
-        <toggle-row id="ambientToggleRow" checked="[[ambientModeEnabled_]]"
-            on-click="onClickAmbientModeButton_" on-change="onToggleStateChanged_">
-        </toggle-row>
-      </template>
-      <template is="dom-if" if="[[ambientModeEnabled_]]">
-        <!-- TODO(b/253470553): Remove after Ambient subpage UI change is released. -->
-        <template is="dom-if" if="[[!isPersonalizationJellyEnabled_]]">
-          <ambient-preview-small class="jelly-disabled"></ambient-preview-small>
-        </template>
-        <template is="dom-if" if="[[loadingSettings_]]">
           <div id="animationThemePlaceholder">
             <h3 id="animationTitle" class="ambient-subpage-element-title" aria-hidden="true">
               $i18n{ambientModeAnimationTitle}
@@ -160,27 +159,108 @@
             </iron-list>
           </div>
         </template>
-        <template is="dom-if" if="[[!loadingSettings_]]">
-          <animation-theme-list
-              selected-animation-theme="[[animationTheme_]]">
-          </animation-theme-list>
-          <topic-source-list selected-topic-source="[[topicSource_]]"
-              has-google-photos-albums="[[hasGooglePhotosAlbums_(albums_)]]">
-          </topic-source-list>
-          <ambient-weather-unit
-              selected-temperature-unit="[[temperatureUnitToString_(temperatureUnit_)]]">
-          </ambient-weather-unit>
+        <template is="dom-if" if="[[!loading_]]">
+          <toggle-row id="ambientToggleRow" checked="[[ambientModeEnabled_]]"
+          on-click="onClickAmbientModeButton_" on-change="onToggleStateChanged_">
+          </toggle-row>
+          <template is="dom-if" if="[[ambientModeEnabled_]]">
+            <animation-theme-list
+                selected-animation-theme="[[animationTheme_]]">
+            </animation-theme-list>
+            <topic-source-list selected-topic-source="[[topicSource_]]"
+                has-google-photos-albums="[[hasGooglePhotosAlbums_(albums_)]]">
+            </topic-source-list>
+            <ambient-weather-unit
+                selected-temperature-unit="[[temperatureUnitToString_(temperatureUnit_)]]">
+            </ambient-weather-unit>
+          </template>
         </template>
-      </template>
-      <template is="dom-if" if="[[shouldShowZeroState_(ambientModeEnabled_, isPersonalizationJellyEnabled_)]]">
-        <ambient-zero-state id="zeroState"></ambient-zero-state>
-      </template>
-    </div>
+      </div>
+    </template>
+    <template is="dom-if" if="[[shouldShowAlbums_(path)]]" restamp>
+      <albums-subpage topic-source="[[getTopicSource_(queryParams)]]"
+          albums="[[getAlbums_(albums_, queryParams)]]">
+      </albums-subpage>
+    </template>
   </template>
-  <!-- restamp to avoid layout issues with iron-list resizing while hidden -->
-  <template is="dom-if" if="[[shouldShowAlbums_(path)]]" restamp>
-    <albums-subpage topic-source="[[getTopicSource_(queryParams)]]"
-        albums="[[getAlbums_(albums_, queryParams)]]">
-    </albums-subpage>
+  <template is="dom-if" if="[[!isPersonalizationJellyEnabled_]]">
+    <!-- restamp to avoid layout issues with iron-list resizing while hidden -->
+    <template is="dom-if" if="[[shouldShowMainSettings_(path)]]" restamp>
+      <div id="mainSettings">
+        <template is="dom-if" if="[[loading_]]">
+          <div id="toggleRowPlaceholder" class="ambient-toggle-row-container">
+            <div class="ambient-toggle-row">
+              <div class="ambient-primary-text-placeholder placeholder"></div>
+            </div>
+          </div>
+          <ambient-preview-small class="jelly-disabled"></ambient-preview-small>
+          <div id="animationThemePlaceholder">
+            <h3 id="animationTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeAnimationTitle}
+            </h3>
+            <iron-list class="animation-placeholder-list" items="[[getPlaceholders_(3)]]" grid>
+              <template>
+                <div class="animation-placeholder-container">
+                  <div class="animation-item-placeholder placeholder"></div>
+                  <div class="animation-item-title-placeholder
+                      ambient-primary-text-placeholder placeholder"></div>
+                </div>
+              </template>
+            </iron-list>
+          </div>
+          <div id="topicSourcePlaceholder">
+            <h3 id="topicSourceTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeTopicSourceTitle}
+            </h3>
+            <iron-list items="[[getPlaceholders_(2)]]" grid>
+              <template>
+                  <div id="topicSourceTextPlaceholder" class$="{{getClassContainer_(index)}}">
+                    <div class="ambient-primary-text-placeholder placeholder"></div>
+                    <div class="ambient-secondary-text-placeholder placeholder"></div>
+                  </div>
+              </template>
+            </iron-list>
+          </div>
+          <div id="weatherUnitPlaceholder">
+            <h3 id="weatherTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeWeatherTitle}
+            </h3>
+            <iron-list items="[[getPlaceholders_(2)]]" grid>
+              <template>
+                <div id="weatherUnitTextPlaceholder" class$="{{getClassContainer_(index)}}">
+                  <div class="ambient-secondary-text-placeholder placeholder"></div>
+                </div>
+              </template>
+            </iron-list>
+          </div>
+        </template>
+        <template is="dom-if" if="[[!loading_]]">
+          <toggle-row id="ambientToggleRow" checked="[[ambientModeEnabled_]]"
+          on-click="onClickAmbientModeButton_" on-change="onToggleStateChanged_">
+          </toggle-row>
+          <template is="dom-if" if="[[!ambientModeEnabled_]]">
+            <ambient-zero-state id="zeroState"></ambient-zero-state>
+          </template>
+          <template is="dom-if" if="[[ambientModeEnabled_]]">
+            <ambient-preview-small class="jelly-disabled"></ambient-preview-small>
+            <animation-theme-list
+                selected-animation-theme="[[animationTheme_]]">
+            </animation-theme-list>
+            <topic-source-list selected-topic-source="[[topicSource_]]"
+                has-google-photos-albums="[[hasGooglePhotosAlbums_(albums_)]]">
+            </topic-source-list>
+            <ambient-weather-unit
+                selected-temperature-unit="[[temperatureUnitToString_(temperatureUnit_)]]">
+            </ambient-weather-unit>
+          </template>
+        </template>
+      </div>
+    </template>
+    <!-- restamp to avoid layout issues with iron-list resizing while hidden -->
+    <template is="dom-if" if="[[shouldShowAlbums_(path)]]" restamp>
+      <albums-subpage topic-source="[[getTopicSource_(queryParams)]]"
+          albums="[[getAlbums_(albums_, queryParams)]]">
+      </albums-subpage>
+    </template>
   </template>
 </div>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
index 254f5df..c4ec5b9 100644
--- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
@@ -63,10 +63,10 @@
         type: Number,
         value: null,
       },
-      loadingSettings_: {
+      loading_: {
         type: Boolean,
         computed:
-            'computeLoadingSettings_(albums_, temperatureUnit_, topicSource_)',
+            'computeLoading_(ambientModeEnabled_, albums_, temperatureUnit_, topicSource_)',
       },
       isPersonalizationJellyEnabled_: {
         type: Boolean,
@@ -201,9 +201,9 @@
     return this.ambientModeEnabled_ === null;
   }
 
-  private computeLoadingSettings_(): boolean {
-    return this.albums_ === null || this.topicSource_ === null ||
-        this.temperatureUnit_ === null;
+  private computeLoading_(): boolean {
+    return this.ambientModeEnabled_ === null || this.albums_ === null ||
+        this.topicSource_ === null || this.temperatureUnit_ === null;
   }
 
   private getPlaceholders_(x: number): number[] {
diff --git a/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.html b/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.html
index b34b72c..4b46788 100644
--- a/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.html
+++ b/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.html
@@ -1,5 +1,13 @@
 <style include="common">
+  #toggleRowTitle {
+    margin: 34px 8px 2px 0;
+  }
 </style>
+<template is="dom-if" if="[[isPersonalizationJellyEnabled_]]">
+  <h3 id="toggleRowTitle" class="ambient-subpage-element-title" aria-hidden="true">
+    [[getToggleRowTitle_(checked)]]
+  </h3>
+</template>
 <div class="ambient-toggle-row-container">
   <div class="ambient-toggle-row">
     <p id="toggleDescription">$i18n{ambientModePageDescription}</p>
diff --git a/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.ts b/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.ts
index 5c66621..6eeeb0e 100644
--- a/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.ts
+++ b/ash/webui/personalization_app/resources/js/ambient/toggle_row_element.ts
@@ -11,6 +11,7 @@
 
 import {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
 
+import {isPersonalizationJellyEnabled} from '../load_time_booleans.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
 
 import {getTemplate} from './toggle_row_element.html.js';
@@ -32,10 +33,18 @@
     return {
       checked:
           {type: Boolean, value: false, notify: true, reflectToAttribute: true},
+
+      isPersonalizationJellyEnabled_: {
+        type: Boolean,
+        value() {
+          return isPersonalizationJellyEnabled();
+        },
+      },
     };
   }
 
   checked: boolean;
+  private isPersonalizationJellyEnabled_: boolean;
   override ariaLabel: string;
 
   override focus() {
@@ -45,6 +54,10 @@
   private getAriaLabel_(): string {
     return this.i18n(this.checked ? 'ambientModeOn' : 'ambientModeOff');
   }
+
+  private getToggleRowTitle_(): string {
+    return this.getAriaLabel_().toUpperCase();
+  }
 }
 
 declare global {
diff --git a/ash/webui/personalization_app/resources/js/personalization_main_element.html b/ash/webui/personalization_app/resources/js/personalization_main_element.html
index 211c432..e96008ec 100644
--- a/ash/webui/personalization_app/resources/js/personalization_main_element.html
+++ b/ash/webui/personalization_app/resources/js/personalization_main_element.html
@@ -13,6 +13,10 @@
     width: 100%;
   }
 
+  :host-context(body.jelly-enabled) #container {
+    grid-template-rows: 132px 1fr auto 32px;
+  }
+
   user-preview {
     grid-area: userpreview;
   }
diff --git a/ash/webui/personalization_app/resources/js/user/user_preview_element.html b/ash/webui/personalization_app/resources/js/user/user_preview_element.html
index df25ddbf..93813776 100644
--- a/ash/webui/personalization_app/resources/js/user/user_preview_element.html
+++ b/ash/webui/personalization_app/resources/js/user/user_preview_element.html
@@ -10,6 +10,14 @@
     height: 100%;
   }
 
+  :host-context(body.jelly-enabled) #container {
+    grid-template-areas:
+      '.     . .'
+      'image . text';
+    grid-template-columns: 96px 20px minmax(0, 1fr);
+    grid-template-rows: 20px 96px;
+  }
+
   #imageContainer {
     grid-area: image;
     position: relative;
@@ -31,6 +39,12 @@
     width: 80px;
   }
 
+  :host-context(body.jelly-enabled) #imageContainer #imageBorderContainer img {
+    background-size: 96px 96px;
+    height: 96px;
+    width: 96px;
+  }
+
   #imageContainer img {
     border: 1px solid rgba(0, 0, 0, 0.08);
     border-radius: 50%;
@@ -38,6 +52,13 @@
     width: 80px;
   }
 
+  :host-context(body.jelly-enabled) #imageBorderContainer,
+  :host-context(body.jelly-enabled) #imageContainer img {
+    border: 0;
+    height: 96px;
+    width: 96px;
+  }
+
   #imageContainer img.clickable {
     cursor: pointer;
   }
@@ -64,6 +85,10 @@
     font: 400 22px/28px var(--cros-font-family-google-sans);
   }
 
+  :host-context(body.jelly-enabled) #infoContainer > h2 {
+    font: 400 22px/24px var(--cros-font-family-google-sans);
+  }
+
   .avatar-link {
     align-items: center;
     cursor: pointer;
@@ -84,6 +109,11 @@
     margin: 0;
   }
 
+  :host-context(body.jelly-enabled) .avatar-link > span {
+    color: var(--cros-sys-secondary, var(--cros-link-color));
+    font: 400 13px/20px var(--cros-font-family-google-sans);
+  }
+
   iron-icon[icon='cr:open-in-new'] {
     --iron-icon-height: 16px;
     --iron-icon-width: 16px;
@@ -91,6 +121,12 @@
     margin-inline-start: 6px;
   }
 
+  :host-context(body.jelly-enabled) iron-icon[icon='cr:open-in-new'] {
+    --iron-icon-height: 12px;
+    --iron-icon-width: 12px;
+    --iron-icon-fill-color: var(--cros-sys-secondary, var(--cros-link-color));
+  }
+
   paper-ripple {
     color: rgba(var(--cros-ripple-color-rgb), 1);
     --paper-ripple-opacity: var(--cros-button-primary-ripple-opacity);
@@ -112,6 +148,14 @@
     width: 24px;
   }
 
+  :host-context(body.jelly-enabled) #iconContainer,
+  :host-context(body.jelly-enabled) #enterpriseIconContainer {
+    height: 32px;
+    line-height: 32px;
+    right: 0;
+    width: 32px;
+  }
+
   #iconContainer {
     align-items: center;
     background-color: var(--cros-icon-color-prominent);
@@ -123,7 +167,7 @@
   }
 
   #iconContainer > svg {
-    fill: var(--cros-button-label-color-primary);
+    fill: var(--cros-sys-on_primary, var(--cros-button-label-color-primary));
   }
 
   #enterpriseIconContainer {
@@ -139,6 +183,16 @@
     }
   }
 
+  :host-context(body.jelly-enabled) #enterpriseIconContainer {
+    background-color: var(--cros-sys-on_primary_container);
+  }
+
+  :host-context(body.jelly-enabled) #enterpriseIconContainer svg {
+    fill: var(--cros-sys-on_primary);
+    margin-top: 10px;
+    text-align: center;
+  }
+
   #avatar:focus-visible {
     outline: 2px solid var(--cros-focus-ring-color);
   }
@@ -152,8 +206,16 @@
         <img id="avatar" class="managed" src$="[[imageUrl_.url]]"
             alt="$i18n{managedSetting}" title="$i18n{managedSetting}">
         <div id="enterpriseIconContainer">
-          <iron-icon icon="personalization:managed">
-          </iron-icon>
+          <template is="dom-if" if="[[!isPersonalizationJellyEnabled_]]">
+            <iron-icon icon="personalization:managed">
+            </iron-icon>
+          </template>
+          <template is="dom-if" if="[[isPersonalizationJellyEnabled_]]">
+            <svg width="13.33" height="12" viewBox="0 0 13.33 12" xmlns="http://www.w3.org/2000/svg">
+              <path d="M7.00004 2.66667V0H0.333374V12H13.6667V2.66667H7.00004ZM5.66671 10.6667H1.66671V9.33333H5.66671V10.6667ZM5.66671 8H1.66671V6.66667H5.66671V8ZM5.66671 5.33333H1.66671V4H5.66671V5.33333ZM5.66671 2.66667H1.66671V1.33333H5.66671V2.66667ZM12.3334 10.6667H7.00004V4H12.3334V10.6667ZM11 5.33333H8.33337V6.66667H11V5.33333ZM11 8H8.33337V9.33333H11V8Z">
+              </path>
+            </svg>
+          </template>
         </div>
       </template>
       <template is="dom-if"
@@ -161,11 +223,20 @@
         <div id="iconContainer"
             on-click="onClickUserSubpageLink_"
             on-keypress="onClickUserSubpageLink_">
-          <svg viewBox="0 0 16 16" width="16" height="16">
-            <path fill-rule="evenodd" clip-rule="evenodd"
-                d="M13.5575 3.45125L12.545 2.43875C11.96 1.85375 11.0075 1.85375 10.4225 2.43875L8.3 4.55375L2 10.8612V13.9962H5.135L13.5575 5.57375C14.15 4.98875 14.15 4.03625 13.5575 3.45125ZM3.5 12.4963V11.4763L9.365 5.61125L10.4225 6.66875L4.5575 12.5413L3.5 12.4963Z">
-            </path>
-          </svg>
+          <template is="dom-if" if="[[!isPersonalizationJellyEnabled_]]">
+            <svg viewBox="0 0 16 16" width="16" height="16">
+              <path fill-rule="evenodd" clip-rule="evenodd"
+                  d="M13.5575 3.45125L12.545 2.43875C11.96 1.85375 11.0075 1.85375 10.4225 2.43875L8.3 4.55375L2 10.8612V13.9962H5.135L13.5575 5.57375C14.15 4.98875 14.15 4.03625 13.5575 3.45125ZM3.5 12.4963V11.4763L9.365 5.61125L10.4225 6.66875L4.5575 12.5413L3.5 12.4963Z">
+              </path>
+            </svg>
+          </template>
+          <template is="dom-if" if="[[isPersonalizationJellyEnabled_]]">
+            <svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg">
+              <path fill-rule="evenodd" clip-rule="evenodd"
+                  d="M12.928 2.148L11.848 1.068C11.224 0.443998 10.208 0.443998 9.58397 1.068L7.31997 3.324L0.599976 10.052V13.396H3.94398L12.928 4.412C13.56 3.788 13.56 2.772 12.928 2.148ZM2.19998 11.796V10.708L8.45598 4.452L9.58397 5.58L3.32798 11.844L2.19998 11.796Z">
+              </path>
+            </svg>
+          </template>
         </div>
         <paper-ripple class="circle"></paper-ripple>
         <div id="imageBorderContainer">
diff --git a/ash/webui/personalization_app/resources/js/user/user_preview_element.ts b/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
index 5051a2c..6ad7b1b 100644
--- a/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
+++ b/ash/webui/personalization_app/resources/js/user/user_preview_element.ts
@@ -15,6 +15,7 @@
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 
+import {isPersonalizationJellyEnabled} from '../load_time_booleans.js';
 import {UserImage, UserInfo} from '../personalization_app.mojom-webui.js';
 import {Paths, PersonalizationRouter} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
@@ -62,6 +63,12 @@
         type: Boolean,
         value: null,
       },
+      isPersonalizationJellyEnabled_: {
+        type: Boolean,
+        value() {
+          return isPersonalizationJellyEnabled();
+        },
+      },
     };
   }
 
@@ -70,6 +77,7 @@
   private image_: UserImage|null;
   private imageUrl_: Url|null;
   private imageIsEnterpriseManaged_: boolean|null;
+  private isPersonalizationJellyEnabled_: boolean;
 
   override ready() {
     super.ready();
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index a93ac03d..810630e 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -7,11 +7,13 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
+#include "ash/wm/float/float_controller.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/ranges/algorithm.h"
+#include "chromeos/ui/wm/features.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/display.h"
@@ -280,6 +282,22 @@
 void WindowPositioner::RearrangeVisibleWindowOnShow(
     aura::Window* added_window) {
   WindowState* added_window_state = WindowState::Get(added_window);
+  // TODO(b/267884882): Temporarily disable auto positioning if there is a
+  // floated window on the same desk, see b/265839238.
+  if (auto* float_controller = Shell::Get()->float_controller()) {
+    auto* floated_window = float_controller->FindFloatedWindowOfDesk(
+        Shell::Get()->desks_controller()->active_desk());
+    if (floated_window && floated_window != added_window) {
+      // Place newly added window to the center of the screen to reduce chances
+      // of being hidden behind the floated window. Note that minimized windows
+      // should not be auto placed.
+      if (!added_window_state->bounds_changed_by_user()) {
+        AutoPlaceSingleWindow(added_window, /*animated=*/false);
+      }
+      return;
+    }
+  }
+
   if (!added_window->TargetVisibility() ||
       !UseAutoWindowManager(added_window) ||
       added_window_state->bounds_changed_by_user()) {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 3a64b319..90e9802 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1691,7 +1691,7 @@
       ]
     }
 
-    if (!is_ios) {
+    if (use_blink) {
       sources += [
         "memory/discardable_shared_memory.cc",
         "memory/discardable_shared_memory.h",
@@ -2111,9 +2111,7 @@
 
     configs += linux_configs
     all_dependent_configs += linux_configs
-    sources += [
-      "system/sys_info_linux.cc",
-    ]
+    sources += [ "system/sys_info_linux.cc" ]
     if (!is_cronet_build) {
       # These dependencies are not required on Android, and in the case
       # of xdg_mime must be excluded due to licensing restrictions.
@@ -2190,7 +2188,6 @@
       "native_library_ios.mm",
       "power_monitor/power_monitor_device_source_ios.mm",
       "process/launch_ios.cc",
-      "process/memory_stubs.cc",
       "process/process_metrics_ios.cc",
       "process/process_stubs.cc",
       "profiler/module_cache_mac.cc",
@@ -2203,6 +2200,17 @@
       "time/time_mac.mm",
     ]
 
+    if (use_blink) {
+      sources += [
+        "process/memory_mac.mm",
+        "process/process_iterator_ios.mm",
+        "sync_socket_posix.cc",
+        "synchronization/waitable_event_watcher_mac.cc",
+      ]
+    } else {
+      sources += [ "process/memory_stubs.cc" ]
+    }
+
     if (is_cronet_build) {
       sources += [
         "message_loop/message_pump_io_ios.cc",
@@ -2248,7 +2256,7 @@
     frameworks += [ "UIKit.framework" ]
   }
 
-  if (!is_ios) {
+  if (use_blink) {
     sources += [
       "files/file_path_watcher.cc",
       "files/file_path_watcher.h",
@@ -3425,6 +3433,10 @@
     "//testing/buildbot/filters:base_unittests_filters",
   ]
 
+  if (is_android && enable_chrome_android_internal) {
+    data_deps += [ "//clank/build/bot/filters:base_unittests_filters" ]
+  }
+
   if (toolchain_has_rust) {
     deps += [ "//build/rust:cxx_cppdeps" ]
   }
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc
index 0b00a8b..148a776db 100644
--- a/base/allocator/partition_alloc_support.cc
+++ b/base/allocator/partition_alloc_support.cc
@@ -775,24 +775,10 @@
 
 PartitionAllocSupport::PartitionAllocSupport() = default;
 
-void PartitionAllocSupport::ReconfigureForTests() {
-  ReconfigureEarlyish("");
-  base::AutoLock scoped_lock(lock_);
-  called_for_tests_ = true;
-}
-
 void PartitionAllocSupport::ReconfigureEarlyish(
     const std::string& process_type) {
   {
     base::AutoLock scoped_lock(lock_);
-
-    // In tests, ReconfigureEarlyish() is called by ReconfigureForTest(), which
-    // is earlier than ContentMain().
-    if (called_for_tests_) {
-      DCHECK(called_earlyish_);
-      return;
-    }
-
     // TODO(bartekn): Switch to DCHECK once confirmed there are no issues.
     CHECK(!called_earlyish_)
         << "ReconfigureEarlyish was already called for process '"
@@ -843,11 +829,8 @@
 }
 
 void PartitionAllocSupport::ReconfigureAfterFeatureListInit(
-    const std::string& process_type,
-    bool configure_dangling_pointer_detector) {
-  if (configure_dangling_pointer_detector) {
-    base::allocator::InstallDanglingRawPtrChecks();
-  }
+    const std::string& process_type) {
+  base::allocator::InstallDanglingRawPtrChecks();
   base::allocator::InstallUnretainedDanglingRawPtrChecks();
   {
     base::AutoLock scoped_lock(lock_);
diff --git a/base/allocator/partition_alloc_support.h b/base/allocator/partition_alloc_support.h
index 129dccb..ead3d47d 100644
--- a/base/allocator/partition_alloc_support.h
+++ b/base/allocator/partition_alloc_support.h
@@ -66,12 +66,9 @@
   // re-configuration steps exactly once.
   //
   // *AfterTaskRunnerInit() may be called more than once.
-  void ReconfigureForTests();
   void ReconfigureEarlyish(const std::string& process_type);
   void ReconfigureAfterZygoteFork(const std::string& process_type);
-  void ReconfigureAfterFeatureListInit(
-      const std::string& process_type,
-      bool configure_dangling_pointer_detector = true);
+  void ReconfigureAfterFeatureListInit(const std::string& process_type);
   void ReconfigureAfterTaskRunnerInit(const std::string& process_type);
 
   // |has_main_frame| tells us if the renderer contains a main frame.
@@ -87,7 +84,6 @@
   PartitionAllocSupport();
 
   base::Lock lock_;
-  bool called_for_tests_ GUARDED_BY(lock_) = false;
   bool called_earlyish_ GUARDED_BY(lock_) = false;
   bool called_after_zygote_fork_ GUARDED_BY(lock_) = false;
   bool called_after_feature_list_init_ GUARDED_BY(lock_) = false;
diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h
index 422a69bf..a819ae13 100644
--- a/base/process/process_iterator.h
+++ b/base/process/process_iterator.h
@@ -114,10 +114,10 @@
 
 #if BUILDFLAG(IS_WIN)
   HANDLE snapshot_;
-  bool started_iteration_;
+  bool started_iteration_ = false;
 #elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_BSD)
   std::vector<kinfo_proc> kinfo_procs_;
-  size_t index_of_kinfo_proc_;
+  size_t index_of_kinfo_proc_ = 0;
 #elif BUILDFLAG(IS_POSIX)
   struct DIRClose {
     inline void operator()(DIR* x) const {
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
index fcc4bed..1673bdd 100644
--- a/base/process/process_iterator_freebsd.cc
+++ b/base/process/process_iterator_freebsd.cc
@@ -17,9 +17,7 @@
 namespace base {
 
 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
-    : index_of_kinfo_proc_(),
-      filter_(filter) {
-
+    : filter_(filter) {
   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
 
   bool done = false;
@@ -62,8 +60,7 @@
   }
 }
 
-ProcessIterator::~ProcessIterator() {
-}
+ProcessIterator::~ProcessIterator() = default;
 
 bool ProcessIterator::CheckForNextProcess() {
   std::string data;
diff --git a/base/process/process_iterator_fuchsia.cc b/base/process/process_iterator_fuchsia.cc
index 85163900..d64c3195 100644
--- a/base/process/process_iterator_fuchsia.cc
+++ b/base/process/process_iterator_fuchsia.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/notreached.h"
 #include "base/process/process_iterator.h"
 
+#include "base/notreached.h"
+
 namespace base {
 
 ProcessIterator::ProcessIterator(const ProcessFilter* filter) {
@@ -12,7 +13,7 @@
   NOTREACHED();
 }
 
-ProcessIterator::~ProcessIterator() {}
+ProcessIterator::~ProcessIterator() = default;
 
 bool ProcessIterator::CheckForNextProcess() {
   return false;
diff --git a/base/process/process_iterator_ios.mm b/base/process/process_iterator_ios.mm
new file mode 100644
index 0000000..70a3c2c5
--- /dev/null
+++ b/base/process/process_iterator_ios.mm
@@ -0,0 +1,25 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/notreached.h"
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter) {
+  // TODO(crbug.com/1412835): Implement ProcessIterator on iOS.
+  NOTREACHED();
+}
+
+ProcessIterator::~ProcessIterator() {}
+
+bool ProcessIterator::CheckForNextProcess() {
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return false;
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
index e4873d6f..13b6f2a 100644
--- a/base/process/process_iterator_mac.cc
+++ b/base/process/process_iterator_mac.cc
@@ -17,8 +17,7 @@
 namespace base {
 
 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
-    : index_of_kinfo_proc_(0),
-      filter_(filter) {
+    : filter_(filter) {
   // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
   // but trying to find where we were in a constantly changing list is basically
   // impossible.
@@ -68,8 +67,7 @@
   }
 }
 
-ProcessIterator::~ProcessIterator() {
-}
+ProcessIterator::~ProcessIterator() = default;
 
 bool ProcessIterator::CheckForNextProcess() {
   std::string data;
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
index e7978fa8d..fc6e1ec 100644
--- a/base/process/process_iterator_openbsd.cc
+++ b/base/process/process_iterator_openbsd.cc
@@ -15,9 +15,7 @@
 namespace base {
 
 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
-    : index_of_kinfo_proc_(),
-      filter_(filter) {
-
+    : filter_(filter) {
   int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
                 sizeof(struct kinfo_proc), 0 };
 
@@ -61,8 +59,7 @@
   }
 }
 
-ProcessIterator::~ProcessIterator() {
-}
+ProcessIterator::~ProcessIterator() = default;
 
 bool ProcessIterator::CheckForNextProcess() {
   std::string data;
diff --git a/base/process/process_iterator_win.cc b/base/process/process_iterator_win.cc
index 6054168..f7dda9d 100644
--- a/base/process/process_iterator_win.cc
+++ b/base/process/process_iterator_win.cc
@@ -9,10 +9,8 @@
 namespace base {
 
 ProcessIterator::ProcessIterator(const ProcessFilter* filter)
-    : started_iteration_(false),
-      filter_(filter) {
-  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-}
+    : snapshot_(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)),
+      filter_(filter) {}
 
 ProcessIterator::~ProcessIterator() {
   CloseHandle(snapshot_);
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 94c72345..287c6ab 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -8,13 +8,11 @@
 
 #include <memory>
 
-#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/tagging.h"
 #include "base/at_exit.h"
 #include "base/base_paths.h"
 #include "base/base_switches.h"
 #include "base/command_line.h"
-#include "base/debug/asan_service.h"
 #include "base/debug/debugger.h"
 #include "base/debug/profiler.h"
 #include "base/debug/stack_trace.h"
@@ -86,10 +84,6 @@
 #include "base/debug/handle_hooks_win.h"
 #endif  // BUILDFLAG(IS_WIN)
 
-#if BUILDFLAG(USE_PARTITION_ALLOC)
-#include "base/allocator/partition_alloc_support.h"
-#endif  // BUILDFLAG(USE_PARTITION_ALLOC)
-
 namespace base {
 
 namespace {
@@ -175,17 +169,6 @@
       new_command_line.AppendSwitchNative(iter.first, iter.second);
 
     *CommandLine::ForCurrentProcess() = new_command_line;
-
-    // TODO(https://crbug.com/1400059): Enable dangling pointer detector.
-    // TODO(https://crbug.com/1400058): Enable BackupRefPtr in unittests on
-    // Windows and Android too.
-    // TODO(https://crbug.com/1413674): Enable PartitionAlloc in unittests with
-    // ASAN.
-#if BUILDFLAG(USE_PARTITION_ALLOC) && !BUILDFLAG(IS_WIN) && \
-    !BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER)
-    allocator::PartitionAllocSupport::Get()->ReconfigureAfterFeatureListInit(
-        "", /*configure_dangling_pointer_detector=*/false);
-#endif
   }
 
   void OnTestEnd(const testing::TestInfo& test_info) override {
@@ -589,22 +572,6 @@
 void TestSuite::Initialize() {
   DCHECK(!is_initialized_);
 
-  // The AsanService causes ASAN errors to emit additional information. It is
-  // helpful on its own. It is also required by ASAN BackupRefPtr when
-  // reconfiguring PartitionAlloc below.
-#if defined(ADDRESS_SANITIZER)
-  base::debug::AsanService::GetInstance()->Initialize();
-#endif
-
-  // TODO(https://crbug.com/1400058): Enable BackupRefPtr in unittests on
-  // Windows and Android too. Same for ASAN.
-  // TODO(https://crbug.com/1413674): Enable PartitionAlloc in unittests with
-  // ASAN.
-#if BUILDFLAG(USE_PARTITION_ALLOC) && !BUILDFLAG(IS_WIN) && \
-    !BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER)
-  allocator::PartitionAllocSupport::Get()->ReconfigureForTests();
-#endif  // BUILDFLAG(IS_WIN)
-
   test::ScopedRunLoopTimeout::SetAddGTestFailureOnTimeout();
 
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
diff --git a/cc/metrics/custom_metrics_recorder.h b/cc/metrics/custom_metrics_recorder.h
index ced959e4..d013bff 100644
--- a/cc/metrics/custom_metrics_recorder.h
+++ b/cc/metrics/custom_metrics_recorder.h
@@ -18,8 +18,12 @@
   static CustomMetricRecorder* Get();
 
   // Invoked to report "PercentDroppedFrames_1sWindow".
+  // Deprecated in favor of "PercentDroppedFrames_1sWindow2".
   virtual void ReportPercentDroppedFramesInOneSecondWindow(double percent) = 0;
 
+  // Invoked to report "PercentDroppedFrames_1sWindow2".
+  virtual void ReportPercentDroppedFramesInOneSecondWindow2(double percent) = 0;
+
   // Invoked to report event latencies.
   virtual void ReportEventLatency(
       std::vector<EventLatencyTracker::LatencyData> latencies) = 0;
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index 1610f66..77de94a 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -292,6 +292,13 @@
 
   if (fcp_received_)
     frame_sorter_.AddFrameResult(args, frame_info);
+
+  // Report frames on every frame for UI. And this needs to happen after
+  // `frame_sorter_.AddFrameResult` so that the current ending frame is included
+  // in the sliding window.
+  if (report_for_ui_) {
+    ReportFramesOnEveryFrameForUI();
+  }
 }
 
 void DroppedFrameCounter::ReportFrames() {
@@ -398,12 +405,33 @@
 void DroppedFrameCounter::ReportFramesForUI() {
   DCHECK(report_for_ui_);
 
-  auto* recorder = CustomMetricRecorder::Get();
-  if (!recorder)
+  if (!sliding_window_current_percent_dropped_) {
     return;
+  }
+
+  auto* recorder = CustomMetricRecorder::Get();
+  if (!recorder) {
+    return;
+  }
 
   recorder->ReportPercentDroppedFramesInOneSecondWindow(
-      sliding_window_current_percent_dropped_);
+      *sliding_window_current_percent_dropped_);
+}
+
+void DroppedFrameCounter::ReportFramesOnEveryFrameForUI() {
+  DCHECK(report_for_ui_);
+
+  if (!sliding_window_current_percent_dropped_) {
+    return;
+  }
+
+  auto* recorder = CustomMetricRecorder::Get();
+  if (!recorder) {
+    return;
+  }
+
+  recorder->ReportPercentDroppedFramesInOneSecondWindow2(
+      *sliding_window_current_percent_dropped_);
 }
 
 double DroppedFrameCounter::GetMostRecentAverageSmoothness() const {
@@ -447,6 +475,7 @@
       .Clear();
   ring_buffer_.Clear();
   last_reported_metrics_ = {};
+  sliding_window_current_percent_dropped_.reset();
 }
 
 base::TimeDelta DroppedFrameCounter::ComputeCurrentWindowSize() const {
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h
index b1de1c23..b78a831 100644
--- a/cc/metrics/dropped_frame_counter.h
+++ b/cc/metrics/dropped_frame_counter.h
@@ -91,6 +91,7 @@
   void AddDroppedFrame();
   void ReportFrames();
   void ReportFramesForUI();
+  void ReportFramesOnEveryFrameForUI();
 
   void OnBeginFrame(const viz::BeginFrameArgs& args, bool is_scroll_active);
   void OnEndFrame(const viz::BeginFrameArgs& args, const FrameInfo& frame_info);
@@ -162,7 +163,7 @@
   }
 
   double sliding_window_current_percent_dropped() const {
-    return sliding_window_current_percent_dropped_;
+    return sliding_window_current_percent_dropped_.value_or(0);
   }
 
  private:
@@ -220,7 +221,7 @@
   absl::optional<SortedFrameCallback> sorted_frame_callback_;
 
   bool report_for_ui_ = false;
-  double sliding_window_current_percent_dropped_ = 0.0;
+  absl::optional<double> sliding_window_current_percent_dropped_;
 
   // Sets to true on a newly dropped frame and stays true as long as the frames
   // that follow are dropped. Reset when a frame is presented. It is used to
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc
index 6c21d28..b16e078 100644
--- a/cc/metrics/dropped_frame_counter_unittest.cc
+++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -35,23 +35,27 @@
   ~TestCustomMetricsRecorder() override = default;
 
   // CustomMetricRecorder:
-  void ReportPercentDroppedFramesInOneSecondWindow(double percentage) override {
-    ++percent_dropped_frames_count_;
-    last_percent_dropped_frames_ = percentage;
+  void ReportPercentDroppedFramesInOneSecondWindow(double percent) override {}
+  void ReportPercentDroppedFramesInOneSecondWindow2(double percent) override {
+    ++report_count_;
+    last_percent_dropped_frames_ = percent;
   }
   void ReportEventLatency(
       std::vector<EventLatencyTracker::LatencyData> latencies) override {}
 
-  int percent_dropped_frames_count() const {
-    return percent_dropped_frames_count_;
+  void Reset() {
+    report_count_ = 0u;
+    last_percent_dropped_frames_ = 0;
   }
 
+  int report_count() const { return report_count_; }
+
   double last_percent_dropped_frames() const {
     return last_percent_dropped_frames_;
   }
 
  private:
-  int percent_dropped_frames_count_ = 0;
+  int report_count_ = 0u;
   double last_percent_dropped_frames_ = 0;
 };
 
@@ -586,7 +590,7 @@
 
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(
       kFps % 5 == 0,
       "kFps must be a multiple of 5 because this test depends on it.");
@@ -621,7 +625,7 @@
 
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(
       kFps % 5 == 0,
       "kFps must be a multiple of 5 because this test depends on it.");
@@ -655,7 +659,7 @@
 
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(
       kFps % 5 == 0,
       "kFps must be a multiple of 5 because this test depends on it.");
@@ -696,7 +700,7 @@
 
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   SetInterval(kInterval);
 
   // One good frame
@@ -727,7 +731,7 @@
 TEST_F(DroppedFrameCounterTest, ResetPendingFramesAccountingForPendingFrames) {
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   SetInterval(kInterval);
 
   // First 2 seconds with 20% dropped frames.
@@ -751,7 +755,7 @@
 TEST_F(DroppedFrameCounterTest, Reset) {
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   SetInterval(kInterval);
 
   // First 2 seconds with 20% dropped frames.
@@ -775,7 +779,7 @@
 TEST_F(DroppedFrameCounterTest, ConsistentSmoothnessRatings) {
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(kFps == 100,
                 "kFps must be 100 because this test depends on it.");
   SetInterval(kInterval);
@@ -824,7 +828,7 @@
 TEST_F(DroppedFrameCounterTest, MovingSmoothnessRatings) {
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(kFps == 100,
                 "kFps must be 100 because this test depends on it.");
   SetInterval(kInterval);
@@ -897,7 +901,7 @@
 TEST_F(DroppedFrameCounterTest, WorstSmoothnessTiming) {
   // Set an interval that rounds up nicely with 1 second.
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(
       kFps % 5 == 0,
       "kFps must be a multiple of 5 because this test depends on it.");
@@ -943,9 +947,9 @@
   EXPECT_FLOAT_EQ(MaxPercentDroppedFrameAfter5Sec(), 100);
 }
 
-TEST_F(DroppedFrameCounterTest, ReportForUI) {
+TEST_F(DroppedFrameCounterTest, ReportOnEveryFrameForUI) {
   constexpr auto kInterval = base::Milliseconds(10);
-  constexpr size_t kFps = base::Seconds(1) / kInterval;
+  constexpr int kFps = base::Seconds(1).IntDiv(kInterval);
   static_assert(
       kFps % 5 == 0,
       "kFps must be a multiple of 5 because this test depends on it.");
@@ -957,9 +961,19 @@
   // 4 seconds with 20% dropped frames.
   SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
 
-  // Recorded more than 1 samples of 20% dropped frame percentage.
-  EXPECT_GE(recorder.percent_dropped_frames_count(), 1);
-  EXPECT_EQ(recorder.last_percent_dropped_frames(), 20.0f);
+  // Recorded (kFps * 3) samples of 20% dropped frame percentage. Only 3 seconds
+  // of frames reported because there is no reports for the very 1st second.
+  EXPECT_EQ(recorder.report_count(), kFps * 3);
+  EXPECT_FLOAT_EQ(recorder.last_percent_dropped_frames(), 20.0f);
+
+  recorder.Reset();
+
+  // 4 seconds with 0 dropped frames.
+  SimulateFrameSequence({false, false, false, false, false}, (kFps / 5) * 4);
+
+  // Recorded (kFps * 4) samples of 0% dropped frame percentage.
+  EXPECT_EQ(recorder.report_count(), kFps * 4);
+  EXPECT_FLOAT_EQ(recorder.last_percent_dropped_frames(), 0.0f);
 }
 
 }  // namespace
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc
index 913cbc7..1d0f1e9 100644
--- a/cc/paint/image_transfer_cache_entry.cc
+++ b/cc/paint/image_transfer_cache_entry.cc
@@ -93,16 +93,13 @@
 
 base::CheckedNumeric<uint32_t> SafeSizeForPixmap(const SkPixmap& pixmap) {
   base::CheckedNumeric<uint32_t> safe_size;
-  safe_size += sizeof(uint64_t);  // color type
-  safe_size += sizeof(uint64_t);  // width
-  safe_size += sizeof(uint64_t);  // height
-  safe_size += sizeof(uint64_t);  // has color space
-  if (pixmap.colorSpace())
-    safe_size += pixmap.colorSpace()->writeToMemory(nullptr);  // color space
-  safe_size += sizeof(uint64_t);                               // row bytes
-  safe_size += sizeof(uint64_t);                               // data size
-  safe_size += sizeof(16u);                                    // alignment
-  safe_size += pixmap.computeByteSize();                       // data
+  safe_size += PaintOpWriter::SerializedSize(pixmap.colorType());
+  safe_size += PaintOpWriter::SerializedSize(pixmap.width());
+  safe_size += PaintOpWriter::SerializedSize(pixmap.height());
+  safe_size += PaintOpWriter::SerializedSize(pixmap.colorSpace());
+  safe_size += PaintOpWriter::SerializedSize(pixmap.rowBytes());
+  safe_size += 16u;  // The max of GetAlignmentForColorType().
+  safe_size += PaintOpWriter::SerializedSizeOfBytes(pixmap.computeByteSize());
   return safe_size;
 }
 
@@ -153,9 +150,9 @@
     DLOG(ERROR) << "Invalid color type";
     return false;
   }
-  uint32_t width = 0;
+  int width = 0;
   reader.Read(&width);
-  uint32_t height = 0;
+  int height = 0;
   reader.Read(&height);
   if (width == 0 || height == 0) {
     DLOG(ERROR) << "Empty width or height";
@@ -200,33 +197,34 @@
 
 size_t TargetColorParamsSize(
     const absl::optional<TargetColorParams>& target_color_params) {
-  // uint32 for whether or not there are going to be parameters.
-  size_t target_color_params_size = sizeof(uint32_t);
+  // bool for whether or not there are going to be parameters.
+  size_t target_color_params_size = PaintOpWriter::SerializedSize<bool>();
   if (target_color_params) {
-    // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
-    // alignment.  Always use 8 byte alignment.
-    const size_t align = sizeof(uint64_t);
-
     // The target color space.
+    target_color_params_size += PaintOpWriter::SerializedSize(
+        target_color_params->color_space.ToSkColorSpace().get());
+    target_color_params_size += PaintOpWriter::SerializedSize(
+        target_color_params->sdr_max_luminance_nits);
+    target_color_params_size += PaintOpWriter::SerializedSize(
+        target_color_params->hdr_max_luminance_relative);
     target_color_params_size +=
-        sizeof(uint64_t) +
-        target_color_params->color_space.ToSkColorSpace()->writeToMemory(
-            nullptr) +
-        align;
-    // Floats for the SDR and HDR maximum luminance.
-    target_color_params_size += sizeof(float);
-    target_color_params_size += sizeof(float);
-    // uint32_t for tone mapping enabled or disabled.
-    target_color_params_size += sizeof(uint32_t);
-    // uint32_t for whether or not there is HDR metadata.
-    target_color_params_size += sizeof(uint32_t);
-    if (target_color_params->hdr_metadata) {
-      // The x and y coordinates for primaries and white point.
-      target_color_params_size += 4 * 2 * sizeof(float);
+        PaintOpWriter::SerializedSize(target_color_params->enable_tone_mapping);
+    // bool for whether or not there is HDR metadata.
+    target_color_params_size += PaintOpWriter::SerializedSize<bool>();
+    if (auto& hdr_metadata = target_color_params->hdr_metadata) {
       // The minimum and maximum luminance.
-      target_color_params_size += 2 * sizeof(float);
+      target_color_params_size +=
+          PaintOpWriter::SerializedSize(hdr_metadata->max_content_light_level);
+      target_color_params_size += PaintOpWriter::SerializedSize(
+          hdr_metadata->max_frame_average_light_level);
+      // The x and y coordinates for primaries and white point.
+      target_color_params_size += PaintOpWriter::SerializedSizeOfElements(
+          &hdr_metadata->color_volume_metadata.primaries.fRX, 4 * 2);
       // The CLL and FALL
-      target_color_params_size += 2 * sizeof(unsigned);
+      target_color_params_size += PaintOpWriter::SerializedSize(
+          hdr_metadata->color_volume_metadata.luminance_max);
+      target_color_params_size += PaintOpWriter::SerializedSize(
+          hdr_metadata->color_volume_metadata.luminance_min);
     }
   }
   return target_color_params_size;
@@ -235,7 +233,7 @@
 void WriteTargetColorParams(
     PaintOpWriter& writer,
     const absl::optional<TargetColorParams>& target_color_params) {
-  const uint32_t has_target_color_params = target_color_params ? 1 : 0;
+  const bool has_target_color_params = !!target_color_params;
   writer.Write(has_target_color_params);
   if (target_color_params) {
     writer.Write(target_color_params->color_space.ToSkColorSpace().get());
@@ -243,7 +241,7 @@
     writer.Write(target_color_params->hdr_max_luminance_relative);
     writer.Write(target_color_params->enable_tone_mapping);
 
-    const uint32_t has_hdr_metadata = !!target_color_params->hdr_metadata;
+    const bool has_hdr_metadata = !!target_color_params->hdr_metadata;
     writer.Write(has_hdr_metadata);
     if (target_color_params->hdr_metadata) {
       const auto& hdr_metadata = target_color_params->hdr_metadata;
@@ -268,7 +266,7 @@
 bool ReadTargetColorParams(
     PaintOpReader& reader,
     absl::optional<TargetColorParams>& target_color_params) {
-  uint32_t has_target_color_params = 0;
+  bool has_target_color_params = false;
   reader.Read(&has_target_color_params);
   if (!has_target_color_params) {
     target_color_params = absl::nullopt;
@@ -286,7 +284,7 @@
   reader.Read(&target_color_params->hdr_max_luminance_relative);
   reader.Read(&target_color_params->enable_tone_mapping);
 
-  uint32_t has_hdr_metadata = 0;
+  bool has_hdr_metadata = false;
   reader.Read(&has_hdr_metadata);
   if (has_hdr_metadata) {
     gfx::HDRMetadata hdr_metadata;
@@ -341,32 +339,13 @@
       id_(GetNextId()),
       pixmap_(pixmap),
       decoded_color_space_(nullptr) {
-  size_t pixmap_color_space_size =
-      pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr)
-                            : 0u;
-
-  // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
-  // alignment.  Always use 8 byte alignment.
-  const size_t align = sizeof(uint64_t);
-
   // Compute and cache the size of the data.
   base::CheckedNumeric<uint32_t> safe_size;
-  safe_size += PaintOpWriter::HeaderBytes();
-  safe_size += sizeof(uint32_t);  // is_yuv
-  safe_size += sizeof(uint32_t);  // color type
-  safe_size += sizeof(uint32_t);  // width
-  safe_size += sizeof(uint32_t);  // height
-  safe_size += sizeof(uint32_t);  // has mips
-  safe_size += sizeof(uint64_t) + align;  // pixels size + alignment
-  safe_size += sizeof(uint64_t) + align;  // row bytes + alignment
+  safe_size += PaintOpWriter::SerializedSize(needs_mips_);
   safe_size += TargetColorParamsSize(target_color_params_);
-  safe_size += pixmap_color_space_size + sizeof(uint64_t) + align;
-  // Include 4 bytes of padding so we can always align our data pointer to a
-  // 4-byte boundary.
-  safe_size += 4;
-  safe_size += pixmap_->computeByteSize();
-  size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
-                              PaintOpWriter::Alignment());
+  safe_size += PaintOpWriter::SerializedSize(plane_config_);
+  safe_size += SafeSizeForPixmap(*pixmap_);
+  size_ = safe_size.ValueOrDefault(0);
 }
 
 ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
@@ -394,29 +373,19 @@
     yuv_pixmaps_->at(i) = &yuva_pixmaps[i];
   }
   DCHECK(IsYuv());
-  size_t decoded_color_space_size =
-      decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u;
-
-  // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
-  // alignment.  Always use 8 byte alignment.
-  const size_t align = sizeof(uint64_t);
 
   // Compute and cache the size of the data.
   base::CheckedNumeric<uint32_t> safe_size;
-  safe_size += PaintOpWriter::HeaderBytes();
-
-  safe_size += sizeof(uint32_t);  // has mips
-  safe_size += sizeof(uint64_t);  // target color space stub (is nullptr)
+  safe_size += PaintOpWriter::SerializedSize(needs_mips_);
   safe_size += TargetColorParamsSize(target_color_params_);
-
-  safe_size += sizeof(uint32_t);  // plane_config
-  safe_size += sizeof(uint32_t);  // subsampling
-  safe_size += sizeof(uint32_t);  // YUVA color matrix for YUVA image
-  safe_size += decoded_color_space_size + align;  // SkColorSpace for YUVA image
-  for (size_t i = 0; i < num_yuva_pixmaps; ++i)
+  safe_size += PaintOpWriter::SerializedSize(plane_config_);
+  safe_size += PaintOpWriter::SerializedSize(subsampling_);
+  safe_size += PaintOpWriter::SerializedSize(yuv_color_space_);
+  safe_size += PaintOpWriter::SerializedSize(decoded_color_space_.get());
+  for (size_t i = 0; i < num_yuva_pixmaps; ++i) {
     safe_size += SafeSizeForPixmap(*yuv_pixmaps_->at(i));
-  size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
-                              PaintOpWriter::Alignment());
+  }
+  size_ = safe_size.ValueOrDefault(0);
 }
 
 ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default;
@@ -454,7 +423,7 @@
   PaintOp::SerializeOptions options;
   PaintOpWriter writer(data.data(), data.size(), options);
 
-  writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
+  writer.Write(needs_mips_);
   WriteTargetColorParams(writer, target_color_params_);
   writer.Write(plane_config_);
 
@@ -556,7 +525,7 @@
   PaintOpReader reader(data.data(), data.size(), options);
 
   // Parameters common to RGBA and YUVA images.
-  uint32_t needs_mips = 0;
+  bool needs_mips = false;
   reader.Read(&needs_mips);
   has_mips_ = needs_mips;
   absl::optional<TargetColorParams> target_color_params;
diff --git a/cc/paint/paint_filter.cc b/cc/paint/paint_filter.cc
index 00fe240..f9ec2d47 100644
--- a/cc/paint/paint_filter.cc
+++ b/cc/paint/paint_filter.cc
@@ -136,22 +136,13 @@
   return base::OptionalToPtr(crop_rect_);
 }
 
-size_t PaintFilter::GetFilterSize(const PaintFilter* filter) {
-  // A null type is used to indicate no filter.
-  if (!filter)
-    return sizeof(uint32_t);
-  return filter->SerializedSize() + PaintOpWriter::Alignment();
-}
-
 size_t PaintFilter::BaseSerializedSize() const {
   size_t total_size = 0u;
-  // Filter type.
-  total_size += sizeof(uint32_t);
+  total_size += PaintOpWriter::SerializedSize(type_);
   // Bool to indicate whether crop exists.
-  total_size += sizeof(uint32_t);
+  total_size += PaintOpWriter::SerializedSize<bool>();
   if (crop_rect_) {
-    // CropRect.
-    total_size += sizeof(*crop_rect_);
+    total_size += PaintOpWriter::SerializedSize(*crop_rect_);
   }
   return total_size;
 }
@@ -240,8 +231,9 @@
 size_t ColorFilterPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size = 0u;
   total_size += BaseSerializedSize();
-  total_size += PaintOpWriter::GetFlattenableSize(color_filter_.get());
-  total_size += GetFilterSize(input_.get());
+  total_size += PaintOpWriter::SerializedSize(
+      static_cast<const SkFlattenable*>(color_filter_.get()));
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -279,9 +271,10 @@
 
 size_t BlurPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(sigma_x_) + sizeof(sigma_y_) +
-      sizeof(tile_mode_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(sigma_x_) +
+      PaintOpWriter::SerializedSize(sigma_y_) +
+      PaintOpWriter::SerializedSize(tile_mode_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -331,9 +324,13 @@
 
 size_t DropShadowPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(dx_) + sizeof(dy_) + sizeof(sigma_x_) +
-      sizeof(sigma_y_) + sizeof(color_) + sizeof(shadow_mode_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(dx_) +
+      PaintOpWriter::SerializedSize(dy_) +
+      PaintOpWriter::SerializedSize(sigma_x_) +
+      PaintOpWriter::SerializedSize(sigma_y_) +
+      PaintOpWriter::SerializedSize(color_) +
+      PaintOpWriter::SerializedSize(shadow_mode_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -368,8 +365,9 @@
 
 size_t MagnifierPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(src_rect_) + sizeof(inset_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(src_rect_) +
+      PaintOpWriter::SerializedSize(inset_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -400,8 +398,8 @@
 
 size_t ComposePaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
-  total_size += GetFilterSize(outer_.get());
-  total_size += GetFilterSize(inner_.get());
+  total_size += PaintOpWriter::SerializedSize(outer_.get());
+  total_size += PaintOpWriter::SerializedSize(inner_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -436,10 +434,11 @@
 size_t AlphaThresholdPaintFilter::SerializedSize() const {
   size_t region_size = region_.writeToMemory(nullptr);
   base::CheckedNumeric<size_t> total_size;
-  total_size = BaseSerializedSize() + sizeof(uint64_t) +
-               base::bits::AlignUp(region_size, PaintOpWriter::Alignment()) +
-               sizeof(inner_min_) + sizeof(outer_max_);
-  total_size += GetFilterSize(input_.get());
+  total_size = BaseSerializedSize() +
+               PaintOpWriter::SerializedSizeOfBytes(region_size) +
+               PaintOpWriter::SerializedSize(inner_min_) +
+               PaintOpWriter::SerializedSize(outer_max_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -477,9 +476,9 @@
 
 size_t XfermodePaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(blend_mode_);
-  total_size += GetFilterSize(background_.get());
-  total_size += GetFilterSize(foreground_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(blend_mode_);
+  total_size += PaintOpWriter::SerializedSize(background_.get());
+  total_size += PaintOpWriter::SerializedSize(foreground_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -525,10 +524,12 @@
 
 size_t ArithmeticPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(k1_) + sizeof(k2_) + sizeof(k3_) +
-      sizeof(k4_) + sizeof(enforce_pm_color_);
-  total_size += GetFilterSize(background_.get());
-  total_size += GetFilterSize(foreground_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(k1_) +
+      PaintOpWriter::SerializedSize(k2_) + PaintOpWriter::SerializedSize(k3_) +
+      PaintOpWriter::SerializedSize(k4_) +
+      PaintOpWriter::SerializedSize(enforce_pm_color_);
+  total_size += PaintOpWriter::SerializedSize(background_.get());
+  total_size += PaintOpWriter::SerializedSize(foreground_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -582,10 +583,16 @@
 
 size_t MatrixConvolutionPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(kernel_size_) + sizeof(size_t) +
-      kernel_->size() * sizeof(SkScalar) + sizeof(gain_) + sizeof(bias_) +
-      sizeof(kernel_offset_) + sizeof(tile_mode_) + sizeof(convolve_alpha_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(kernel_size_) +
+      PaintOpWriter::SerializedSize<size_t>() +
+      PaintOpWriter::SerializedSizeOfElements(kernel_->data(),
+                                              kernel_->size()) +
+      PaintOpWriter::SerializedSize(gain_) +
+      PaintOpWriter::SerializedSize(bias_) +
+      PaintOpWriter::SerializedSize(kernel_offset_) +
+      PaintOpWriter::SerializedSize(tile_mode_) +
+      PaintOpWriter::SerializedSize(convolve_alpha_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -631,11 +638,12 @@
 DisplacementMapEffectPaintFilter::~DisplacementMapEffectPaintFilter() = default;
 
 size_t DisplacementMapEffectPaintFilter::SerializedSize() const {
-  base::CheckedNumeric<size_t> total_size = BaseSerializedSize() +
-                                            sizeof(channel_x_) +
-                                            sizeof(channel_y_) + sizeof(scale_);
-  total_size += GetFilterSize(displacement_.get());
-  total_size += GetFilterSize(color_.get());
+  base::CheckedNumeric<size_t> total_size =
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(channel_x_) +
+      PaintOpWriter::SerializedSize(channel_y_) +
+      PaintOpWriter::SerializedSize(scale_);
+  total_size += PaintOpWriter::SerializedSize(displacement_.get());
+  total_size += PaintOpWriter::SerializedSize(color_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -674,9 +682,10 @@
 
 size_t ImagePaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(src_rect_) + sizeof(dst_rect_) +
-      sizeof(filter_quality_);
-  total_size += PaintOpWriter::GetImageSize(image_);
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(src_rect_) +
+      PaintOpWriter::SerializedSize(dst_rect_) +
+      PaintOpWriter::SerializedSize(filter_quality_);
+  total_size += PaintOpWriter::SerializedSize(image_);
   return total_size.ValueOrDefault(0u);
 }
 
@@ -795,9 +804,10 @@
 
 size_t RecordPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(record_bounds_) + sizeof(raster_scale_) +
-      sizeof(scaling_behavior_) + sizeof(bool);
-  total_size += PaintOpWriter::GetRecordSize(&record_);
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(record_bounds_) +
+      PaintOpWriter::SerializedSize(raster_scale_) +
+      PaintOpWriter::SerializedSize(scaling_behavior_);
+  total_size += PaintOpWriter::SerializedSize(record_);
   return total_size.ValueOrDefault(0u);
 }
 
@@ -842,11 +852,11 @@
 MergePaintFilter::~MergePaintFilter() = default;
 
 size_t MergePaintFilter::SerializedSize() const {
-  base::CheckedNumeric<size_t> total_size = 0u;
-  for (size_t i = 0; i < input_count(); ++i)
-    total_size += GetFilterSize(input_at(i));
-  total_size += BaseSerializedSize();
-  total_size += sizeof(input_count());
+  base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
+  total_size += PaintOpWriter::SerializedSize(input_count());
+  for (size_t i = 0; i < input_count(); ++i) {
+    total_size += PaintOpWriter::SerializedSize(input_at(i));
+  }
   return total_size.ValueOrDefault(0u);
 }
 
@@ -889,9 +899,10 @@
 
 size_t MorphologyPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(morph_type_) + sizeof(radius_x_) +
-      sizeof(radius_y_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(morph_type_) +
+      PaintOpWriter::SerializedSize(radius_x_) +
+      PaintOpWriter::SerializedSize(radius_y_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -924,9 +935,10 @@
 OffsetPaintFilter::~OffsetPaintFilter() = default;
 
 size_t OffsetPaintFilter::SerializedSize() const {
-  base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(dx_) + sizeof(dy_);
-  total_size += GetFilterSize(input_.get());
+  base::CheckedNumeric<size_t> total_size = BaseSerializedSize() +
+                                            PaintOpWriter::SerializedSize(dx_) +
+                                            PaintOpWriter::SerializedSize(dy_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -956,8 +968,9 @@
 
 size_t TilePaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(src_) + sizeof(dst_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(src_) +
+      PaintOpWriter::SerializedSize(dst_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -1006,9 +1019,13 @@
 TurbulencePaintFilter::~TurbulencePaintFilter() = default;
 
 size_t TurbulencePaintFilter::SerializedSize() const {
-  return BaseSerializedSize() + sizeof(turbulence_type_) +
-         sizeof(base_frequency_x_) + sizeof(base_frequency_y_) +
-         sizeof(num_octaves_) + sizeof(seed_) + sizeof(tile_size_);
+  return BaseSerializedSize() +
+         PaintOpWriter::SerializedSize(turbulence_type_) +
+         PaintOpWriter::SerializedSize(base_frequency_x_) +
+         PaintOpWriter::SerializedSize(base_frequency_y_) +
+         PaintOpWriter::SerializedSize(num_octaves_) +
+         PaintOpWriter::SerializedSize(seed_) +
+         PaintOpWriter::SerializedSize(tile_size_);
 }
 
 sk_sp<PaintFilter> TurbulencePaintFilter::SnapshotWithImagesInternal(
@@ -1057,9 +1074,10 @@
 size_t ShaderPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size = BaseSerializedSize();
   total_size += PaintShader::GetSerializedSize(shader_.get());
-  total_size += sizeof(alpha_);
-  total_size += sizeof(filter_quality_);  // filter quality
-  total_size += sizeof(dither_);
+  total_size += PaintOpWriter::SerializedSize(alpha_);
+  total_size +=
+      PaintOpWriter::SerializedSize(filter_quality_);  // filter quality
+  total_size += PaintOpWriter::SerializedSize(dither_);
   return total_size.ValueOrDefault(0u);
 }
 
@@ -1110,8 +1128,9 @@
 
 size_t MatrixPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(matrix_) + sizeof(filter_quality_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(matrix_) +
+      PaintOpWriter::SerializedSize(filter_quality_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -1163,10 +1182,13 @@
 
 size_t LightingDistantPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(lighting_type_) + sizeof(direction_) +
-      sizeof(light_color_) + sizeof(surface_scale_) + sizeof(kconstant_) +
-      sizeof(shininess_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
+      PaintOpWriter::SerializedSize(direction_) +
+      PaintOpWriter::SerializedSize(light_color_) +
+      PaintOpWriter::SerializedSize(surface_scale_) +
+      PaintOpWriter::SerializedSize(kconstant_) +
+      PaintOpWriter::SerializedSize(shininess_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -1222,10 +1244,13 @@
 
 size_t LightingPointPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(lighting_type_) + sizeof(location_) +
-      sizeof(light_color_) + sizeof(surface_scale_) + sizeof(kconstant_) +
-      sizeof(shininess_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
+      PaintOpWriter::SerializedSize(location_) +
+      PaintOpWriter::SerializedSize(light_color_) +
+      PaintOpWriter::SerializedSize(surface_scale_) +
+      PaintOpWriter::SerializedSize(kconstant_) +
+      PaintOpWriter::SerializedSize(shininess_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
@@ -1289,11 +1314,16 @@
 
 size_t LightingSpotPaintFilter::SerializedSize() const {
   base::CheckedNumeric<size_t> total_size =
-      BaseSerializedSize() + sizeof(lighting_type_) + sizeof(location_) +
-      sizeof(target_) + sizeof(specular_exponent_) + sizeof(cutoff_angle_) +
-      sizeof(light_color_) + sizeof(surface_scale_) + sizeof(kconstant_) +
-      sizeof(shininess_);
-  total_size += GetFilterSize(input_.get());
+      BaseSerializedSize() + PaintOpWriter::SerializedSize(lighting_type_) +
+      PaintOpWriter::SerializedSize(location_) +
+      PaintOpWriter::SerializedSize(target_) +
+      PaintOpWriter::SerializedSize(specular_exponent_) +
+      PaintOpWriter::SerializedSize(cutoff_angle_) +
+      PaintOpWriter::SerializedSize(light_color_) +
+      PaintOpWriter::SerializedSize(surface_scale_) +
+      PaintOpWriter::SerializedSize(kconstant_) +
+      PaintOpWriter::SerializedSize(shininess_);
+  total_size += PaintOpWriter::SerializedSize(input_.get());
   return total_size.ValueOrDefault(0u);
 }
 
diff --git a/cc/paint/paint_filter.h b/cc/paint/paint_filter.h
index f1a1267..532bc8dc 100644
--- a/cc/paint/paint_filter.h
+++ b/cc/paint/paint_filter.h
@@ -77,10 +77,6 @@
 
   static std::string TypeToString(Type type);
 
-  // Returns the size required to serialize the |filter|. Note that |filter| can
-  // be nullptr.
-  static size_t GetFilterSize(const PaintFilter* filter);
-
   Type type() const { return type_; }
   SkIRect filter_bounds(const SkIRect& src,
                         const SkMatrix& ctm,
diff --git a/cc/paint/paint_flags.cc b/cc/paint/paint_flags.cc
index 20e7f9a..5f90f2e 100644
--- a/cc/paint/paint_flags.cc
+++ b/cc/paint/paint_flags.cc
@@ -9,8 +9,8 @@
 #include "base/memory/values_equivalent.h"
 #include "base/notreached.h"
 #include "cc/paint/paint_filter.h"
+#include "cc/paint/paint_op.h"
 #include "cc/paint/paint_op_buffer.h"
-#include "cc/paint/paint_op_writer.h"
 #include "cc/paint/paint_shader.h"
 #include "third_party/skia/include/core/SkPathUtils.h"
 
@@ -202,18 +202,4 @@
          (image_filter_ && image_filter_->has_discardable_images());
 }
 
-size_t PaintFlags::GetSerializedSize() const {
-  return sizeof(color_) + sizeof(width_) + sizeof(miter_limit_) +
-         sizeof(blend_mode_) + sizeof(bitfields_uint_) +
-         PaintOpWriter::GetFlattenableSize(path_effect_.get()) +
-         PaintOpWriter::Alignment() +
-         PaintOpWriter::GetFlattenableSize(mask_filter_.get()) +
-         PaintOpWriter::Alignment() +
-         PaintOpWriter::GetFlattenableSize(color_filter_.get()) +
-         PaintOpWriter::Alignment() +
-         PaintOpWriter::GetFlattenableSize(draw_looper_.get()) +
-         PaintFilter::GetFilterSize(image_filter_.get()) +
-         PaintShader::GetSerializedSize(shader_.get());
-}
-
 }  // namespace cc
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h
index f843536..5b75b91 100644
--- a/cc/paint/paint_flags.h
+++ b/cc/paint/paint_flags.h
@@ -188,8 +188,6 @@
 
   bool HasDiscardableImages() const;
 
-  size_t GetSerializedSize() const;
-
  private:
   friend class PaintOpReader;
   friend class PaintOpWriter;
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc
index 056b3ad..9c81396 100644
--- a/cc/paint/paint_op.cc
+++ b/cc/paint/paint_op.cc
@@ -491,7 +491,6 @@
   writer.Write(
       CreateDrawImage(image, flags_to_serialize, sampling, current_ctm),
       &serialized_scale_adjustment);
-  writer.AssertAlignment(alignof(SkScalar));
   writer.Write(serialized_scale_adjustment.width());
   writer.Write(serialized_scale_adjustment.height());
 
@@ -513,7 +512,6 @@
   SkSize serialized_scale_adjustment = SkSize::Make(1.f, 1.f);
   writer.Write(CreateDrawImage(image, flags_to_serialize, sampling, matrix),
                &serialized_scale_adjustment);
-  writer.AssertAlignment(alignof(SkScalar));
   writer.Write(serialized_scale_adjustment.width());
   writer.Write(serialized_scale_adjustment.height());
 
@@ -536,7 +534,6 @@
                            const SkM44& current_ctm,
                            const SkM44& original_ctm) const {
   writer.Write(*flags_to_serialize, current_ctm);
-  writer.AssertAlignment(alignof(SkScalar));
   writer.Write(x0);
   writer.Write(y0);
   writer.Write(x1);
@@ -804,7 +801,6 @@
   reader.Read(&op->flags);
 
   reader.Read(&op->image);
-  reader.AssertAlignment(alignof(SkScalar));
   reader.Read(&op->scale_adjustment.fWidth);
   reader.Read(&op->scale_adjustment.fHeight);
 
@@ -820,7 +816,6 @@
   reader.Read(&op->flags);
 
   reader.Read(&op->image);
-  reader.AssertAlignment(alignof(SkScalar));
   reader.Read(&op->scale_adjustment.fWidth);
   reader.Read(&op->scale_adjustment.fHeight);
 
@@ -842,7 +837,6 @@
 PaintOp* DrawLineOp::Deserialize(PaintOpReader& reader, void* output) {
   DrawLineOp* op = new (output) DrawLineOp;
   reader.Read(&op->flags);
-  reader.AssertAlignment(alignof(SkScalar));
   reader.Read(&op->x0);
   reader.Read(&op->y0);
   reader.Read(&op->x1);
@@ -1660,17 +1654,15 @@
                           const SkM44& current_ctm,
                           const SkM44& original_ctm) const {
   // Need at least enough room for the header.
-  if (size < PaintOpWriter::HeaderBytes()) {
+  if (size < PaintOpWriter::kHeaderBytes) {
     return 0u;
   }
 
-  DCHECK_EQ(0u,
-            reinterpret_cast<uintptr_t>(memory) % PaintOpBuffer::kPaintOpAlign);
-
   PaintOpWriter writer(memory, size, options);
+  writer.ReserveOpHeader();
   g_serialize_functions[type](*this, writer, flags_to_serialize, current_ctm,
                               original_ctm);
-  return writer.Finish(type);
+  return writer.FinishOp(type);
 }
 
 PaintOp* PaintOp::Deserialize(const volatile void* input,
@@ -1679,15 +1671,13 @@
                               size_t output_size,
                               size_t* read_bytes,
                               const DeserializeOptions& options) {
-  DCHECK_GE(output_size, sizeof(LargestPaintOp));
+  DCHECK_GE(output_size, kLargestPaintOpAlignedSize);
 
   uint8_t type;
-  if (!PaintOpReader::ReadAndValidateOpHeader(input, input_size, &type,
-                                              read_bytes)) {
+  PaintOpReader reader(input, input_size, options);
+  if (!reader.ReadAndValidateOpHeader(&type, read_bytes)) {
     return nullptr;
   }
-
-  PaintOpReader reader(input, *read_bytes, options);
   return g_deserialize_functions[type](reader, output, output_size);
 }
 
@@ -1698,12 +1688,11 @@
     size_t* read_bytes,
     const DeserializeOptions& options) {
   uint8_t type;
-  if (!PaintOpReader::ReadAndValidateOpHeader(input, input_size, &type,
-                                              read_bytes)) {
+  PaintOpReader reader(input, input_size, options);
+  if (!reader.ReadAndValidateOpHeader(&type, read_bytes)) {
     return nullptr;
   }
 
-  PaintOpReader reader(input, *read_bytes, options);
   uint16_t op_aligned_size = g_type_to_aligned_size[type];
   if (auto* op = g_deserialize_functions[type](
           reader, buffer->AllocatePaintOp(op_aligned_size), op_aligned_size)) {
diff --git a/cc/paint/paint_op.h b/cc/paint/paint_op.h
index e521da98..ce94e7b 100644
--- a/cc/paint/paint_op.h
+++ b/cc/paint/paint_op.h
@@ -1034,6 +1034,12 @@
                               DrawImageRectOp,
                               DrawDRRectOp>::type;
 
+// When allocating a buffer for deserialization of a single PaintOp, the buffer
+// should be aligned as PaintOpBuffer::kPaintOpAlign, and the size should be
+// kLargestPaintOpAlignedSize instead of sizeof(LargestPaintOp).
+inline constexpr size_t kLargestPaintOpAlignedSize =
+    PaintOpBuffer::ComputeOpAlignedSize<LargestPaintOp>();
+
 }  // namespace cc
 
 #endif  // CC_PAINT_PAINT_OP_H_
diff --git a/cc/paint/paint_op_buffer_fuzzer.cc b/cc/paint/paint_op_buffer_fuzzer.cc
index a782f9c..1a15133 100644
--- a/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/cc/paint/paint_op_buffer_fuzzer.cc
@@ -73,7 +73,6 @@
             const uint8_t* data,
             size_t size) {
   const size_t kRasterDimension = 32;
-  const size_t kMaxSerializedSize = 1000000;
 
   SkImageInfo image_info = SkImageInfo::MakeN32(
       kRasterDimension, kRasterDimension, kOpaque_SkAlphaType);
@@ -89,16 +88,8 @@
       &transfer_cache_helper, paint_cache, strike_client, &scratch_buffer,
       true /* is_privileged */, nullptr /* shared_image_provider */);
 
-  // Need HeaderBytes() bytes to be able to read the header.
-  while (size >= cc::PaintOpWriter::HeaderBytes()) {
-    uint8_t serialized_type = 0;
-    size_t serialized_size = 0;
-    cc::PaintOpReader::ReadAndValidateOpHeader(data, size, &serialized_type,
-                                               &serialized_size);
-    if (serialized_size > kMaxSerializedSize) {
-      break;
-    }
-
+  // Need kHeaderBytes bytes to be able to read the header.
+  while (size >= cc::PaintOpWriter::kHeaderBytes) {
     std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
         static_cast<char*>(base::AlignedAlloc(
             sizeof(cc::LargestPaintOp), cc::PaintOpBuffer::kPaintOpAlign)));
@@ -114,10 +105,6 @@
 
     deserialized_op->DestroyThis();
 
-    if (serialized_size >= size) {
-      break;
-    }
-
     size -= bytes_read;
     data += bytes_read;
   }
@@ -134,12 +121,16 @@
 
   // Partition the data to use some bytes for populating the font cache.
   uint32_t bytes_for_fonts = data[0];
-  if (bytes_for_fonts > size)
+  if (bytes_for_fonts > size) {
     bytes_for_fonts = size / 2;
-  // PaintOpBuffer only accepts 4 bytes aligned buffer.
-  bytes_for_fonts = base::bits::AlignDown(
-      bytes_for_fonts,
-      base::checked_cast<uint32_t>(cc::PaintOpWriter::Alignment()));
+  }
+  const uint8_t* raster_data = base::bits::AlignDown(
+      data + bytes_for_fonts, cc::PaintOpWriter::kMaxAlignment);
+  if (raster_data < data) {
+    return 0;
+  }
+  bytes_for_fonts = raster_data - data;
+  size_t raster_size = size - bytes_for_fonts;
 
   FontSupport font_support;
   scoped_refptr<gpu::ServiceFontManager> font_manager(
@@ -150,15 +141,13 @@
   if (bytes_for_fonts > 0u) {
     font_manager->Deserialize(reinterpret_cast<const char*>(data),
                               bytes_for_fonts, &locked_handles);
-    data += bytes_for_fonts;
-    size -= bytes_for_fonts;
   }
 
   auto context_provider_no_support = viz::TestContextProvider::Create();
   context_provider_no_support->BindToCurrentSequence();
   CHECK(!context_provider_no_support->GrContext()->supportsDistanceFieldText());
   Raster(context_provider_no_support, font_manager->strike_client(),
-         &paint_cache, data, size);
+         &paint_cache, raster_data, raster_size);
 
   auto context_provider_with_support = viz::TestContextProvider::Create(
       std::string("GL_OES_standard_derivatives"));
@@ -166,7 +155,7 @@
   CHECK(
       context_provider_with_support->GrContext()->supportsDistanceFieldText());
   Raster(context_provider_with_support, font_manager->strike_client(),
-         &paint_cache, data, size);
+         &paint_cache, raster_data, raster_size);
 
   font_manager->Unlock(locked_handles);
   font_manager->Destroy();
diff --git a/cc/paint/paint_op_buffer_serializer.cc b/cc/paint/paint_op_buffer_serializer.cc
index 44becf5..30fed4d 100644
--- a/cc/paint/paint_op_buffer_serializer.cc
+++ b/cc/paint/paint_op_buffer_serializer.cc
@@ -13,6 +13,7 @@
 #include "base/trace_event/trace_event.h"
 #include "cc/paint/clear_for_opaque_raster.h"
 #include "cc/paint/paint_op_buffer_iterator.h"
+#include "cc/paint/paint_op_writer.h"
 #include "cc/paint/scoped_raster_flags.h"
 #include "skia/ext/legacy_display_globals.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
@@ -309,8 +310,7 @@
     return false;
   }
 
-  DCHECK_GE(bytes, 4u);
-  DCHECK_EQ(bytes % PaintOpBuffer::kPaintOpAlign, 0u);
+  DCHECK_GE(bytes, PaintOpWriter::kHeaderBytes);
   return true;
 }
 
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 2cec213c..cc2392c 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -67,17 +67,21 @@
 // An arbitrary size guaranteed to fit the size of any serialized op in this
 // unit test.  This can also be used for deserialized op size safely in this
 // unit test suite as generally deserialized ops are smaller.
-static constexpr size_t kBufferBytesPerOp = 1000 + sizeof(LargestPaintOp);
+static constexpr size_t kSerializedBytesPerOp = 1000 + sizeof(LargestPaintOp);
 
-static constexpr size_t kDefaultBufferSize = 4096;
-
-std::unique_ptr<char, base::AlignedFreeDeleter> AllocateBuffer(size_t size) {
-  return std::unique_ptr<char, base::AlignedFreeDeleter>(static_cast<char*>(
-      base::AlignedAlloc(size, PaintOpBuffer::kPaintOpAlign)));
+static constexpr size_t kDefaultSerializedBufferSize = 4096;
+std::unique_ptr<char, base::AlignedFreeDeleter> AllocateSerializedBuffer(
+    size_t size = kDefaultSerializedBufferSize) {
+  return PaintOpWriter::AllocateAlignedBuffer(size);
 }
 
-std::unique_ptr<char, base::AlignedFreeDeleter> AllocateDefaultBuffer() {
-  return AllocateBuffer(kDefaultBufferSize);
+bool ReadAndValidateOpHeader(const void* memory,
+                             size_t size,
+                             uint8_t* op_type,
+                             size_t* serialized_size) {
+  return PaintOpReader(memory, size,
+                       TestOptionsProvider().deserialize_options())
+      .ReadAndValidateOpHeader(op_type, serialized_size);
 }
 
 }  // namespace
@@ -1276,8 +1280,8 @@
 
       uint8_t type = 0;
       size_t bytes_to_read = 0;
-      EXPECT_TRUE(PaintOpReader::ReadAndValidateOpHeader(
-          current_, remaining_, &type, &bytes_to_read));
+      EXPECT_TRUE(
+          ReadAndValidateOpHeader(current_, remaining_, &type, &bytes_to_read));
       EXPECT_EQ(op.type, type);
       EXPECT_EQ(bytes_written, bytes_to_read);
 
@@ -1286,10 +1290,13 @@
       current_ += bytes_written;
       remaining_ -= bytes_written;
 
-      // Number of bytes bytes_written must be a multiple of PaintOpAlign
-      // unless the buffer is filled entirely.
+      // Number of bytes bytes_written must be a multiple of
+      // PaintOpWriter::kMaxAlignment unless the buffer is filled
+      // entirely.
       if (remaining_ != 0u) {
-        DCHECK_EQ(0u, bytes_written % PaintOpBuffer::kPaintOpAlign);
+        EXPECT_EQ(
+            bytes_written,
+            base::bits::AlignUp(bytes_written, PaintOpWriter::kMaxAlignment));
       }
     }
   }
@@ -1362,8 +1369,7 @@
         current_(current),
         input_size_(input_size),
         remaining_(remaining),
-        options_(options),
-        data_(AllocateBuffer(sizeof(LargestPaintOp))) {
+        options_(options) {
     DeserializeCurrentOp();
   }
 
@@ -1379,9 +1385,9 @@
 
     if (!remaining_)
       return;
-    deserialized_op_ = PaintOp::Deserialize(current_, remaining_, data_.get(),
-                                            sizeof(LargestPaintOp),
-                                            &last_bytes_read_, options_);
+    deserialized_op_ = PaintOp::Deserialize(
+        current_, remaining_, paint_op_buffer_data_,
+        std::size(paint_op_buffer_data_), &last_bytes_read_, options_);
   }
 
   raw_ptr<const void> input_ = nullptr;
@@ -1390,7 +1396,8 @@
   size_t remaining_ = 0u;
   size_t last_bytes_read_ = 0u;
   PaintOp::DeserializeOptions options_;
-  std::unique_ptr<char, base::AlignedFreeDeleter> data_;
+  alignas(PaintOpBuffer::kPaintOpAlign) char paint_op_buffer_data_
+      [kLargestPaintOpAlignedSize];
   raw_ptr<PaintOp> deserialized_op_ = nullptr;
 };
 
@@ -1874,10 +1881,9 @@
   }
 
   void ResizeOutputBuffer() {
-    // An arbitrary deserialization buffer size that should fit all the ops
-    // in the buffer_.
-    output_size_ = kBufferBytesPerOp * buffer_.size();
-    output_ = AllocateBuffer(output_size_);
+    // An serialization buffer size that should fit all the ops in the buffer_.
+    output_size_ = kSerializedBytesPerOp * buffer_.size();
+    output_ = AllocateSerializedBuffer(output_size_);
   }
 
   bool IsTypeSupported() {
@@ -1974,8 +1980,9 @@
         "%s #%zu", PaintOpTypeToString(GetParamType()).c_str(), op_idx));
     size_t expected_bytes = bytes_written[op_idx];
     EXPECT_GT(expected_bytes, 0u);
-    EXPECT_EQ(expected_bytes,
-              base::bits::AlignUp(expected_bytes, PaintOpWriter::Alignment()));
+    EXPECT_EQ(
+        expected_bytes,
+        base::bits::AlignUp(expected_bytes, PaintOpWriter::kMaxAlignment));
 
     // Attempt to write op into a buffer of size |i|, and only expect
     // it to succeed if the buffer is large enough.
@@ -2012,17 +2019,16 @@
   char* first = static_cast<char*>(output_.get());
   char* current = first;
 
-  static constexpr size_t kAlign = PaintOpBuffer::kPaintOpAlign;
-  static constexpr size_t kOutputOpSize = kBufferBytesPerOp;
-  auto deserialize_buffer = AllocateBuffer(kOutputOpSize);
+  static constexpr size_t kAlign = PaintOpWriter::kMaxAlignment;
+  static constexpr size_t kOutputOpSize = kSerializedBytesPerOp;
+  auto deserialize_buffer = AllocateSerializedBuffer(kOutputOpSize);
 
   size_t total_read = 0;
   for (size_t op_idx = 0; op_idx < buffer_.size(); ++op_idx) {
     uint8_t serialized_type = 0;
     size_t serialized_size = 0;
-    PaintOpReader::ReadAndValidateOpHeader(current,
-                                           PaintOpWriter::HeaderBytes(),
-                                           &serialized_type, &serialized_size);
+    ReadAndValidateOpHeader(current, PaintOpWriter::kHeaderBytes,
+                            &serialized_type, &serialized_size);
     EXPECT_EQ(static_cast<uint8_t>(GetParamType()), serialized_type);
 
     // Read from buffers of various sizes to make sure that having a serialized
@@ -2110,16 +2116,15 @@
   ResizeOutputBuffer();
 
   TestOptionsProvider options_provider;
-  size_t deserialized_size =
-      sizeof(LargestPaintOp) + PaintOpWriter::kMaxSerializedSize;
-  auto deserialized = AllocateBuffer(deserialized_size);
+  alignas(PaintOpBuffer::kPaintOpAlign) char
+      deserialized[kLargestPaintOpAlignedSize];
   for (const PaintOp& op : buffer_) {
     size_t bytes_written = op.Serialize(output_.get(), output_size_,
                                         options_provider.serialize_options(),
                                         nullptr, SkM44(), SkM44());
     size_t bytes_read = 0u;
     PaintOp* written = PaintOp::Deserialize(
-        output_.get(), bytes_written, deserialized.get(), deserialized_size,
+        output_.get(), bytes_written, deserialized, std::size(deserialized),
         &bytes_read, options_provider.deserialize_options());
     ASSERT_TRUE(written) << PaintOpTypeToString(GetParamType());
     EXPECT_THAT(op, PaintOpEq<const PaintOp&>(*written));
@@ -2131,9 +2136,9 @@
     bytes_written = op.Serialize(output_.get(), output_size_,
                                  options_provider.serialize_options(),
                                  &override_flags, SkM44(), SkM44());
-    written = PaintOp::Deserialize(
-        output_.get(), bytes_written, deserialized.get(), deserialized_size,
-        &bytes_read, options_provider.deserialize_options());
+    written = PaintOp::Deserialize(output_.get(), bytes_written, deserialized,
+                                   std::size(deserialized), &bytes_read,
+                                   options_provider.deserialize_options());
     ASSERT_TRUE(written);
     ASSERT_TRUE(written->IsPaintOpWithFlags());
     EXPECT_EQ(static_cast<const PaintOpWithFlags*>(written)->flags.getAlpha(),
@@ -2153,9 +2158,9 @@
   preamble.full_raster_rect = preamble.playback_rect;
   preamble.requires_clear = true;
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer, nullptr, preamble);
   ASSERT_NE(serializer.written(), 0u);
@@ -2188,9 +2193,9 @@
   PaintOpBuffer buffer;
   buffer.push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer, nullptr, preamble);
   ASSERT_NE(serializer.written(), 0u);
@@ -2224,9 +2229,9 @@
   PaintOpBuffer buffer;
   buffer.push<DrawRecordOp>(record);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   PaintOpBufferSerializer::Preamble preamble;
   serializer.Serialize(buffer, nullptr, preamble);
@@ -2270,9 +2275,10 @@
         static_cast<SkScalar>(test_case.image_rect.x()),
         static_cast<SkScalar>(test_case.image_rect.y()));
 
-    auto memory = AllocateDefaultBuffer();
+    auto memory = AllocateSerializedBuffer();
     TestOptionsProvider options_provider;
-    SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+    SimpleBufferSerializer serializer(memory.get(),
+                                      kDefaultSerializedBufferSize,
                                       options_provider.serialize_options());
     PaintOpBufferSerializer::Preamble preamble;
     preamble.playback_rect = test_case.clip_rect;
@@ -2319,9 +2325,9 @@
   preamble.full_raster_rect = preamble.playback_rect;
   preamble.requires_clear = false;
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer, nullptr, preamble);
   ASSERT_NE(serializer.written(), 0u);
@@ -2347,10 +2353,8 @@
 
 // Test generic PaintOp deserializing failure cases.
 TEST(PaintOpBufferTest, PaintOpDeserialize) {
-  static constexpr size_t kSize = sizeof(LargestPaintOp) + 100;
-  static constexpr size_t kAlign = PaintOpBuffer::kPaintOpAlign;
-  auto input = AllocateBuffer(kSize);
-  auto output = AllocateBuffer(kSize);
+  auto input = AllocateSerializedBuffer(kSerializedBytesPerOp);
+  alignas(PaintOpBuffer::kPaintOpAlign) char output[kLargestPaintOpAlignedSize];
 
   PaintOpBuffer buffer;
   buffer.push<DrawColorOp>(SkColors::kMagenta, SkBlendMode::kSrc);
@@ -2360,16 +2364,16 @@
   ASSERT_TRUE(op);
 
   TestOptionsProvider options_provider;
-  size_t bytes_written =
-      op->Serialize(input.get(), kSize, options_provider.serialize_options(),
-                    nullptr, SkM44(), SkM44());
+  size_t bytes_written = op->Serialize(input.get(), kSerializedBytesPerOp,
+                                       options_provider.serialize_options(),
+                                       nullptr, SkM44(), SkM44());
   ASSERT_GT(bytes_written, 0u);
 
   // Can deserialize from exactly the right size.
   size_t bytes_read = 0;
-  PaintOp* success =
-      PaintOp::Deserialize(input.get(), bytes_written, output.get(), kSize,
-                           &bytes_read, options_provider.deserialize_options());
+  PaintOp* success = PaintOp::Deserialize(
+      input.get(), bytes_written, output, std::size(output), &bytes_read,
+      options_provider.deserialize_options());
   ASSERT_TRUE(success);
   EXPECT_EQ(bytes_written, bytes_read);
   success->DestroyThis();
@@ -2377,7 +2381,7 @@
   // Fail to deserialize if serialized_size goes past input size (the
   // DeserializationFailures test above tests if the serialized_size is lying).
   for (size_t i = 0; i < bytes_written - 1; ++i) {
-    EXPECT_FALSE(PaintOp::Deserialize(input.get(), i, output.get(), kSize,
+    EXPECT_FALSE(PaintOp::Deserialize(input.get(), i, output, std::size(output),
                                       &bytes_read,
                                       options_provider.deserialize_options()));
   }
@@ -2385,21 +2389,22 @@
   // Unaligned serialized_size should fail to deserialize.
   uint8_t serialized_type = 0;
   size_t serialized_size = 0;
-  PaintOpReader::ReadAndValidateOpHeader(input.get(), bytes_written,
-                                         &serialized_type, &serialized_size);
-  EXPECT_EQ(0u, serialized_size % kAlign);
+  ReadAndValidateOpHeader(input.get(), bytes_written, &serialized_type,
+                          &serialized_size);
+  EXPECT_EQ(serialized_size,
+            base::bits::AlignUp(serialized_size, PaintOpWriter::kMaxAlignment));
   PaintOpWriter::WriteHeaderForTesting(input.get(), serialized_type,
                                        serialized_size - 1);
-  EXPECT_FALSE(PaintOp::Deserialize(input.get(), bytes_written, output.get(),
-                                    kSize, &bytes_read,
+  EXPECT_FALSE(PaintOp::Deserialize(input.get(), bytes_written, output,
+                                    std::size(output), &bytes_read,
                                     options_provider.deserialize_options()));
 
   // Bogus types fail to deserialize.
   PaintOpWriter::WriteHeaderForTesting(
       input.get(), static_cast<uint8_t>(PaintOpType::LastPaintOpType) + 1,
       serialized_size);
-  EXPECT_FALSE(PaintOp::Deserialize(input.get(), bytes_written, output.get(),
-                                    kSize, &bytes_read,
+  EXPECT_FALSE(PaintOp::Deserialize(input.get(), bytes_written, output,
+                                    std::size(output), &bytes_read,
                                     options_provider.deserialize_options()));
 }
 
@@ -2407,13 +2412,13 @@
 // asserts on invalid values in several places so these are not safe to pass
 // them to the SkCanvas API.
 TEST(PaintOpBufferTest, ValidateRects) {
-  size_t buffer_size = kBufferBytesPerOp;
-  auto serialized = AllocateBuffer(buffer_size);
-  auto deserialized = AllocateBuffer(buffer_size);
+  auto serialized = AllocateSerializedBuffer(kSerializedBytesPerOp);
+  alignas(PaintOpBuffer::kPaintOpAlign) char
+      deserialized[kLargestPaintOpAlignedSize];
   // We may read uninitialized gaps in this test. Initialize the buffer with a
   // special value to avoid MSAN errors.
-  memset(serialized.get(), 0xA5, buffer_size);
-  memset(deserialized.get(), 0x5A, buffer_size);
+  memset(serialized.get(), 0xA5, kSerializedBytesPerOp);
+  memset(deserialized, 0x5A, std::size(deserialized));
 
   float rect_size = 0x8.765432p1;
   SkRect rect = SkRect::MakeWH(rect_size, rect_size);
@@ -2438,14 +2443,14 @@
   // Every op should serialize but fail to deserialize due to the bad rect.
   int op_idx = 0;
   for (const PaintOp& op : buffer) {
-    size_t bytes_written = op.Serialize(serialized.get(), buffer_size,
+    size_t bytes_written = op.Serialize(serialized.get(), kSerializedBytesPerOp,
                                         options_provider.serialize_options(),
                                         nullptr, SkM44(), SkM44());
     ASSERT_GT(bytes_written, sizeof(float));
 
     size_t bytes_read = 0;
     PaintOp* deserialized_op = PaintOp::Deserialize(
-        serialized.get(), bytes_written, deserialized.get(), buffer_size,
+        serialized.get(), bytes_written, deserialized, std::size(deserialized),
         &bytes_read, options_provider.deserialize_options());
     EXPECT_TRUE(deserialized_op) << op_idx;
     deserialized_op->DestroyThis();
@@ -2460,7 +2465,7 @@
       }
     }
     deserialized_op = PaintOp::Deserialize(
-        serialized.get(), bytes_written, deserialized.get(), buffer_size,
+        serialized.get(), bytes_written, deserialized, std::size(deserialized),
         &bytes_read, options_provider.deserialize_options());
     EXPECT_FALSE(deserialized_op) << op_idx;
 
@@ -3067,9 +3072,9 @@
                                          SkTileMode::kRepeat, nullptr));
   buffer.push<DrawOvalOp>(SkRect::MakeWH(10, 10), flags);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
   ASSERT_NE(serializer.written(), 0u);
@@ -3176,20 +3181,18 @@
     SCOPED_TRACE(i);
 
     auto& filter = filters[i];
-    std::vector<uint8_t> memory;
     size_t buffer_size = filter->type() == PaintFilter::Type::kPaintRecord
-                             ? kDefaultBufferSize
-                             : PaintFilter::GetFilterSize(filter.get());
-    buffer_size += PaintOpWriter::HeaderBytes();
-    memory.resize(buffer_size);
+                             ? kDefaultSerializedBufferSize
+                             : PaintOpWriter::SerializedSize(filter.get());
+    auto memory = AllocateSerializedBuffer(buffer_size);
 
-    PaintOpWriter writer(memory.data(), memory.size(),
+    PaintOpWriter writer(memory.get(), buffer_size,
                          options_provider.serialize_options(), GetParam());
     writer.Write(filter.get(), ctm);
     ASSERT_GT(writer.size(), 0u) << PaintFilter::TypeToString(filter->type());
 
     sk_sp<PaintFilter> deserialized_filter;
-    PaintOpReader reader(memory.data(), writer.size(),
+    PaintOpReader reader(memory.get(), writer.size(),
                          options_provider.deserialize_options(), GetParam());
     reader.Read(&deserialized_filter);
     ASSERT_TRUE(deserialized_filter);
@@ -3237,7 +3240,7 @@
                                               SkRect::MakeWH(100, 100));
 
   TestOptionsProvider options_provider;
-  std::vector<uint8_t> memory(kDefaultBufferSize);
+  std::vector<uint8_t> memory(kDefaultSerializedBufferSize);
   PaintOpWriter writer(memory.data(), memory.size(),
                        options_provider.serialize_options(), false);
   writer.Write(filter.get(), SkM44());
@@ -3260,7 +3263,7 @@
 }
 
 TEST(PaintOpBufferTest, PaintRecordShaderSerialization) {
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   PaintOpBuffer shader_buffer;
   shader_buffer.push<DrawRectOp>(SkRect::MakeXYWH(0, 0, 1, 1), PaintFlags());
 
@@ -3272,7 +3275,7 @@
   PaintOpBuffer buffer;
   buffer.push<DrawRectOp>(SkRect::MakeXYWH(1, 2, 3, 4), flags);
 
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
   ASSERT_TRUE(serializer.valid());
@@ -3303,7 +3306,7 @@
 // Skottie-specific deserialization failure case.
 TEST(PaintOpBufferTest,
      DrawSkottieOpSerializationFailureFromUnPrivilegedProcess) {
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
 
   scoped_refptr<SkottieWrapper> skottie =
       CreateSkottie(gfx::Size(100, 100), /*duration_secs=*/1);
@@ -3320,7 +3323,7 @@
 
   // Serialize
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
   ASSERT_TRUE(serializer.valid());
@@ -3530,9 +3533,9 @@
       PaintFlags::FilterQuality::kLow);
   const bool enable_security_constraints = true;
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  PaintOpWriter writer(memory.get(), kDefaultBufferSize,
+  PaintOpWriter writer(memory.get(), kDefaultSerializedBufferSize,
                        options_provider.serialize_options(),
                        enable_security_constraints);
   writer.Write(filter.get(), SkM44());
@@ -3562,9 +3565,9 @@
 
   buffer.push<DrawImageRectOp>(CreateDiscardablePaintImage(gfx::Size(32, 16)),
                                src, dst, SkCanvas::kStrict_SrcRectConstraint);
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
 
@@ -3589,9 +3592,9 @@
   flags.setShader(shader);
   buffer.push<DrawRectOp>(SkRect::MakeWH(10.f, 10.f), flags);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
 
@@ -3614,7 +3617,7 @@
   auto* transfer_cache = options_provider.transfer_cache_helper();
 
   // Generate serialized |memory|.
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   size_t memory_written = 0;
   {
     PaintOpBuffer buffer;
@@ -3622,7 +3625,8 @@
     flags.setShader(shader);
     buffer.push<DrawRectOp>(SkRect::MakeWH(10.f, 10.f), flags);
 
-    SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+    SimpleBufferSerializer serializer(memory.get(),
+                                      kDefaultSerializedBufferSize,
                                       options_provider.serialize_options());
     serializer.Serialize(buffer);
     memory_written = serializer.written();
@@ -3630,7 +3634,7 @@
 
   // Generate serialized |memory_scaled|, which is the same pob, but with
   // a scale factor.
-  auto memory_scaled = AllocateDefaultBuffer();
+  auto memory_scaled = AllocateSerializedBuffer();
   size_t memory_scaled_written = 0;
   {
     PaintOpBuffer buffer;
@@ -3640,7 +3644,8 @@
     buffer.push<ScaleOp>(2.0f, 3.7f);
     buffer.push<DrawRectOp>(SkRect::MakeWH(10.f, 10.f), flags);
 
-    SimpleBufferSerializer serializer(memory_scaled.get(), kDefaultBufferSize,
+    SimpleBufferSerializer serializer(memory_scaled.get(),
+                                      kDefaultSerializedBufferSize,
                                       options_provider.serialize_options());
     serializer.Serialize(buffer);
     memory_scaled_written = serializer.written();
@@ -3718,13 +3723,13 @@
   auto* transfer_cache = options_provider.transfer_cache_helper();
 
   // Generate serialized |memory|.
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   PaintOpBuffer buffer;
   PaintFlags flags;
   flags.setShader(shader);
   buffer.push<DrawRectOp>(SkRect::MakeWH(10.f, 10.f), flags);
 
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   options_provider.context_supports_distance_field_text();
   serializer.Serialize(buffer);
@@ -3759,9 +3764,9 @@
   flags.setImageFilter(filter);
   buffer.push<DrawRectOp>(SkRect::MakeWH(10.f, 10.f), flags);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
 
@@ -3793,9 +3798,9 @@
   PaintOpBuffer buffer;
   buffer.push<DrawImageOp>(PaintImage(), 0.f, 0.f);
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   TestOptionsProvider options_provider;
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
   ASSERT_TRUE(serializer.valid());
@@ -3943,10 +3948,10 @@
 
   TestOptionsProvider options_provider;
 
-  auto memory = AllocateDefaultBuffer();
+  auto memory = AllocateSerializedBuffer();
   PaintOpBuffer buffer;
   buffer.push<DrawPathOp>(path, flags, UsePaintCache::kEnabled);
-  SimpleBufferSerializer serializer(memory.get(), kDefaultBufferSize,
+  SimpleBufferSerializer serializer(memory.get(), kDefaultSerializedBufferSize,
                                     options_provider.serialize_options());
   serializer.Serialize(buffer);
 
diff --git a/cc/paint/paint_op_perftest.cc b/cc/paint/paint_op_perftest.cc
index 89583a1..699ec58 100644
--- a/cc/paint/paint_op_perftest.cc
+++ b/cc/paint/paint_op_perftest.cc
@@ -9,6 +9,7 @@
 #include "base/timer/lap_timer.h"
 #include "cc/paint/paint_op_buffer.h"
 #include "cc/paint/paint_op_buffer_serializer.h"
+#include "cc/paint/paint_op_writer.h"
 #include "cc/paint/paint_shader.h"
 #include "cc/test/test_options_provider.h"
 #include "testing/perf/perf_result_reporter.h"
@@ -32,12 +33,8 @@
       : timer_(kNumWarmupRuns,
                base::Milliseconds(kTimeLimitMillis),
                kTimeCheckInterval),
-        serialized_data_(static_cast<char*>(
-            base::AlignedAlloc(kMaxSerializedBufferBytes,
-                               PaintOpBuffer::kPaintOpAlign))),
-        deserialized_data_(static_cast<char*>(
-            base::AlignedAlloc(sizeof(LargestPaintOp),
-                               PaintOpBuffer::kPaintOpAlign))) {}
+        serialized_data_(
+            PaintOpWriter::AllocateAlignedBuffer(kMaxSerializedBufferBytes)) {}
 
   void RunTest(const std::string& name, const PaintOpBuffer& buffer) {
     TestOptionsProvider test_options_provider;
@@ -73,8 +70,8 @@
 
       while (true) {
         PaintOp* deserialized_op = PaintOp::Deserialize(
-            to_read, remaining_read_bytes, deserialized_data_.get(),
-            sizeof(LargestPaintOp), &bytes_read,
+            to_read, remaining_read_bytes, deserialized_data_,
+            kLargestPaintOpAlignedSize, &bytes_read,
             test_options_provider.deserialize_options());
         CHECK(deserialized_op);
         deserialized_op->DestroyThis();
@@ -98,7 +95,8 @@
  protected:
   base::LapTimer timer_;
   std::unique_ptr<char, base::AlignedFreeDeleter> serialized_data_;
-  std::unique_ptr<char, base::AlignedFreeDeleter> deserialized_data_;
+  alignas(PaintOpBuffer::kPaintOpAlign) char deserialized_data_
+      [kLargestPaintOpAlignedSize];
 };
 
 // Ops that can be memcopied both when serializing and deserializing.
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 66b63c4..3399ff4 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -54,6 +54,18 @@
 
 }  // namespace
 
+PaintOpReader::PaintOpReader(const volatile void* memory,
+                             size_t size,
+                             const PaintOp::DeserializeOptions& options,
+                             bool enable_security_constraints)
+    : memory_(static_cast<const volatile char*>(memory)),
+      remaining_bytes_(
+          base::bits::AlignDown(size, PaintOpWriter::kDefaultAlignment)),
+      options_(options),
+      enable_security_constraints_(enable_security_constraints) {
+  PaintOpWriter::AssertAlignment(memory, BufferAlignment());
+}
+
 // static
 void PaintOpReader::FixupMatrixPostSerialization(SkMatrix* matrix) {
   // Can't trust malicious clients to provide the correct derived matrix type.
@@ -64,25 +76,24 @@
     matrix->dirtyMatrixTypeCache();
 }
 
-// static
-bool PaintOpReader::ReadAndValidateOpHeader(const volatile void* input,
-                                            size_t input_size,
-                                            uint8_t* type,
-                                            size_t* bytes_to_read) {
-  static_assert(PaintOpWriter::HeaderBytes() == sizeof(uint32_t));
-  if (input_size < PaintOpWriter::HeaderBytes()) {
+bool PaintOpReader::ReadAndValidateOpHeader(uint8_t* type,
+                                            size_t* serialized_size) {
+  static_assert(PaintOpWriter::kHeaderBytes == sizeof(uint32_t));
+  uint32_t header;
+  Read(&header);
+  if (!valid_) {
     return false;
   }
-  uint32_t header = reinterpret_cast<const volatile uint32_t*>(input)[0];
   *type = static_cast<uint8_t>(header & 0xFF);
-  *bytes_to_read = header >> 8;
+  *serialized_size = header >> 8;
 
-  if (input_size < *bytes_to_read) {
+  size_t remaining_op_bytes = *serialized_size - PaintOpWriter::kHeaderBytes;
+  if (remaining_bytes_ < remaining_op_bytes) {
     return false;
   }
-  // For now we require serialized PaintOps are aligned to kPaintOpAlign.
-  // TODO(wangxianzhu): Revisit the requirement.
-  if (*bytes_to_read % PaintOpBuffer::kPaintOpAlign != 0) {
+  remaining_bytes_ = remaining_op_bytes;
+
+  if (*serialized_size % BufferAlignment() != 0) {
     return false;
   }
   if (*type > static_cast<uint8_t>(PaintOpType::LastPaintOpType)) {
@@ -95,10 +106,10 @@
 void PaintOpReader::ReadSimple(T* val) {
   static_assert(std::is_trivially_copyable_v<T>);
 
-  DCHECK_EQ(memory_, base::bits::AlignUp(memory_, PaintOpWriter::Alignment()));
+  AssertFieldAlignment();
   // Align everything to 4 bytes, as the writer does.
   static constexpr size_t size =
-      base::bits::AlignUp(sizeof(T), PaintOpWriter::Alignment());
+      base::bits::AlignUp(sizeof(T), PaintOpWriter::kDefaultAlignment);
 
   if (remaining_bytes_ < size)
     SetInvalid(DeserializationError::kInsufficientRemainingBytes_ReadSimple);
@@ -114,6 +125,7 @@
 
   memory_ += size;
   remaining_bytes_ -= size;
+  AssertFieldAlignment();
 }
 
 uint8_t* PaintOpReader::CopyScratchSpace(size_t bytes) {
@@ -153,7 +165,7 @@
 }
 
 void PaintOpReader::ReadData(size_t bytes, void* data) {
-  DCHECK_EQ(memory_, base::bits::AlignUp(memory_, PaintOpWriter::Alignment()));
+  AssertFieldAlignment();
   if (bytes == 0)
     return;
 
@@ -167,20 +179,14 @@
 }
 
 void PaintOpReader::ReadSize(size_t* size) {
-  AlignMemory(8);
-  if (!valid_)
-    return;
-  uint64_t size64 = 0;
-  ReadSimple(&size64);
-  *size = size64;
+  ReadSimple(size);
 }
 
 void PaintOpReader::Read(SkScalar* data) {
   ReadSimple(data);
 }
 
-    void
-    PaintOpReader::Read(uint8_t* data) {
+void PaintOpReader::Read(uint8_t* data) {
   ReadSimple(data);
 }
 
@@ -319,6 +325,13 @@
       case PaintOp::SerializedImageType::kImageData: {
         SkColorType color_type;
         Read(&color_type);
+        // Color types requiring alignment larger than kDefaultAlignment is not
+        // supported.
+        if (static_cast<size_t>(SkColorTypeBytesPerPixel(color_type)) >
+            PaintOpWriter::kDefaultAlignment) {
+          SetInvalid(DeserializationError::kReadImageFailure);
+          return;
+        }
         uint32_t width;
         Read(&width);
         uint32_t height;
@@ -477,7 +490,7 @@
 }
 
 void PaintOpReader::Read(sk_sp<GrSlug>* slug) {
-  AssertAlignment(PaintOpWriter::Alignment());
+  AssertFieldAlignment();
 
   size_t data_bytes = 0u;
   ReadSize(&data_bytes);
@@ -737,6 +750,10 @@
 }
 
 void PaintOpReader::AlignMemory(size_t alignment) {
+  DCHECK_GE(alignment, PaintOpWriter::kDefaultAlignment);
+  DCHECK_LE(alignment, BufferAlignment());
+  // base::bits::AlignUp() below will check if alignment is a power of two.
+
   size_t padding = base::bits::AlignUp(memory_, alignment) - memory_;
   if (padding > remaining_bytes_)
     SetInvalid(DeserializationError::kInsufficientRemainingBytes_AlignMemory);
@@ -794,7 +811,7 @@
     crop_rect.emplace(rect);
   }
 
-  AssertAlignment(PaintOpWriter::Alignment());
+  AssertFieldAlignment();
   switch (type) {
     case PaintFilter::Type::kNullFilter:
       NOTREACHED();
@@ -1381,7 +1398,7 @@
 size_t PaintOpReader::Read(absl::optional<PaintRecord>* record) {
   size_t size_bytes = 0;
   ReadSize(&size_bytes);
-  AlignMemory(PaintOpBuffer::kPaintOpAlign);
+
   if (enable_security_constraints_) {
     // Validate that the record was not serialized if security constraints are
     // enabled.
@@ -1393,6 +1410,8 @@
     return 0;
   }
 
+  AlignMemory(BufferAlignment());
+
   if (size_bytes > remaining_bytes_)
     SetInvalid(
         DeserializationError::kInsufficientRemainingBytes_Read_PaintRecord);
@@ -1429,9 +1448,9 @@
 }
 
 inline void PaintOpReader::DidRead(size_t bytes_read) {
-  // All data are aligned with PaintOpWriter::Alignment() at least.
+  // All data are aligned with PaintOpWriter::kDefaultAlignment at least.
   size_t aligned_bytes =
-      base::bits::AlignUp(bytes_read, PaintOpWriter::Alignment());
+      base::bits::AlignUp(bytes_read, PaintOpWriter::kDefaultAlignment);
   memory_ += aligned_bytes;
   DCHECK_LE(aligned_bytes, remaining_bytes_);
   remaining_bytes_ -= aligned_bytes;
diff --git a/cc/paint/paint_op_reader.h b/cc/paint/paint_op_reader.h
index a4bd656..3bb9a94 100644
--- a/cc/paint/paint_op_reader.h
+++ b/cc/paint/paint_op_reader.h
@@ -31,30 +31,22 @@
  public:
   // The DeserializeOptions passed to the reader must set all fields if it can
   // be used to for deserializing images, paint records or text blobs.
+  // See PaintOpWriter for the alignment requirement for `memory`.
   PaintOpReader(const volatile void* memory,
                 size_t size,
                 const PaintOp::DeserializeOptions& options,
-                bool enable_security_constraints = false)
-      : memory_(static_cast<const volatile char*>(memory) +
-                PaintOpWriter::HeaderBytes()),
-        remaining_bytes_(
-            base::bits::AlignDown(size, PaintOpWriter::Alignment())),
-        options_(options),
-        enable_security_constraints_(enable_security_constraints) {
-    DCHECK_EQ(memory_,
-              base::bits::AlignUp(memory_, PaintOpWriter::Alignment()));
-    if (remaining_bytes_ < PaintOpWriter::HeaderBytes()) {
-      valid_ = false;
-      return;
-    }
-    remaining_bytes_ -= PaintOpWriter::HeaderBytes();
-  }
+                bool enable_security_constraints = false);
 
   static void FixupMatrixPostSerialization(SkMatrix* matrix);
-  static bool ReadAndValidateOpHeader(const volatile void* input,
-                                      size_t input_size,
-                                      uint8_t* type,
-                                      size_t* bytes_to_read);
+
+  // This should be called before before reading PaintOp data. This function
+  // should not be called if this PaintOpReader is used to read specific data
+  // instead of a whole PaintOp.
+  bool ReadAndValidateOpHeader(uint8_t* op_type, size_t* serialized_size);
+
+  size_t BufferAlignment() const {
+    return PaintOpWriter::BufferAlignment(enable_security_constraints_);
+  }
 
   bool valid() const { return valid_; }
   size_t remaining_bytes() const { return remaining_bytes_; }
@@ -131,13 +123,13 @@
   // would exceed the available budfer.
   const volatile void* ExtractReadableMemory(size_t bytes);
 
-  // Aligns the memory to the given alignment.
+  // Aligns the memory to the given `alignment` which must be within the range
+  // of [PaintOpWriter::kDefaultAlignment, BufferAlignment()].
   void AlignMemory(size_t alignment);
 
-  void AssertAlignment(size_t alignment) {
+  void AssertFieldAlignment() {
 #if DCHECK_IS_ON()
-    uintptr_t memory = reinterpret_cast<uintptr_t>(memory_);
-    DCHECK_EQ(base::bits::AlignUp(memory, alignment), memory);
+    PaintOpWriter::AssertAlignment(memory_, PaintOpWriter::kDefaultAlignment);
 #endif
   }
 
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc
index abe1a30..af2002c 100644
--- a/cc/paint/paint_op_writer.cc
+++ b/cc/paint/paint_op_writer.cc
@@ -57,79 +57,91 @@
 }  // namespace
 
 // static
-size_t PaintOpWriter::GetFlattenableSize(const SkFlattenable* flattenable) {
-  // The first bit is always written to indicate the serialized size of the
-  // flattenable, or zero if it doesn't exist.
-  size_t total_size = sizeof(uint64_t) + sizeof(uint64_t) /* alignment */;
-  if (!flattenable)
-    return total_size;
-
-  // There is no method to know the serialized size of a flattenable without
-  // serializing it.
-  sk_sp<SkData> data = flattenable->serialize();
-  total_size += data->isEmpty() ? 0u : data->size();
-  return total_size;
-}
-
-// static
-size_t PaintOpWriter::GetImageSize(const PaintImage& image) {
+size_t PaintOpWriter::SerializedSize(const PaintImage& image) {
   // Image Serialization type.
-  size_t image_size = sizeof(PaintOp::SerializedImageType);
+  base::CheckedNumeric<size_t> image_size =
+      SerializedSize<PaintOp::SerializedImageType>();
   if (image) {
     auto info = SkImageInfo::Make(image.width(), image.height(),
                                   kN32_SkColorType, kPremul_SkAlphaType);
-    image_size += sizeof(info.colorType());
-    image_size += sizeof(info.width());
-    image_size += sizeof(info.height());
-    image_size += sizeof(uint64_t) + sizeof(uint64_t) /* alignment */;
-    image_size += info.computeMinByteSize();
+    image_size += SerializedSize(info.colorType());
+    image_size += SerializedSize(info.width());
+    image_size += SerializedSize(info.height());
+    image_size += SerializedSizeOfBytes(info.computeMinByteSize());
   }
-  return image_size;
+  return image_size.ValueOrDie();
 }
 
 // static
-size_t PaintOpWriter::GetRecordSize(const PaintRecord* record) {
-  // Zero size indicates no record.
+size_t PaintOpWriter::SerializedSize(const SkFlattenable* flattenable) {
+  // There is no method to know the serialized size of a flattenable without
+  // serializing it.
+  return SerializedSizeOfBytes(flattenable ? flattenable->serialize()->size()
+                                           : 0u);
+}
+
+// static
+size_t PaintOpWriter::SerializedSize(const SkColorSpace* color_space) {
+  return SerializedSizeOfBytes(color_space ? color_space->writeToMemory(nullptr)
+                                           : 0u);
+}
+
+// static
+size_t PaintOpWriter::SerializedSize(const PaintRecord& record) {
   // TODO(khushalsagar): Querying the size of a PaintRecord is not supported.
   // This works only for security constrained serialization which ignores
-  // records.
-  return sizeof(uint64_t);
+  // records and writes only a size_t(0).
+  return SerializedSize<size_t>();
+}
+
+// static
+size_t PaintOpWriter::SerializedSize(const PaintFilter* filter) {
+  if (!filter) {
+    return SerializedSize(PaintFilter::Type::kNullFilter);
+  }
+  return filter->SerializedSize();
 }
 
 PaintOpWriter::PaintOpWriter(void* memory,
                              size_t size,
                              const PaintOp::SerializeOptions& options,
                              bool enable_security_constraints)
-    : memory_(static_cast<char*>(memory) + HeaderBytes()),
-      size_(base::bits::AlignDown(size, Alignment())),
-      remaining_bytes_(size_ - HeaderBytes()),
+    : memory_(static_cast<char*>(memory)),
+      size_(base::bits::AlignDown(size, kDefaultAlignment)),
+      remaining_bytes_(size_),
       options_(options),
       enable_security_constraints_(enable_security_constraints) {
-  // Leave space for header of type/skip.
-  DCHECK_GE(size, HeaderBytes());
-  DCHECK_EQ(memory_.get(), base::bits::AlignUp(memory_.get(), Alignment()));
+  AssertAlignment(memory, BufferAlignment());
 }
 
 PaintOpWriter::~PaintOpWriter() = default;
 
-size_t PaintOpWriter::Finish(uint8_t type) {
+void PaintOpWriter::ReserveOpHeader() {
+  // Pretend we have written the header to leave a space for the header.
+  DCHECK_GE(size_, kHeaderBytes);
+  DidWrite(kHeaderBytes);
+}
+
+size_t PaintOpWriter::FinishOp(uint8_t type) {
   if (!valid_) {
     return 0u;
   }
 
   size_t written = size();
-  DCHECK_GE(written, HeaderBytes());
+  DCHECK_GE(written, kHeaderBytes);
 
-  size_t aligned_written =
-      base::bits::AlignUp(written, PaintOpBuffer::kPaintOpAlign);
-  if (aligned_written > kMaxSerializedSize ||
-      aligned_written - written > remaining_bytes_) {
+  size_t aligned_written = base::bits::AlignUp(written, BufferAlignment());
+  size_t padding = aligned_written - written;
+  if (aligned_written > kMaxSerializedSize || padding > remaining_bytes_) {
     valid_ = false;
     return 0u;
   }
 
   // Write type and skip into the header bytes.
   WriteHeader(memory_.get() - written, type, aligned_written);
+
+  memory_ += padding;
+  remaining_bytes_ -= padding;
   return aligned_written;
 }
 
@@ -143,8 +155,9 @@
 void PaintOpWriter::WriteSimple(const T& val) {
   static_assert(std::is_trivially_copyable_v<T>);
 
-  DCHECK_EQ(memory_.get(), base::bits::AlignUp(memory_.get(), Alignment()));
-  static constexpr size_t size = base::bits::AlignUp(sizeof(T), Alignment());
+  AssertFieldAlignment();
+  static constexpr size_t size =
+      base::bits::AlignUp(sizeof(T), kDefaultAlignment);
   EnsureBytes(size);
   if (!valid_)
     return;
@@ -153,19 +166,21 @@
 
   memory_ += size;
   remaining_bytes_ -= size;
+  AssertFieldAlignment();
 }
+
 void PaintOpWriter::WriteFlattenable(const SkFlattenable* val) {
   if (!val) {
     WriteSize(static_cast<size_t>(0u));
     return;
   }
 
-  uint64_t* size_memory = WriteSize(0u);
+  size_t* size_memory = WriteSize(0u);
   if (!valid_)
     return;
 
   size_t bytes_written = val->serialize(
-      memory_, base::bits::AlignDown(remaining_bytes_, Alignment()));
+      memory_, base::bits::AlignDown(remaining_bytes_, kDefaultAlignment));
   if (bytes_written == 0u) {
     valid_ = false;
     return;
@@ -174,10 +189,9 @@
   DidWrite(bytes_written);
 }
 
-uint64_t* PaintOpWriter::WriteSize(size_t size) {
-  AlignMemory(8);
-  uint64_t* memory = reinterpret_cast<uint64_t*>(memory_.get());
-  WriteSimple<uint64_t>(size);
+size_t* PaintOpWriter::WriteSize(size_t size) {
+  size_t* memory = reinterpret_cast<size_t*>(memory_.get());
+  WriteSimple(size);
   return memory;
 }
 
@@ -242,7 +256,7 @@
   } else {
     Write(static_cast<uint32_t>(PaintCacheEntryState::kInlinedDoNotCache));
   }
-  uint64_t* bytes_to_skip = WriteSize(0u);
+  size_t* bytes_to_skip = WriteSize(0u);
   if (!valid_)
     return;
 
@@ -284,7 +298,7 @@
   const PaintImage& paint_image = draw_image.paint_image();
 
   // Empty image.
-  if (!draw_image.paint_image()) {
+  if (!paint_image) {
     Write(static_cast<uint8_t>(PaintOp::SerializedImageType::kNoImage));
     return;
   }
@@ -296,13 +310,19 @@
   // Security constrained serialization inlines the image bitmap.
   if (enable_security_constraints_) {
     SkBitmap bm;
-    if (!draw_image.paint_image().GetSwSkImage()->asLegacyBitmap(&bm)) {
+    if (!paint_image.GetSwSkImage()->asLegacyBitmap(&bm)) {
       Write(static_cast<uint8_t>(PaintOp::SerializedImageType::kNoImage));
       return;
     }
 
     Write(static_cast<uint8_t>(PaintOp::SerializedImageType::kImageData));
     const auto& pixmap = bm.pixmap();
+    // Pixmaps requiring alignments larger than kDefaultAlignment [1] are not
+    // supported because the buffer is only guaranteed to align to
+    // kDefaultAlignment when enable_security_constraits_ is true.
+    // [1] See https://crbug.com/1300188 and https://crrev.com/c/3485859.
+    DCHECK_LE(static_cast<size_t>(SkColorTypeBytesPerPixel(pixmap.colorType())),
+              kDefaultAlignment);
     Write(pixmap.colorType());
     Write(pixmap.width());
     Write(pixmap.height());
@@ -329,7 +349,7 @@
   uint32_t id = skottie->id();
   Write(id);
 
-  uint64_t* bytes_to_skip = WriteSize(0u);
+  size_t* bytes_to_skip = WriteSize(0u);
   if (!valid_)
     return;
 
@@ -337,7 +357,7 @@
       options_->transfer_cache->LockEntry(TransferCacheEntryType::kSkottie, id);
 
   // Add a cache entry for the skottie animation.
-  uint64_t bytes_written = 0u;
+  size_t bytes_written = 0u;
   if (!locked) {
     bytes_written = options_->transfer_cache->CreateEntry(
         ClientSkottieTransferCacheEntry(skottie), memory_);
@@ -432,8 +452,8 @@
   if (!valid_)
     return;
 
-  AssertAlignment(Alignment());
-  uint64_t* size_memory = WriteSize(0u);
+  AssertFieldAlignment();
+  size_t* size_memory = WriteSize(0u);
   if (!valid_)
     return;
 
@@ -442,7 +462,7 @@
     // TODO(penghuang): should we use a unique id to avoid sending the same
     // slug?
     bytes_written = slug->serialize(
-        memory_, base::bits::AlignDown(remaining_bytes_, Alignment()));
+        memory_, base::bits::AlignDown(remaining_bytes_, kDefaultAlignment));
     if (bytes_written == 0u) {
       valid_ = false;
       return;
@@ -599,30 +619,28 @@
 }
 
 void PaintOpWriter::WriteData(size_t bytes, const void* input) {
-  DCHECK_EQ(memory_.get(),
-            base::bits::AlignUp(memory_.get(), PaintOpWriter::Alignment()));
-  if (bytes == 0)
+  AssertFieldAlignment();
+
+  if (bytes == 0) {
     return;
+  }
 
   EnsureBytes(bytes);
 
-  if (!valid_)
+  if (!valid_) {
     return;
+  }
 
   memcpy(memory_, input, bytes);
   DidWrite(bytes);
 }
 
 void PaintOpWriter::AlignMemory(size_t alignment) {
-  // Due to the math below, alignment must be a power of two.
-  DCHECK_GT(alignment, 0u);
-  DCHECK_EQ(alignment & (alignment - 1), 0u);
+  DCHECK_GE(alignment, kDefaultAlignment);
+  DCHECK_LE(alignment, BufferAlignment());
+  // base::bits::AlignUp() below will check if alignment is a power of two.
 
   uintptr_t memory = reinterpret_cast<uintptr_t>(memory_.get());
-  // The following is equivalent to:
-  //   padding = (alignment - memory % alignment) % alignment;
-  // because alignment is a power of two. This doesn't use modulo operator
-  // however, since it can be slow.
   size_t padding = base::bits::AlignUp(memory, alignment) - memory;
   EnsureBytes(padding);
   if (!valid_)
@@ -647,7 +665,7 @@
   if (!valid_)
     return;
 
-  AssertAlignment(Alignment());
+  AssertFieldAlignment();
   switch (filter->type()) {
     case PaintFilter::Type::kNullFilter:
       NOTREACHED();
@@ -950,17 +968,10 @@
 void PaintOpWriter::Write(const PaintRecord& record,
                           const gfx::Rect& playback_rect,
                           const gfx::SizeF& post_scale) {
-  AlignMemory(PaintOpBuffer::kPaintOpAlign);
-
   // We need to record how many bytes we will serialize, but we don't know this
-  // information until we do the serialization. So, skip the amount needed
-  // before writing.
-  size_t size_offset = sizeof(uint64_t);
-  EnsureBytes(size_offset);
-  if (!valid_)
-    return;
-
-  uint64_t* size_memory = WriteSize(0u);
+  // information until we do the serialization. So, write 0 as the size first,
+  // and amend it after writing.
+  size_t* size_memory = WriteSize(0u);
   if (!valid_)
     return;
 
@@ -969,6 +980,8 @@
     return;
   }
 
+  AlignMemory(BufferAlignment());
+
   // Nested records are used for picture shaders and filters. These are always
   // converted to a fixed scale mode (hence |post_scale|), which means they are
   // first rendered offscreen via SkImage::MakeFromPicture. This inherently does
@@ -1009,8 +1022,8 @@
 }
 
 inline void PaintOpWriter::DidWrite(size_t bytes_written) {
-  // All data are aligned with PaintOpWriter::Alignment() at least.
-  size_t aligned_bytes = base::bits::AlignUp(bytes_written, Alignment());
+  // All data are aligned with kDefaultAlignment at least.
+  size_t aligned_bytes = base::bits::AlignUp(bytes_written, kDefaultAlignment);
   memory_ += aligned_bytes;
   DCHECK_LE(aligned_bytes, remaining_bytes_);
   remaining_bytes_ -= aligned_bytes;
diff --git a/cc/paint/paint_op_writer.h b/cc/paint/paint_op_writer.h
index 920df172..d1de951 100644
--- a/cc/paint/paint_op_writer.h
+++ b/cc/paint/paint_op_writer.h
@@ -5,9 +5,13 @@
 #ifndef CC_PAINT_PAINT_OP_WRITER_H_
 #define CC_PAINT_PAINT_OP_WRITER_H_
 
+#include <memory>
+
 #include "base/bits.h"
+#include "base/memory/aligned_memory.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ref.h"
+#include "base/numerics/checked_math.h"
 #include "cc/paint/paint_canvas.h"
 #include "cc/paint/paint_export.h"
 #include "cc/paint/paint_filter.h"
@@ -33,36 +37,127 @@
  public:
   // The SerializeOptions passed to the writer must set the required fields
   // if it can be used for serializing images, paint records or text blobs.
+  // If `enable_security_constraints` is false, `memory` must be aligned to
+  // kMaxAlignment, and AllocateAlignedBuffer() is the preferred way to
+  // allocate `memory`. Otherwise `memory` can be allocated in any way that can
+  // ensure kDefaultAlignment. See BufferAlignment() for more details.
+  // If `size` is not enough to contain serialized data, the buffer won't
+  // overflow, but Write() will be silent no-ops.
   PaintOpWriter(void* memory,
                 size_t size,
                 const PaintOp::SerializeOptions& options,
                 bool enable_security_constraints = false);
   ~PaintOpWriter();
 
+  static std::unique_ptr<char, base::AlignedFreeDeleter> AllocateAlignedBuffer(
+      size_t size) {
+    return std::unique_ptr<char, base::AlignedFreeDeleter>(
+        static_cast<char*>(base::AlignedAlloc(size, kMaxAlignment)));
+  }
+
   const PaintOp::SerializeOptions& options() const { return *options_; }
 
-  // Type and serialized_size fit in HeaderBytes, using 1 byte and 3 bytes,
+  // Type and serialized_size fit in kHeaderBytes, using 1 byte and 3 bytes,
   // respectively. Note that serialized_size in the header is different from
   // PaintOp::aligned_size because serialized data may have different byte
   // format and serialization of reference data fields may be make
   // serialized_size much bigger than PaintOp::aligned_size.
-  static size_t constexpr HeaderBytes() { return sizeof(uint32_t); }
+  static constexpr size_t kHeaderBytes = sizeof(uint32_t);
   static constexpr size_t kMaxSerializedSize = (1u << 24) - 1;
 
-  // Round up each field to 4 bytes. This is not technically perfect alignment,
-  // but it is about 30% faster to post-align each write to 4 bytes than it is
-  // to pre-align memory to the correct alignment.
-  // The whole serialized PaintOp is aligned to PaintOpBuffer::kPaintOpAlign.
-  // TODO(wangxianzhu): Revisit the kPaintOpAlign requirement for serialization.
-  static size_t constexpr Alignment() { return alignof(uint32_t); }
+  // The start/end of the buffer for a serialized PaintOp must be aligned to
+  // BufferAlignment() which is the maximum alignment of all serialized fields,
+  // to ensure the alignment padding of any field to be constant.
+  //
+  // When enable_security_constraints is true, we won't serialize PaintRecords
+  // or images that require alignments greater than kDefaultAlignment. We can't
+  // require larger alignment because the buffer may be a part of another
+  // buffer (e.g. mojom data) for which the caller can't control the alignment.
+  //
+  // When enable_security_constraints is false, the alignment is 16 which is
+  // the maximum alignment requirement of particular types of pixmaps (see
+  // image_transfer_data_cache.cc).
+  static constexpr size_t BufferAlignment(bool enable_security_constraints) {
+    return enable_security_constraints ? kDefaultAlignment : kMaxAlignment;
+  }
+  static constexpr size_t kMaxAlignment = 16;
+  size_t BufferAlignment() const {
+    return BufferAlignment(enable_security_constraints_);
+  }
 
-  static size_t GetFlattenableSize(const SkFlattenable* flattenable);
-  static size_t GetImageSize(const PaintImage& image);
-  static size_t GetRecordSize(const PaintRecord* record);
+  // Round up each field to 4 bytes by default. This is not technically perfect
+  // alignment, but it is about 30% faster to post-align each write to 4 bytes
+  // than it is to pre-align memory to the correct alignment.
+  // A field can also use a larger alignment by calling AlignMemory().
+  static constexpr size_t kDefaultAlignment = alignof(uint32_t);
 
-  // Called after serializing data of a PaintOp. Returns the serialized size
-  // of the PaintOp aligned to PaintOpBuffer::kPaintOpAlign, or 0 on any errors.
-  size_t Finish(uint8_t type);
+  // SerializedSize() returns the maximum serialized size of the given type or
+  // the given parameter. For a buffer to contain serialization of multiple
+  // data, the size can be the accumulated results of SerializedSize() of each
+  // data.
+  template <typename T>
+  static constexpr size_t SerializedSize() {
+    static_assert(std::is_arithmetic_v<T> || std::is_enum_v<T>);
+    return base::bits::AlignUp(sizeof(T), kDefaultAlignment);
+  }
+  template <typename T>
+  static constexpr size_t SerializedSize(const T& data) {
+    static_assert(!std::is_pointer_v<T>);
+    return base::bits::AlignUp(sizeof(T), kDefaultAlignment);
+  }
+  static size_t SerializedSize(const PaintImage& image);
+  static size_t SerializedSize(const PaintRecord& record);
+
+  // Serialization of raw/smart pointers is not supported by default.
+  template <typename T>
+  static inline size_t SerializedSize(const T* p);
+  template <typename T>
+  static inline size_t SerializedSize(const std::unique_ptr<T>& p);
+  template <typename T>
+  static inline size_t SerializedSize(const scoped_refptr<T>& p);
+  template <typename T>
+  static inline size_t SerializedSize(const raw_ptr<T>& p);
+
+  template <typename T>
+  static inline size_t SerializedSize(T* p) {
+    return SerializedSize(static_cast<const T*>(p));
+  }
+  static size_t SerializedSize(const SkFlattenable* flattenable);
+  static size_t SerializedSize(const SkColorSpace* color_space);
+  static size_t SerializedSize(const PaintFilter* filter);
+
+  template <typename T>
+  static size_t SerializedSize(const absl::optional<T>& o) {
+    if (o) {
+      return (base::CheckedNumeric<size_t>(SerializedSize<bool>()) +
+              SerializedSize<T>(*o))
+          .ValueOrDie();
+    }
+    return SerializedSize<bool>();
+  }
+
+  // Size of serialized (size_t, bytes).
+  static size_t SerializedSizeOfBytes(size_t num_bytes) {
+    return (base::CheckedNumeric<size_t>(SerializedSize<size_t>()) +
+            base::bits::AlignUp(num_bytes, kDefaultAlignment))
+        .ValueOrDie();
+  }
+  // Size of serialized (size_t, elements>
+  template <typename T>
+  static size_t SerializedSizeOfElements(const T* elements, size_t count) {
+    return (SerializedSize<size_t>() +
+            base::CheckedNumeric<size_t>(count) * SerializedSize(*elements))
+        .ValueOrDie();
+  }
+
+  // These two functions should be called before and after (respectively)
+  // serializing the data of a PaintOp. These functions should not be called
+  // if this PaintOpWriter is used to write specific data instead of a whole
+  // PaintOp.
+  void ReserveOpHeader();
+  // Returns the serialized size (aligned to BufferAlignment()) of the PaintOp,
+  // or 0 on any errors.
+  size_t FinishOp(uint8_t type);
 
   static void WriteHeaderForTesting(void* memory,
                                     uint8_t type,
@@ -71,9 +166,11 @@
   // Write a sequence of arbitrary bytes.
   void WriteData(size_t bytes, const void* input);
 
+  // Returns the size of successfully written data, including paddings for
+  // alignment.
   size_t size() const { return valid_ ? size_ - remaining_bytes_ : 0u; }
 
-  uint64_t* WriteSize(size_t size);
+  size_t* WriteSize(size_t size);
 
   void Write(SkScalar data);
   void Write(SkMatrix data);
@@ -120,13 +217,19 @@
 
   void Write(bool data) { Write(static_cast<uint8_t>(data)); }
 
-  // Aligns the memory to the given alignment.
+  // Aligns the memory to the given `alignment` which must be within the range
+  // of [kDefaultAlignment, BufferAlignment()].
   void AlignMemory(size_t alignment);
 
-  void AssertAlignment(size_t alignment) {
+  static void AssertAlignment(const volatile void* memory, size_t alignment) {
 #if DCHECK_IS_ON()
-    uintptr_t memory = reinterpret_cast<uintptr_t>(memory_.get());
-    DCHECK_EQ(base::bits::AlignUp(memory, alignment), memory);
+    uintptr_t uintptr = reinterpret_cast<uintptr_t>(memory);
+    DCHECK_EQ(uintptr, base::bits::AlignUp(uintptr, alignment));
+#endif
+  }
+  void AssertFieldAlignment() {
+#if DCHECK_IS_ON()
+    AssertAlignment(memory_.get(), kDefaultAlignment);
 #endif
   }
 
diff --git a/cc/paint/paint_shader.cc b/cc/paint/paint_shader.cc
index da505ef..a23ba7a 100644
--- a/cc/paint/paint_shader.cc
+++ b/cc/paint/paint_shader.cc
@@ -4,10 +4,12 @@
 
 #include "cc/paint/paint_shader.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/atomic_sequence_num.h"
 #include "base/notreached.h"
+#include "base/numerics/checked_math.h"
 #include "base/types/optional_util.h"
 #include "cc/paint/image_provider.h"
 #include "cc/paint/paint_image_builder.h"
@@ -219,26 +221,35 @@
 
 // static
 size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
-  size_t bool_size = sizeof(bool);
-  if (!shader)
-    return bool_size;
+  if (!shader) {
+    return PaintOpWriter::SerializedSize<bool>();
+  }
 
-  return bool_size + sizeof(shader->shader_type_) + sizeof(shader->flags_) +
-         sizeof(shader->end_radius_) + sizeof(shader->start_radius_) +
-         sizeof(shader->tx_) + sizeof(shader->ty_) +
-         sizeof(shader->fallback_color_) + sizeof(shader->scaling_behavior_) +
-         bool_size + sizeof(*shader->local_matrix_) + sizeof(shader->center_) +
-         sizeof(shader->tile_) + sizeof(shader->start_point_) +
-         sizeof(shader->end_point_) + sizeof(shader->start_degrees_) +
-         sizeof(shader->end_degrees_) +
-         PaintOpWriter::GetImageSize(shader->image_) +
-         PaintOpWriter::GetImageSize(shader->image_) + bool_size +
-         sizeof(shader->id_) +
-         PaintOpWriter::GetRecordSize(shader->paint_record()) +
-         sizeof(shader->colors_.size()) +
-         shader->colors_.size() * sizeof(SkColor4f) +
-         sizeof(shader->positions_.size()) +
-         shader->positions_.size() * sizeof(SkScalar);
+  return (base::CheckedNumeric<size_t>(PaintOpWriter::SerializedSize<bool>()) +
+          PaintOpWriter::SerializedSize(shader->shader_type_) +
+          PaintOpWriter::SerializedSize(shader->flags_) +
+          PaintOpWriter::SerializedSize(shader->end_radius_) +
+          PaintOpWriter::SerializedSize(shader->start_radius_) +
+          PaintOpWriter::SerializedSize(shader->tx_) +
+          PaintOpWriter::SerializedSize(shader->ty_) +
+          PaintOpWriter::SerializedSize(shader->fallback_color_) +
+          PaintOpWriter::SerializedSize(shader->scaling_behavior_) +
+          PaintOpWriter::SerializedSize(shader->local_matrix_) +
+          PaintOpWriter::SerializedSize(shader->center_) +
+          PaintOpWriter::SerializedSize(shader->tile_) +
+          PaintOpWriter::SerializedSize(shader->start_point_) +
+          PaintOpWriter::SerializedSize(shader->end_point_) +
+          PaintOpWriter::SerializedSize(shader->start_degrees_) +
+          PaintOpWriter::SerializedSize(shader->end_degrees_) +
+          PaintOpWriter::SerializedSize(shader->gradient_interpolation_) +
+          PaintOpWriter::SerializedSize(shader->image_) +
+          PaintOpWriter::SerializedSize(shader->id_) +
+          PaintOpWriter::SerializedSize(shader->record_) +
+          PaintOpWriter::SerializedSizeOfElements(shader->colors_.data(),
+                                                  shader->colors_.size()) +
+          PaintOpWriter::SerializedSizeOfElements(shader->positions_.data(),
+                                                  shader->positions_.size()))
+      .ValueOrDie();
 }
 
 PaintShader::PaintShader(Type type) : shader_type_(type) {}
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/MostVisitedSuggestionsUiDelegate.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/MostVisitedSuggestionsUiDelegate.java
new file mode 100644
index 0000000..7a3f290
--- /dev/null
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/MostVisitedSuggestionsUiDelegate.java
@@ -0,0 +1,31 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.features.start_surface;
+
+import android.view.View;
+
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
+import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegateImpl;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+
+/** Suggestions UI Delegate for constructing the TileGroup. */
+public class MostVisitedSuggestionsUiDelegate extends SuggestionsUiDelegateImpl {
+    private final View mView;
+
+    public MostVisitedSuggestionsUiDelegate(View view,
+            SuggestionsNavigationDelegate navigationDelegate, Profile profile,
+            SnackbarManager snackbarManager) {
+        super(navigationDelegate, profile, /*host=*/null, snackbarManager);
+        mView = view;
+    }
+
+    @Override
+    public boolean isVisible() {
+        return mView.getVisibility() == View.VISIBLE
+                && mView.findViewById(org.chromium.chrome.R.id.mv_tiles_layout).getVisibility()
+                == View.VISIBLE;
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinder.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinder.java
index 0811b3c..9c70343 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinder.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinder.java
@@ -16,8 +16,8 @@
 
 /** The binder controls the display of the secondary {@link TasksView} in its parent. */
 class SecondaryTasksSurfaceViewBinder {
-    public static void bind(PropertyModel model, TasksSurfaceViewBinder.ViewHolder viewHolder,
-            PropertyKey propertyKey) {
+    public static void bind(PropertyModel model,
+            StartSurfaceWithParentViewBinder.ViewHolder viewHolder, PropertyKey propertyKey) {
         if (IS_SECONDARY_SURFACE_VISIBLE == propertyKey) {
             updateVisibility(viewHolder, model);
         } else if (TOP_MARGIN == propertyKey) {
@@ -28,7 +28,7 @@
     }
 
     private static void updateVisibility(
-            TasksSurfaceViewBinder.ViewHolder viewHolder, PropertyModel model) {
+            StartSurfaceWithParentViewBinder.ViewHolder viewHolder, PropertyModel model) {
         boolean isShowing = model.get(IS_SECONDARY_SURFACE_VISIBLE);
         if (isShowing && viewHolder.tasksSurfaceView.getParent() == null) {
             viewHolder.parentView.addView(viewHolder.tasksSurfaceView);
@@ -42,13 +42,14 @@
     }
 
     private static void bringSurfaceToFront(
-            TasksSurfaceViewBinder.ViewHolder viewHolder, PropertyModel model) {
+            StartSurfaceWithParentViewBinder.ViewHolder viewHolder, PropertyModel model) {
         if (model.get(IS_SECONDARY_SURFACE_VISIBLE)) {
             viewHolder.tasksSurfaceView.bringToFront();
         }
     }
 
-    private static void setTopMargin(TasksSurfaceViewBinder.ViewHolder viewHolder, int topMargin) {
+    private static void setTopMargin(
+            StartSurfaceWithParentViewBinder.ViewHolder viewHolder, int topMargin) {
         MarginLayoutParams layoutParams =
                 (MarginLayoutParams) viewHolder.tasksSurfaceView.getLayoutParams();
         if (layoutParams == null) return;
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurface.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurface.java
index aaa318f..30831eb 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurface.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurface.java
@@ -17,7 +17,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherCustomViewManager;
-import org.chromium.chrome.features.tasks.TasksSurface;
+import org.chromium.chrome.features.tasks.TasksView;
 
 /** Interface to communicate with the start surface. */
 public interface StartSurface {
@@ -162,7 +162,8 @@
      * Show the overview.
      * @param animate Whether we should animate while showing.
      */
-    // TODO(crbug.com/1315676): Decouple Start surface layout and Grid tab switcher layout.
+    // TODO(crbug.com/1315676): Rename this function once the Start surface layout and Grid tab
+    // switcher layout are decoupled.
     void showOverview(boolean animate);
 
     /**
@@ -255,6 +256,7 @@
      * carousel/single tab switcher when start surface is enabled; when start surface is disabled,
      * null should be returned.
      */
+    // TODO(crbug.com/1315676): Remove this API after the refactoring is done.
     TabSwitcher.TabListDelegate getCarouselOrSingleTabListDelegate();
 
     /**
@@ -272,11 +274,11 @@
             boolean isOverviewShownOnStartup, final long activityCreationTimeMs);
 
     /**
-     * Returns the primary {@link TasksSurface} (omnibox, most visited, feed, etc.). Can be null if
+     * Returns the primary {@link TasksView} (omnibox, most visited, feed, etc.). Can be null if
      * grid tab switcher is enabled but Start surface is disabled.
      */
     @Nullable
-    TasksSurface getPrimaryTasksSurface();
+    TasksView getPrimarySurfaceView();
 
     /**
      * TODO(crbug.com/1315676): Remove this API after the bug is resolved.
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index ba824cc..4dcebf1 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.os.SystemClock;
 import android.text.TextUtils;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -24,6 +25,7 @@
 import org.chromium.base.MathUtils;
 import org.chromium.base.ObserverList;
 import org.chromium.base.jank_tracker.JankTracker;
+import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
@@ -45,9 +47,16 @@
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
 import org.chromium.chrome.browser.omnibox.OmniboxStub;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.OriginalProfileSupplier;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileManager;
+import org.chromium.chrome.browser.query_tiles.QueryTileSection;
+import org.chromium.chrome.browser.query_tiles.QueryTileUtils;
 import org.chromium.chrome.browser.share.ShareDelegate;
 import org.chromium.chrome.browser.share.crow.CrowButtonDelegate;
+import org.chromium.chrome.browser.suggestions.tile.MostVisitedTilesCoordinator;
 import org.chromium.chrome.browser.suggestions.tile.TileGroupDelegateImpl;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -57,15 +66,22 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherCustomViewManager;
+import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.toolbar.top.Toolbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.util.BrowserUiUtils;
+import org.chromium.chrome.features.tasks.MostVisitedTileNavigationDelegate;
+import org.chromium.chrome.features.tasks.SingleTabSwitcherCoordinator;
 import org.chromium.chrome.features.tasks.TasksSurface;
 import org.chromium.chrome.features.tasks.TasksSurfaceCoordinator;
 import org.chromium.chrome.features.tasks.TasksSurfaceProperties;
+import org.chromium.chrome.features.tasks.TasksView;
+import org.chromium.chrome.features.tasks.TasksViewBinder;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.components.user_prefs.UserPrefs;
+import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.ViewUtils;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -76,6 +92,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Root coordinator that is responsible for showing start surfaces, like a grid of Tabs, explore
@@ -113,6 +130,7 @@
     @VisibleForTesting
     static final String START_SHOWN_AT_STARTUP_UMA = "Startup.Android.StartSurfaceShownAtStartup";
     private static final String TAG = "StartSurface";
+    private static final int MAX_TILE_ROWS_FOR_GRID_MVT = 2;
 
     // Non-null in SurfaceMode.SINGLE_PANE mode.
     @Nullable
@@ -122,6 +140,9 @@
     @Nullable
     private PropertyModelChangeProcessor mTasksSurfacePropertyModelChangeProcessor;
 
+    private PropertyModelChangeProcessor mStartSurfaceWithParentViewPropertyModelChangeProcessor;
+    private PropertyModelChangeProcessor mStartSurfacePropertyModelChangeProcessor;
+
     // TODO(crbug.com/1315676): Remove this once the start surface refactoring is done, since the
     // secondary tasks surface will go away.
     // Non-null in SurfaceMode.SINGLE_PANE mode to show more tabs.
@@ -134,7 +155,7 @@
 
     // Non-null in SurfaceMode.NO_START_SURFACE to show the tabs.
     @Nullable
-    private TabSwitcher mTabSwitcher;
+    private TabSwitcher mGridTabSwitcher;
 
     // Non-null in SurfaceMode.SINGLE_PANE modes.
     @Nullable
@@ -176,6 +197,21 @@
     @Nullable
     private FeedSwipeRefreshLayout mSwipeRefreshLayout;
 
+    // The single or carousel Tab switcher module on the Start surface.
+    // None-null when the Start surface refactoring is enabled.
+    @Nullable
+    private TabSwitcher mTabSwitcherModule;
+    // The view of Start surface layout.
+    // None-null when the Start surface refactoring is enabled.
+    @Nullable
+    private TasksView mView;
+    private MostVisitedTilesCoordinator mMostVisitedCoordinator;
+    private MostVisitedSuggestionsUiDelegate mSuggestionsUiDelegate;
+    private TileGroupDelegateImpl mTileGroupDelegate;
+    private OneshotSupplier<Profile> mQueryTileProfileSupplier;
+    private QueryTileSection mQueryTileSection;
+    private boolean mIsMVTilesInitialized;
+
     private class ScrollableContainerDelegateImpl implements ScrollableContainerDelegate {
         @Override
         public void addScrollListener(ScrollListener listener) {
@@ -290,42 +326,51 @@
                 || !ChromeFeatureList.sQueryTilesOnStart.isEnabled();
         mIsStartSurfaceRefactorEnabled =
                 ReturnToChromeUtil.isStartSurfaceRefactorEnabled(mActivity);
+        TabSwitcher.Controller controller;
+        Runnable initializeMVTilesRunnable = null;
+        View logoContainerView = null;
+        ViewGroup feedPlaceholderParentView = null;
         if (!mIsStartSurfaceEnabled && !mIsStartSurfaceRefactorEnabled) {
             // Create Tab switcher directly to save one layer in the view hierarchy.
-            mTabSwitcher = TabManagementModuleProvider.getDelegate().createGridTabSwitcher(activity,
-                    activityLifecycleDispatcher, tabModelSelector, tabContentManager,
+            mGridTabSwitcher = TabManagementModuleProvider.getDelegate().createGridTabSwitcher(
+                    activity, activityLifecycleDispatcher, tabModelSelector, tabContentManager,
                     browserControlsManager, tabCreatorManager, menuOrKeyboardActionController,
                     containerView, shareDelegateSupplier, multiWindowModeStateDispatcher,
                     scrimCoordinator, /* rootView= */ containerView, dynamicResourceLoaderSupplier,
                     snackbarManager, modalDialogManager, incognitoReauthControllerSupplier,
                     backPressManager);
             mTabSwitcherCustomViewManagerSupplier.set(
-                    mTabSwitcher.getTabSwitcherCustomViewManager());
-        } else {
+                    mGridTabSwitcher.getTabSwitcherCustomViewManager());
+            controller = mGridTabSwitcher.getController();
+        } else if (!mIsStartSurfaceRefactorEnabled) {
+            assert mIsStartSurfaceEnabled;
+
             // createSwipeRefreshLayout has to be called before creating any surface.
             createSwipeRefreshLayout();
             createAndSetStartSurface(excludeQueryTiles);
-        }
+            controller = mTasksSurface.getController();
+            initializeMVTilesRunnable = mTasksSurface::initializeMVTiles;
+            logoContainerView = mTasksSurface.getView().findViewById(R.id.logo_container);
+            feedPlaceholderParentView = mTasksSurface.getBodyViewContainer();
+        } else {
+            assert mIsStartSurfaceEnabled && mIsStartSurfaceRefactorEnabled;
 
-        TabSwitcher.Controller controller =
-                mTabSwitcher != null ? mTabSwitcher.getController() : mTasksSurface.getController();
-        Runnable initializeMVTilesRunnable =
-                mTasksSurface == null ? null : mTasksSurface::initializeMVTiles;
-        View logoContainerView = mTasksSurface == null
-                ? null
-                : mTasksSurface.getView().findViewById(R.id.logo_container);
-        ViewGroup feedPlaceholderParentView =
-                mTasksSurface == null ? null : mTasksSurface.getBodyViewContainer();
+            // createSwipeRefreshLayout has to be called before creating any surface.
+            createSwipeRefreshLayout();
+            createStartSurfaceWithoutTasksSurface(excludeQueryTiles);
+            controller = mTabSwitcherModule.getController();
+            initializeMVTilesRunnable = this::initializeMVTiles;
+            logoContainerView = mView.findViewById(R.id.logo_container);
+            feedPlaceholderParentView = mView.findViewById(R.id.tasks_surface_body);
+        }
         mStartSurfaceMediator = new StartSurfaceMediator(controller, containerView,
-                mTabModelSelector, mPropertyModel,
-                mIsStartSurfaceEnabled && !mIsStartSurfaceRefactorEnabled
-                        ? this::initializeSecondaryTasksSurface
-                        : null,
+                mTabSwitcherModule, mTabModelSelector, mPropertyModel,
+                mTasksSurface != null ? this::initializeSecondaryTasksSurface : null,
                 mIsStartSurfaceEnabled, mActivity, mBrowserControlsManager,
                 this::isActivityFinishingOrDestroyed, excludeQueryTiles,
                 startSurfaceOneshotSupplier, hadWarmStart, jankTracker, initializeMVTilesRunnable,
                 mParentTabSupplier, logoContainerView,
-                mTabSwitcher == null ? backPressManager : null, feedPlaceholderParentView,
+                mGridTabSwitcher == null ? backPressManager : null, feedPlaceholderParentView,
                 mActivityLifecycleDispatcher, tabSwitcherClickHandler);
 
         startSurfaceOneshotSupplier.set(this);
@@ -370,8 +415,20 @@
                 assert !mIsStartSurfaceRefactorEnabled;
                 mSecondaryTasksSurface.onHide();
             }
+            if (mSuggestionsUiDelegate != null) {
+                mSuggestionsUiDelegate.onDestroy();
+                mSuggestionsUiDelegate = null;
+            }
+            if (mTileGroupDelegate != null) {
+                mTileGroupDelegate.destroy();
+                mTileGroupDelegate = null;
+            }
+            if (mMostVisitedCoordinator != null) {
+                mMostVisitedCoordinator.destroyMvtiles();
+                mIsMVTilesInitialized = false;
+            }
         }
-        mStartSurfaceMediator.maybeDestroyFeedPlaceholder();
+        mStartSurfaceMediator.onHide();
     }
 
     @Override
@@ -392,6 +449,8 @@
         // TODO (crbug.com/1113852): Add a header offset change listener for incognito homepage.
         if (mTasksSurface != null) {
             mTasksSurface.addHeaderOffsetChangeListener(onOffsetChangedListener);
+        } else if (mView != null) {
+            mView.addHeaderOffsetChangeListener(onOffsetChangedListener);
         }
     }
 
@@ -400,6 +459,8 @@
             AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
         if (mTasksSurface != null) {
             mTasksSurface.removeHeaderOffsetChangeListener(onOffsetChangedListener);
+        } else if (mView != null) {
+            mView.removeHeaderOffsetChangeListener(onOffsetChangedListener);
         }
     }
 
@@ -418,8 +479,10 @@
         mStartSurfaceMediator.setOnTabSelectingListener(listener);
         if (mTasksSurface != null) {
             mTasksSurface.setOnTabSelectingListener(mStartSurfaceMediator);
+        } else if (mGridTabSwitcher != null) {
+            mGridTabSwitcher.setOnTabSelectingListener(mStartSurfaceMediator);
         } else {
-            mTabSwitcher.setOnTabSelectingListener(mStartSurfaceMediator);
+            mTabSwitcherModule.setOnTabSelectingListener(mStartSurfaceMediator);
         }
 
         if (mIsStartSurfaceRefactorEnabled) return;
@@ -441,19 +504,21 @@
 
         mIsInitializedWithNative = true;
         if (mIsStartSurfaceEnabled) {
+            ViewGroup parentView = mView != null ? mView.getBodyViewContainer()
+                                                 : mTasksSurface.getBodyViewContainer();
             mExploreSurfaceCoordinatorFactory = new ExploreSurfaceCoordinatorFactory(mActivity,
-                    mTasksSurface.getBodyViewContainer(), mPropertyModel, mBottomSheetController,
-                    mParentTabSupplier, new ScrollableContainerDelegateImpl(), mSnackbarManager,
-                    mShareDelegateSupplier, mWindowAndroid, mTabModelSelector, mToolbarSupplier,
-                    mConstructedTimeNs, mSwipeRefreshLayout, mCrowButtonDelegate);
+                    parentView, mPropertyModel, mBottomSheetController, mParentTabSupplier,
+                    new ScrollableContainerDelegateImpl(), mSnackbarManager, mShareDelegateSupplier,
+                    mWindowAndroid, mTabModelSelector, mToolbarSupplier, mConstructedTimeNs,
+                    mSwipeRefreshLayout, mCrowButtonDelegate);
         }
         mStartSurfaceMediator.initWithNative(
                 mIsStartSurfaceEnabled ? mOmniboxStubSupplier.get() : null,
                 mExploreSurfaceCoordinatorFactory,
                 UserPrefs.get(Profile.getLastUsedRegularProfile()), mSnackbarManager);
 
-        if (mTabSwitcher != null) {
-            mTabSwitcher.initWithNative();
+        if (mGridTabSwitcher != null) {
+            mGridTabSwitcher.initWithNative();
         }
         if (mTasksSurface != null) {
             mTasksSurface.onFinishNativeInitialization(mActivity, mOmniboxStubSupplier.get(),
@@ -538,8 +603,8 @@
 
     @Override
     public boolean onBackPressed() {
-        if (mTabSwitcher != null) {
-            return mTabSwitcher.onBackPressed();
+        if (mGridTabSwitcher != null) {
+            return mGridTabSwitcher.onBackPressed();
         }
         return mStartSurfaceMediator.onBackPressed();
     }
@@ -587,15 +652,20 @@
             }
             return mSecondaryTasksSurface.getTabListDelegate();
         } else {
-            return mTabSwitcher.getTabListDelegate();
+            return mGridTabSwitcher.getTabListDelegate();
         }
     }
 
     @Override
     public TabSwitcher.TabListDelegate getCarouselOrSingleTabListDelegate() {
         if (mIsStartSurfaceEnabled) {
-            assert mTasksSurface != null;
-            return mTasksSurface.getTabListDelegate();
+            if (mIsStartSurfaceRefactorEnabled) {
+                assert mTabSwitcherModule != null;
+                return mTabSwitcherModule.getTabListDelegate();
+            } else {
+                assert mTasksSurface != null;
+                return mTasksSurface.getTabListDelegate();
+            }
         } else {
             return null;
         }
@@ -605,8 +675,10 @@
     public Supplier<Boolean> getTabGridDialogVisibilitySupplier() {
         // If TabSwitcher has been created directly, use the TabGridDialogVisibilitySupplier from
         // TabSwitcher.
-        if (mTabSwitcher != null) {
-            return mTabSwitcher.getTabGridDialogVisibilitySupplier();
+        if (mGridTabSwitcher != null) {
+            return mGridTabSwitcher.getTabGridDialogVisibilitySupplier();
+        } else if (mTabSwitcherModule != null) {
+            return () -> mTabSwitcherModule.getTabGridDialogVisibilitySupplier() != null;
         }
         return () -> {
             // Return true if either mTasksSurface or mSecondaryTasksSurface has a visible dialog.
@@ -650,8 +722,11 @@
 
     @Override
     @Nullable
-    public TasksSurface getPrimaryTasksSurface() {
-        return mTasksSurface;
+    public TasksView getPrimarySurfaceView() {
+        if (mTasksSurface != null) {
+            return (TasksView) mTasksSurface.getView();
+        }
+        return mView;
     }
 
     @Override
@@ -730,17 +805,29 @@
 
     @VisibleForTesting
     public boolean isMVTilesCleanedUpForTesting() {
-        return mTasksSurface.isMVTilesCleanedUp();
+        if (mTasksSurface != null) {
+            return mTasksSurface.isMVTilesCleanedUp();
+        }
+        if (mMostVisitedCoordinator != null) {
+            return mMostVisitedCoordinator.isMVTilesCleanedUp();
+        }
+        return false;
     }
 
     @VisibleForTesting
     public boolean isMVTilesInitializedForTesting() {
-        return mTasksSurface.isMVTilesInitialized();
+        if (mTasksSurface != null) {
+            return mTasksSurface.isMVTilesInitialized();
+        }
+        return mIsMVTilesInitialized;
     }
 
     @VisibleForTesting
     public TileGroupDelegateImpl getTileGroupDelegateForTesting() {
-        return mTasksSurface.getTileGroupDelegate();
+        if (mTasksSurface != null) {
+            return mTasksSurface.getTileGroupDelegate();
+        }
+        return mTileGroupDelegate;
     }
 
     /**
@@ -770,9 +857,79 @@
 
         mTasksSurfacePropertyModelChangeProcessor =
                 PropertyModelChangeProcessor.create(mPropertyModel,
-                        new TasksSurfaceViewBinder.ViewHolder(
+                        new StartSurfaceWithParentViewBinder.ViewHolder(
                                 mContainerView, mTasksSurface.getView(), mSwipeRefreshLayout),
-                        TasksSurfaceViewBinder::bind);
+                        StartSurfaceWithParentViewBinder::bind);
+    }
+
+    private void createStartSurfaceWithoutTasksSurface(boolean excludeQueryTiles) {
+        ArrayList<PropertyKey> allProperties =
+                new ArrayList<>(Arrays.asList(TasksSurfaceProperties.ALL_KEYS));
+        allProperties.addAll(Arrays.asList(StartSurfaceProperties.ALL_KEYS));
+        mPropertyModel = new PropertyModel(allProperties);
+
+        assert mIsStartSurfaceEnabled;
+
+        int tabSwitcherType =
+                StartSurfaceConfiguration.START_SURFACE_LAST_ACTIVE_TAB_ONLY.getValue()
+                ? TabSwitcherType.SINGLE
+                : TabSwitcherType.CAROUSEL;
+
+        mView = (TasksView) LayoutInflater.from(mActivity).inflate(
+                R.layout.tasks_view_layout, null);
+        mView.setId(R.id.primary_tasks_surface_view);
+        mView.initialize(mActivityLifecycleDispatcher,
+                mParentTabSupplier.hasValue() && mParentTabSupplier.get().isIncognito(),
+                mWindowAndroid);
+        if (tabSwitcherType == TabSwitcherType.CAROUSEL) {
+            mTabSwitcherModule =
+                    TabManagementModuleProvider.getDelegate().createCarouselTabSwitcher(mActivity,
+                            mActivityLifecycleDispatcher, mTabModelSelector, mTabContentManager,
+                            mBrowserControlsManager, mTabCreatorManager,
+                            mMenuOrKeyboardActionController,
+                            mView.getCarouselTabSwitcherContainer(), mShareDelegateSupplier,
+                            mMultiWindowModeStateDispatcher, mScrimCoordinator, mView,
+                            mDynamicResourceLoaderSupplier, mSnackbarManager, mModalDialogManager);
+        } else {
+            mTabSwitcherModule = new SingleTabSwitcherCoordinator(
+                    mActivity, mView.getCarouselTabSwitcherContainer(), mTabModelSelector);
+        }
+        boolean isScrollableMVTEnabled =
+                !ReturnToChromeUtil.shouldImproveStartWhenFeedIsDisabled(mActivity);
+        int maxRowsForGridMVT = getQueryTilesVisibility()
+                ? QueryTileSection.getMaxRowsForMostVisitedTiles(mActivity)
+                : MAX_TILE_ROWS_FOR_GRID_MVT;
+        View mvTilesContainer = mView.findViewById(R.id.mv_tiles_container);
+        mMostVisitedCoordinator = new MostVisitedTilesCoordinator(mActivity,
+                mActivityLifecycleDispatcher, mvTilesContainer, mWindowAndroid,
+                TabUiFeatureUtilities.supportInstantStart(
+                        DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity), mActivity),
+                isScrollableMVTEnabled,
+                isScrollableMVTEnabled ? Integer.MAX_VALUE : maxRowsForGridMVT,
+                /*snapshotTileGridChangedRunnable=*/null,
+                /*tileCountChangedRunnable=*/null);
+
+        if (!excludeQueryTiles) {
+            if (ProfileManager.isInitialized()) {
+                initializeQueryTileSection(Profile.getLastUsedRegularProfile());
+            } else {
+                mQueryTileProfileSupplier = new OriginalProfileSupplier();
+                mQueryTileProfileSupplier.onAvailable(this::initializeQueryTileSection);
+            }
+        } else {
+            storeQueryTilesVisibility(false);
+        }
+        initializeOffsetChangedListener();
+        addHeaderOffsetChangeListener(mOffsetChangedListenerToGenerateScrollEvents);
+
+        mStartSurfaceWithParentViewPropertyModelChangeProcessor =
+                PropertyModelChangeProcessor.create(mPropertyModel,
+                        new StartSurfaceWithParentViewBinder.ViewHolder(
+                                mContainerView, mView, mSwipeRefreshLayout),
+                        StartSurfaceWithParentViewBinder::bind);
+
+        mStartSurfacePropertyModelChangeProcessor =
+                PropertyModelChangeProcessor.create(mPropertyModel, mView, TasksViewBinder::bind);
     }
 
     // TODO(crbug.com/1315676): Remove this function once the start surface refactoring is done,
@@ -802,7 +959,7 @@
         mSecondaryTasksSurface.getView().setId(R.id.secondary_tasks_surface_view);
         mSecondaryTasksSurfacePropertyModelChangeProcessor =
                 PropertyModelChangeProcessor.create(mPropertyModel,
-                        new TasksSurfaceViewBinder.ViewHolder(
+                        new StartSurfaceWithParentViewBinder.ViewHolder(
                                 mContainerView, mSecondaryTasksSurface.getView(), null),
                         SecondaryTasksSurfaceViewBinder::bind);
         if (mOnTabSelectingListener != null) {
@@ -900,7 +1057,9 @@
             // This function should be called together with
             // StartSurfaceToolbarMediator#updateTranslationY, which scroll up the start surface
             // toolbar together with the header.
-            mTasksSurface.updateFakeSearchBox(fakeHeight - reducedHeight, reducedHeight,
+            TasksView tasksView =
+                    mTasksSurface != null ? (TasksView) mTasksSurface.getView() : mView;
+            tasksView.updateFakeSearchBox(fakeHeight - reducedHeight, reducedHeight,
                     (int) (fakeEndPadding * (1 - expansionFraction)),
                     SearchEngineLogoUtils.getInstance().shouldShowSearchEngineLogo(false)
                             ? realTranslationX * expansionFraction
@@ -914,6 +1073,56 @@
         return mActivity.getResources().getDimensionPixelSize(id);
     }
 
+    public void initializeMVTiles() {
+        if (!LibraryLoader.getInstance().isInitialized() || mIsMVTilesInitialized
+                || mMostVisitedCoordinator == null) {
+            return;
+        }
+
+        Profile profile = Profile.getLastUsedRegularProfile();
+        MostVisitedTileNavigationDelegate navigationDelegate =
+                new MostVisitedTileNavigationDelegate(mActivity, profile, mParentTabSupplier);
+        mSuggestionsUiDelegate = new MostVisitedSuggestionsUiDelegate(
+                mView, navigationDelegate, profile, mSnackbarManager);
+        mTileGroupDelegate = new TileGroupDelegateImpl(mActivity, profile, navigationDelegate,
+                mSnackbarManager, BrowserUiUtils.HostSurface.START_SURFACE);
+
+        mMostVisitedCoordinator.initWithNative(
+                mSuggestionsUiDelegate, mTileGroupDelegate, enabled -> {});
+        mIsMVTilesInitialized = true;
+    }
+
+    private void storeQueryTilesVisibility(boolean isShown) {
+        SharedPreferencesManager.getInstance().writeBoolean(
+                ChromePreferenceKeys.QUERY_TILES_SHOWN_ON_START_SURFACE, isShown);
+    }
+
+    private boolean getQueryTilesVisibility() {
+        return SharedPreferencesManager.getInstance().readBoolean(
+                ChromePreferenceKeys.QUERY_TILES_SHOWN_ON_START_SURFACE, false);
+    }
+
+    private void initializeQueryTileSection(Profile profile) {
+        assert profile != null;
+        if (!QueryTileUtils.isQueryTilesEnabledOnStartSurface()) {
+            storeQueryTilesVisibility(false);
+            return;
+        }
+        mQueryTileSection = new QueryTileSection(mView.findViewById(R.id.query_tiles_layout),
+                profile, query -> performSearchQuery(query.queryText, query.searchParams));
+        storeQueryTilesVisibility(true);
+        mQueryTileProfileSupplier = null;
+    }
+
+    /**
+     * Called to send the search query and params to omnibox to kick off a search.
+     * @param queryText Text of the search query to perform.
+     * @param searchParams A list of params to sent along with the search query.
+     */
+    void performSearchQuery(String queryText, List<String> searchParams) {
+        mStartSurfaceMediator.performSearchQuery(queryText, searchParams);
+    }
+
     @VisibleForTesting
     boolean isSecondaryTasksSurfaceEmptyForTesting() {
         return mSecondaryTasksSurface == null;
@@ -923,4 +1132,12 @@
     FeedSwipeRefreshLayout getFeedSwipeRefreshLayoutForTesting() {
         return mSwipeRefreshLayout;
     }
+
+    TasksSurface getTasksSurfaceForTesting() {
+        return mTasksSurface;
+    }
+
+    TasksView getViewForTesting() {
+        return mView;
+    }
 }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java
index 197f2a7..24c107e 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java
@@ -6,7 +6,6 @@
 
 import android.animation.Animator;
 import android.content.Context;
-import android.view.ViewGroup;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -17,7 +16,7 @@
 import org.chromium.chrome.browser.layouts.EventFilter;
 import org.chromium.chrome.browser.layouts.LayoutType;
 import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer;
-import org.chromium.chrome.features.tasks.TasksSurface;
+import org.chromium.chrome.features.tasks.TasksView;
 
 /**
  * A {@link Layout} that shows Start Surface home view.
@@ -131,15 +130,14 @@
         if (!background || newIsIncognito || !mIsShown) {
             return;
         }
-        TasksSurface primaryTasksSurface = mStartSurface.getPrimaryTasksSurface();
-        assert primaryTasksSurface != null;
+        TasksView startSurfaceView = mStartSurface.getPrimarySurfaceView();
+        assert startSurfaceView != null;
 
         if (mBackgroundTabAnimation != null && mBackgroundTabAnimation.isStarted()) {
             mBackgroundTabAnimation.end();
         }
-        mBackgroundTabAnimation =
-                BackgroundTabAnimation.create(this, (ViewGroup) primaryTasksSurface.getView(),
-                        originX, originY, getOrientation() == Orientation.PORTRAIT);
+        mBackgroundTabAnimation = BackgroundTabAnimation.create(
+                this, startSurfaceView, originX, originY, getOrientation() == Orientation.PORTRAIT);
         mBackgroundTabAnimation.start();
     }
 
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index a941343..901b11622 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -11,6 +11,8 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.RESET_FEED_SURFACE_SCROLL_POSITION;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.FAKE_SEARCH_BOX_CLICK_LISTENER;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.FAKE_SEARCH_BOX_TEXT_WATCHER;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_FAKE_SEARCH_BOX_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_INCOGNITO;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_INITIALIZED;
@@ -20,6 +22,7 @@
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_TITLE_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.LENS_BUTTON_CLICK_LISTENER;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MORE_TABS_CLICK_LISTENER;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_LEFT_RIGHT_MARGIN;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.MV_TILES_CONTAINER_TOP_MARGIN;
@@ -30,9 +33,12 @@
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TAB_SWITCHER_TITLE_TOP_MARGIN;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TOP_TOOLBAR_PLACEHOLDER_HEIGHT;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER;
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -64,8 +70,10 @@
 import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
 import org.chromium.chrome.browser.logo.LogoCoordinator;
 import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin;
+import org.chromium.chrome.browser.omnibox.OmniboxFocusReason;
 import org.chromium.chrome.browser.omnibox.OmniboxStub;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
+import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
@@ -90,6 +98,8 @@
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.util.ColorUtils;
 
+import java.util.List;
+
 /** The mediator implements the logic to interact with the surfaces and caller. */
 class StartSurfaceMediator implements TabSwitcher.TabSwitcherViewObserver, View.OnClickListener,
                                       StartSurface.OnTabSelectingListener, BackPressHandler,
@@ -201,6 +211,10 @@
     private boolean mHideOverviewOnTabSelecting = true;
     private StartSurface.OnTabSelectingListener mOnTabSelectingListener;
     private ViewGroup mTabSwitcherContainer;
+    // The single or carousel Tab switcher module on the Start surface.
+    // None-null when the Start surface refactoring is enabled.
+    @Nullable
+    private TabSwitcher mTabSwitcherModule;
     private SnackbarManager mSnackbarManager;
     private boolean mIsNativeInitialized;
     // The timestamp at which the Start Surface was last shown to the user.
@@ -208,8 +222,11 @@
     private boolean mIsStartSurfaceRefactorEnabled;
     private OnClickListener mTabSwitcherClickHandler;
 
+    // TODO(crbug.com/1315676): Clean up TabSwitcher#Controller once the start surface refactoring
+    // is done.
     StartSurfaceMediator(Controller controller, ViewGroup tabSwitcherContainer,
-            TabModelSelector tabModelSelector, @Nullable PropertyModel propertyModel,
+            @Nullable TabSwitcher tabSwitcherModule, TabModelSelector tabModelSelector,
+            @Nullable PropertyModel propertyModel,
             @Nullable SecondaryTasksSurfaceInitializer secondaryTasksSurfaceInitializer,
             boolean isStartSurfaceEnabled, Context context,
             BrowserControlsStateProvider browserControlsStateProvider,
@@ -222,6 +239,7 @@
             OnClickListener tabSwitcherClickHandler) {
         mController = controller;
         mTabSwitcherContainer = tabSwitcherContainer;
+        mTabSwitcherModule = tabSwitcherModule;
         mTabModelSelector = tabModelSelector;
         mPropertyModel = propertyModel;
         mSecondaryTasksSurfaceInitializer = secondaryTasksSurfaceInitializer;
@@ -251,6 +269,19 @@
         if (mPropertyModel != null) {
             assert mIsStartSurfaceEnabled;
 
+            if (mTabSwitcherModule != null) {
+                boolean isTabCarousel = mTabSwitcherModule.getController().getTabSwitcherType()
+                        == TabSwitcherType.CAROUSEL;
+                mPropertyModel.set(IS_TAB_CAROUSEL_VISIBLE, isTabCarousel);
+                mPropertyModel.set(IS_TAB_CAROUSEL_TITLE_VISIBLE, isTabCarousel);
+
+                // Set the initial state.
+                mPropertyModel.set(IS_SURFACE_BODY_VISIBLE, true);
+                mPropertyModel.set(IS_FAKE_SEARCH_BOX_VISIBLE, true);
+                mPropertyModel.set(IS_VOICE_RECOGNITION_BUTTON_VISIBLE, false);
+                mPropertyModel.set(IS_LENS_BUTTON_VISIBLE, false);
+            }
+
             // Show feed loading image if necessary.
             if (shouldShowFeedPlaceholder()) {
                 assert feedPlaceholderParentView != null;
@@ -459,8 +490,51 @@
                     if (mLogoCoordinator != null) mLogoCoordinator.initWithNative();
                 }
             }
-        }
 
+            if (mTabSwitcherModule != null) {
+                mPropertyModel.set(FAKE_SEARCH_BOX_CLICK_LISTENER, v -> {
+                    mOmniboxStub.setUrlBarFocus(
+                            true, null, OmniboxFocusReason.TASKS_SURFACE_FAKE_BOX_TAP);
+                    RecordUserAction.record("TasksSurface.FakeBox.Tapped");
+                });
+                mPropertyModel.set(FAKE_SEARCH_BOX_TEXT_WATCHER, new TextWatcher() {
+                    @Override
+                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                    }
+
+                    @Override
+                    public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+                    @Override
+                    public void afterTextChanged(Editable s) {
+                        if (s.length() == 0) return;
+                        mOmniboxStub.setUrlBarFocus(true, s.toString(),
+                                OmniboxFocusReason.TASKS_SURFACE_FAKE_BOX_LONG_PRESS);
+                        RecordUserAction.record("TasksSurface.FakeBox.LongPressed");
+
+                        // This won't cause infinite loop since we checked s.length() == 0 above.
+                        s.clear();
+                    }
+                });
+                mPropertyModel.set(VOICE_SEARCH_BUTTON_CLICK_LISTENER, v -> {
+                    FeedReliabilityLogger feedReliabilityLogger = getFeedReliabilityLogger();
+                    if (feedReliabilityLogger != null) {
+                        feedReliabilityLogger.onVoiceSearch();
+                    }
+                    mOmniboxStub.getVoiceRecognitionHandler().startVoiceRecognition(
+                            VoiceRecognitionHandler.VoiceInteractionSource.TASKS_SURFACE);
+                    RecordUserAction.record("TasksSurface.FakeBox.VoiceSearch");
+                });
+
+                mPropertyModel.set(LENS_BUTTON_CLICK_LISTENER, v -> {
+                    LensMetrics.recordClicked(LensEntryPoint.TASKS_SURFACE);
+                    mOmniboxStub.startLens(LensEntryPoint.TASKS_SURFACE);
+                });
+            }
+        }
+        if (mTabSwitcherModule != null) {
+            mTabSwitcherModule.initWithNative();
+        }
         mFeedVisibilityPrefOnStartUp = prefService.getBoolean(Pref.ARTICLES_LIST_VISIBLE);
     }
 
@@ -668,7 +742,7 @@
             // reset the scrolling position.
             resetScrollPosition();
         } else if (mStartSurfaceState == StartSurfaceState.SHOWING_TABSWITCHER) {
-            maybeDestroyFeedPlaceholder();
+            onHide();
             // Set secondary surface visible to make sure tab list recyclerview is updated in time
             // (before GTS animations start). We need to skip
             // mSecondaryTasksSurfaceController#showOverview here since it will hide GTS animations.
@@ -887,11 +961,14 @@
         return ret;
     }
 
-    void maybeDestroyFeedPlaceholder() {
+    void onHide() {
         if (mFeedPlaceholderCoordinator != null) {
             mFeedPlaceholderCoordinator.destroy();
             mFeedPlaceholderCoordinator = null;
         }
+        if (mTabSwitcherModule != null) {
+            mTabSwitcherModule.getTabListDelegate().postHiding();
+        }
     }
 
     @Override
@@ -1365,6 +1442,12 @@
         return mLogoCoordinator != null && mLogoCoordinator.isLogoVisible();
     }
 
+    void performSearchQuery(String queryText, List<String> searchParams) {
+        if (mOmniboxStub != null) {
+            mOmniboxStub.performSearchQuery(queryText, searchParams);
+        }
+    }
+
     void setOnTabSelectingListener(StartSurface.OnTabSelectingListener onTabSelectingListener) {
         mOnTabSelectingListener = onTabSelectingListener;
     }
@@ -1496,4 +1579,12 @@
         return mPropertyModel.get(EXPLORE_SURFACE_COORDINATOR)
                 .getFeedActionDelegateForTesting(); // IN-TEST
     }
+
+    TabSwitcher getTabSwitcherModuleForTesting() {
+        return mTabSwitcherModule;
+    }
+
+    Runnable getInitializeMVTilesRunnableForTesting() {
+        return mInitializeMVTilesRunnable;
+    }
 }
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinder.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinder.java
similarity index 98%
rename from chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinder.java
rename to chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinder.java
index 7037d7d..a170acce 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinder.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinder.java
@@ -17,7 +17,7 @@
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** The binder controls the display of the {@link TasksView} in its parent. */
-class TasksSurfaceViewBinder {
+class StartSurfaceWithParentViewBinder {
     private static final long FADE_IN_DURATION_MS = 50;
 
     /**
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java
index 6c841ef..bba6c60 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java
@@ -48,7 +48,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.chrome.features.start_surface.StartSurface.TabSwitcherViewObserver;
-import org.chromium.chrome.features.tasks.TasksSurface;
+import org.chromium.chrome.features.tasks.TasksView;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.animation.Interpolators;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
@@ -484,15 +484,14 @@
                 || mStartSurface.getStartSurfaceState() != StartSurfaceState.SHOWN_HOMEPAGE) {
             return;
         }
-        TasksSurface primaryTasksSurface = mStartSurface.getPrimaryTasksSurface();
+        TasksView primaryTasksSurface = mStartSurface.getPrimarySurfaceView();
         assert primaryTasksSurface != null;
 
         if (mBackgroundTabAnimation != null && mBackgroundTabAnimation.isStarted()) {
             mBackgroundTabAnimation.end();
         }
-        mBackgroundTabAnimation =
-                BackgroundTabAnimation.create(this, (ViewGroup) primaryTasksSurface.getView(),
-                        originX, originY, getOrientation() == Orientation.PORTRAIT);
+        mBackgroundTabAnimation = BackgroundTabAnimation.create(this, primaryTasksSurface, originX,
+                originY, getOrientation() == Orientation.PORTRAIT);
         mBackgroundTabAnimation.start();
     }
 
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherCoordinator.java
index 317aac5..cbef4369 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherCoordinator.java
@@ -27,14 +27,14 @@
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /** Coordinator of the single tab tab switcher. */
-class SingleTabSwitcherCoordinator implements TabSwitcher {
+public class SingleTabSwitcherCoordinator implements TabSwitcher {
     private final PropertyModelChangeProcessor mPropertyModelChangeProcessor;
     private final SingleTabSwitcherMediator mMediator;
     private final TabListFaviconProvider mTabListFaviconProvider;
     private final TabSwitcher.TabListDelegate mTabListDelegate;
     private final TabModelSelector mTabModelSelector;
 
-    SingleTabSwitcherCoordinator(@NonNull Activity activity, @NonNull ViewGroup container,
+    public SingleTabSwitcherCoordinator(@NonNull Activity activity, @NonNull ViewGroup container,
             @NonNull TabModelSelector tabModelSelector) {
         mTabModelSelector = tabModelSelector;
         PropertyModel propertyModel = new PropertyModel(SingleTabViewProperties.ALL_KEYS);
@@ -149,7 +149,6 @@
 
     @Override
     public Supplier<Boolean> getTabGridDialogVisibilitySupplier() {
-        assert false : "should not reach here";
         return null;
     }
 
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceCoordinator.java
index f4ba433..0c61140 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksSurfaceCoordinator.java
@@ -37,8 +37,6 @@
 import org.chromium.chrome.browser.query_tiles.QueryTileSection;
 import org.chromium.chrome.browser.query_tiles.QueryTileUtils;
 import org.chromium.chrome.browser.share.ShareDelegate;
-import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
-import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegateImpl;
 import org.chromium.chrome.browser.suggestions.tile.MostVisitedTilesCoordinator;
 import org.chromium.chrome.browser.suggestions.tile.TileGroupDelegateImpl;
 import org.chromium.chrome.browser.tab.Tab;
@@ -52,6 +50,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.util.BrowserUiUtils;
+import org.chromium.chrome.features.start_surface.MostVisitedSuggestionsUiDelegate;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -225,8 +224,8 @@
         Profile profile = Profile.getLastUsedRegularProfile();
         MostVisitedTileNavigationDelegate navigationDelegate =
                 new MostVisitedTileNavigationDelegate(mActivity, profile, mParentTabSupplier);
-        mSuggestionsUiDelegate =
-                new MostVisitedSuggestionsUiDelegate(navigationDelegate, profile, mSnackbarManager);
+        mSuggestionsUiDelegate = new MostVisitedSuggestionsUiDelegate(
+                mView, navigationDelegate, profile, mSnackbarManager);
         mTileGroupDelegate = new TileGroupDelegateImpl(mActivity, profile, navigationDelegate,
                 mSnackbarManager, BrowserUiUtils.HostSurface.START_SURFACE);
 
@@ -342,20 +341,6 @@
         return (mTabSwitcher != null) ? mTabSwitcher.getTabSwitcherCustomViewManager() : null;
     }
 
-    /** Suggestions UI Delegate for constructing the TileGroup. */
-    private class MostVisitedSuggestionsUiDelegate extends SuggestionsUiDelegateImpl {
-        public MostVisitedSuggestionsUiDelegate(SuggestionsNavigationDelegate navigationDelegate,
-                Profile profile, SnackbarManager snackbarManager) {
-            super(navigationDelegate, profile, /*host=*/null, snackbarManager);
-        }
-
-        @Override
-        public boolean isVisible() {
-            return mView.getVisibility() == View.VISIBLE
-                    && mView.findViewById(R.id.mv_tiles_layout).getVisibility() == View.VISIBLE;
-        }
-    }
-
     private void storeQueryTilesVisibility(boolean isShown) {
         SharedPreferencesManager.getInstance().writeBoolean(
                 ChromePreferenceKeys.QUERY_TILES_SHOWN_ON_START_SURFACE, isShown);
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
index 0ac3a7ed..9175b93 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksView.java
@@ -46,7 +46,6 @@
  * The view of the tasks surface. Set public for testing.
  */
 public class TasksView extends CoordinatorLayoutForPointer {
-    private static final int OMNIBOX_BOTTOM_PADDING_DP = 4;
     private static final MutableFlagWithSafeDefault sIncognitoRevampFlag =
             new MutableFlagWithSafeDefault(ChromeFeatureList.INCOGNITO_NTP_REVAMP, false);
 
@@ -63,7 +62,6 @@
             CookieControlsEnforcement.NO_ENFORCEMENT;
     private View.OnClickListener mIncognitoCookieControlsIconClickListener;
     private UiConfig mUiConfig;
-    private boolean mIsIncognito;
 
     /** Default constructor needed to inflate via XML. */
     public TasksView(Context context, AttributeSet attrs) {
@@ -117,11 +115,11 @@
                 titleDescription.getPaddingBottom());
     }
 
-    ViewGroup getCarouselTabSwitcherContainer() {
+    public ViewGroup getCarouselTabSwitcherContainer() {
         return mCarouselTabSwitcherContainer;
     }
 
-    ViewGroup getBodyViewContainer() {
+    public ViewGroup getBodyViewContainer() {
         return findViewById(R.id.tasks_surface_body);
     }
 
@@ -208,7 +206,6 @@
         int hintTextColor = mContext.getColor(isIncognito ? R.color.locationbar_light_hint_text
                                                           : R.color.locationbar_dark_hint_text);
         mSearchBoxCoordinator.setSearchBoxHintColor(hintTextColor);
-        mIsIncognito = isIncognito;
     }
 
     /**
@@ -388,7 +385,7 @@
      * Add a header offset change listener.
      * @param onOffsetChangedListener The given header offset change listener.
      */
-    void addHeaderOffsetChangeListener(
+    public void addHeaderOffsetChangeListener(
             AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
         if (mHeaderView != null) {
             mHeaderView.addOnOffsetChangedListener(onOffsetChangedListener);
@@ -399,7 +396,7 @@
      * Remove the given header offset change listener.
      * @param onOffsetChangedListener The header offset change listener which should be removed.
      */
-    void removeHeaderOffsetChangeListener(
+    public void removeHeaderOffsetChangeListener(
             AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
         if (mHeaderView != null) {
             mHeaderView.removeOnOffsetChangedListener(onOffsetChangedListener);
@@ -415,7 +412,7 @@
      * @param buttonSize Current height and width of the buttons in fake search box layout.
      * @param lensButtonLeftMargin Current left margin of the lens button in fake search box layout.
      */
-    void updateFakeSearchBox(int height, int topMargin, int endPadding, float translationX,
+    public void updateFakeSearchBox(int height, int topMargin, int endPadding, float translationX,
             int buttonSize, int lensButtonLeftMargin) {
         if (mSearchBoxCoordinator.getView().getVisibility() != View.VISIBLE) return;
         mSearchBoxCoordinator.setHeight(height);
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java
index 85e0b8ee..db4db0b 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/TasksViewBinder.java
@@ -39,8 +39,10 @@
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
-// The view binder of the tasks surface view.
-class TasksViewBinder {
+/**
+ *  The view binder of the tasks surface view.
+ */
+public class TasksViewBinder {
     public static void bind(PropertyModel model, TasksView view, PropertyKey propertyKey) {
         if (propertyKey == FAKE_SEARCH_BOX_CLICK_LISTENER) {
             view.getSearchBoxCoordinator().setSearchBoxClickListener(
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
index 257a0025..727ff34e 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
@@ -320,6 +320,7 @@
     @Feature({"StartSurface"})
     // clang-format off
     @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS})
+    @DisabledTest(message = "https://crbug.com/1246457")
     @DisableFeatures({ChromeFeatureList.BACK_GESTURE_REFACTOR})
     public void testSwipeBackOnStartSurfaceHomePage() throws ExecutionException {
         // clang-format on
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
index 610c3f1b..b59b4a3 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
@@ -61,7 +61,8 @@
 
         mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
         mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
-                new TasksSurfaceViewBinder.ViewHolder(mParentView, mTasksSurfaceView, null),
+                new StartSurfaceWithParentViewBinder.ViewHolder(
+                        mParentView, mTasksSurfaceView, null),
                 SecondaryTasksSurfaceViewBinder::bind);
     }
 
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java
index 0ae2fc00..46f963a9 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java
@@ -5,6 +5,10 @@
 package org.chromium.chrome.features.start_surface;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
@@ -42,8 +46,12 @@
 import org.chromium.chrome.browser.suggestions.tile.TileSource;
 import org.chromium.chrome.browser.suggestions.tile.TileTitleSource;
 import org.chromium.chrome.browser.tasks.ReturnToChromeUtil;
+import org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegate.TabSwitcherType;
+import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
 import org.chromium.chrome.browser.util.BrowserUiUtils;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.mojom.WindowOpenDisposition;
@@ -85,7 +93,36 @@
     }
 
     @Test
+    @EnableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR)
+    public void testShowAndHideWithRefactorEnabled() {
+        assertTrue(ChromeFeatureList.sStartSurfaceRefactor.isEnabled());
+        assertNull(mCoordinator.getTasksSurfaceForTesting());
+        TabSwitcher tabSwitcherModule =
+                mCoordinator.getMediatorForTesting().getTabSwitcherModuleForTesting();
+        assertNotNull(tabSwitcherModule);
+        assertEquals(TabSwitcherType.SINGLE,
+                tabSwitcherModule.getTabListDelegate().getListModeForTesting());
+        assertNotNull(mCoordinator.getViewForTesting());
+
+        mCoordinator.showOverview(false);
+        assertTrue(mCoordinator.isMVTilesInitializedForTesting());
+        assertFalse(mCoordinator.isMVTilesCleanedUpForTesting());
+        assertNotNull(mCoordinator.getTileGroupDelegateForTesting());
+
+        mCoordinator.onHide();
+        assertTrue(mCoordinator.isMVTilesCleanedUpForTesting());
+        assertFalse(mCoordinator.isMVTilesInitializedForTesting());
+        assertNull(mCoordinator.getTileGroupDelegateForTesting());
+    }
+
+    @Test
+    @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR)
     public void testCleanUpMVTilesAfterHiding() {
+        assertFalse(ChromeFeatureList.sStartSurfaceRefactor.isEnabled());
+        assertNotNull(mCoordinator.getTasksSurfaceForTesting());
+        assertNull(mCoordinator.getMediatorForTesting().getTabSwitcherModuleForTesting());
+        assertNull(mCoordinator.getViewForTesting());
+
         mCoordinator.setStartSurfaceState(StartSurfaceState.SHOWING_HOMEPAGE);
         mCoordinator.showOverview(false);
 
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
index e42b726e..c7267974 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -34,10 +34,14 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SECONDARY_SURFACE_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.FAKE_SEARCH_BOX_CLICK_LISTENER;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.FAKE_SEARCH_BOX_TEXT_WATCHER;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_FAKE_SEARCH_BOX_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_INCOGNITO;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_INITIALIZED;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_VISIBLE;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_LENS_BUTTON_VISIBLE;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_SURFACE_BODY_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_TITLE_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_TAB_CAROUSEL_VISIBLE;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.IS_VOICE_RECOGNITION_BUTTON_VISIBLE;
@@ -47,6 +51,7 @@
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.SINGLE_TAB_TOP_MARGIN;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TAB_SWITCHER_TITLE_TOP_MARGIN;
 import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.TASKS_SURFACE_BODY_TOP_MARGIN;
+import static org.chromium.chrome.features.tasks.TasksSurfaceProperties.VOICE_SEARCH_BUTTON_CLICK_LISTENER;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -81,6 +86,7 @@
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.feed.FeedReliabilityLogger;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.lens.LensEntryPoint;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
 import org.chromium.chrome.browser.logo.LogoBridge;
@@ -108,6 +114,7 @@
 import org.chromium.chrome.browser.tasks.ReturnToChromeUtil;
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegate.TabSwitcherType;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
+import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher.TabListDelegate;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher.TabSwitcherViewObserver;
 import org.chromium.chrome.features.start_surface.StartSurfaceMediator.SecondaryTasksSurfaceInitializer;
 import org.chromium.chrome.features.tasks.TasksSurfaceProperties;
@@ -197,6 +204,12 @@
     private ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
     @Mock
     private OnClickListener mTabSwitcherClickHandler;
+    @Mock
+    private TabSwitcher mTabSwitcherModule;
+    @Mock
+    private TabListDelegate mTabListDelegate;
+    @Mock
+    private TabSwitcher.Controller mSingleTabSwitcherModuleController;
     @Captor
     private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor;
     @Captor
@@ -1259,7 +1272,7 @@
 
         StartSurfaceMediator mediator = createStartSurfaceMediatorWithoutInit(
                 /* isStartSurfaceEnabled= */ true,
-                /* hadWarmStart= */ false);
+                /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
         verify(mCarouselOrSingleTabSwitcherModuleController)
                 .addTabSwitcherViewObserver(
                         mCarouselTabSwitcherModuleVisibilityObserverCaptor.capture());
@@ -1293,7 +1306,7 @@
                 resources.getDimensionPixelSize(R.dimen.tab_switcher_title_top_margin);
 
         createStartSurfaceMediatorWithoutInit(/* isStartSurfaceEnabled= */ true,
-                /* hadWarmStart= */ false);
+                /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
         assertThat(mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN),
                 equalTo(tasksSurfaceBodyTopMargin));
         assertThat(mPropertyModel.get(MV_TILES_CONTAINER_TOP_MARGIN),
@@ -1331,7 +1344,7 @@
 
         StartSurfaceMediator mediator =
                 createStartSurfaceMediatorWithoutInit(/* isStartSurfaceEnabled= */ true,
-                        /* hadWarmStart= */ false);
+                        /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
         assertThat(mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN),
                 equalTo(tasksSurfaceBodyTopMarginWithTab));
         assertThat(mPropertyModel.get(MV_TILES_CONTAINER_TOP_MARGIN),
@@ -1365,7 +1378,7 @@
 
         StartSurfaceMediator mediator = createStartSurfaceMediator(
                 /* isStartSurfaceEnabled= */ true,
-                /* hadWarmStart= */ true);
+                /* isRefactorEnabled */ false, /* hadWarmStart= */ true);
         assertFalse(mediator.shouldShowFeedPlaceholder());
 
         mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, true);
@@ -1470,8 +1483,8 @@
         Assert.assertTrue(ReturnToChromeUtil.shouldImproveStartWhenFeedIsDisabled(
                 ContextUtils.getApplicationContext()));
 
-        StartSurfaceMediator mediator =
-                createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true, false);
+        StartSurfaceMediator mediator = createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true,
+                /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
         showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE);
 
         verify(mLogoContainerView).setVisibility(View.VISIBLE);
@@ -1490,8 +1503,8 @@
         Assert.assertFalse(ReturnToChromeUtil.shouldImproveStartWhenFeedIsDisabled(
                 ContextUtils.getApplicationContext()));
 
-        StartSurfaceMediator mediator =
-                createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true, false);
+        StartSurfaceMediator mediator = createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true,
+                /* isRefactorEnabled */ false, /* hadWarmStart= */ false);
         showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE);
 
         verify(mLogoContainerView, times(0)).setVisibility(View.VISIBLE);
@@ -1608,14 +1621,27 @@
      * showing but Tab switcher hasn't been created yet.
      */
     @Test
+    @DisableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR)
     public void testBackPressHandlerOnStartSurfaceWithoutTabSwitcherCreated() {
+        backPressHandlerOnStartSurfaceWithoutTabSwitcherCreatedImpl(
+                StartSurfaceState.SHOWN_HOMEPAGE);
+    }
+
+    @Test
+    @EnableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR)
+    public void testBackPressHandlerOnStartSurfaceWithoutTabSwitcherCreated_RefactorEnabled() {
+        backPressHandlerOnStartSurfaceWithoutTabSwitcherCreatedImpl(null);
+    }
+
+    private void backPressHandlerOnStartSurfaceWithoutTabSwitcherCreatedImpl(
+            @StartSurfaceState Integer state) {
         doReturn(false).when(mTabModelSelector).isIncognitoSelected();
         doReturn(false).when(mTabModelSelector).isIncognitoSelected();
         doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler();
         doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
         StartSurfaceMediator mediator = createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true);
 
-        showHomepageAndVerify(mediator, StartSurfaceState.SHOWN_HOMEPAGE);
+        showHomepageAndVerify(mediator, state);
 
         doReturn(true).when(mCarouselOrSingleTabSwitcherModuleController).isDialogVisible();
         mediator.onBackPressed();
@@ -1766,14 +1792,58 @@
         histogramWatcher.assertExpected();
     }
 
+    @Test
+    @EnableFeatures(ChromeFeatureList.START_SURFACE_REFACTOR)
+    public void testShowAndOnHide() {
+        doReturn(false).when(mTabModelSelector).isIncognitoSelected();
+        doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler();
+        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
+        doReturn(mSingleTabSwitcherModuleController).when(mTabSwitcherModule).getController();
+        doReturn(TabSwitcherType.SINGLE)
+                .when(mSingleTabSwitcherModuleController)
+                .getTabSwitcherType();
+        doReturn(true).when(mOmniboxStub).isLensEnabled(LensEntryPoint.TASKS_SURFACE);
+
+        StartSurfaceMediator mediator = createStartSurfaceMediator(/*isStartSurfaceEnabled=*/true,
+                /* isRefactorEnabled */ true);
+        assertEquals(mInitializeMVTilesRunnable, mediator.getInitializeMVTilesRunnableForTesting());
+        assertEquals(mTabSwitcherModule, mediator.getTabSwitcherModuleForTesting());
+
+        showHomepageAndVerify(mediator, null);
+        verify(mOmniboxStub, times(2))
+                .addUrlFocusChangeListener(mUrlFocusChangeListenerCaptor.capture());
+        assertFalse(mPropertyModel.get(IS_INCOGNITO));
+        assertTrue(mPropertyModel.get(IS_VOICE_RECOGNITION_BUTTON_VISIBLE));
+        assertTrue(mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE));
+        assertTrue(mPropertyModel.get(MV_TILES_VISIBLE));
+        assertTrue(mPropertyModel.get(IS_SHOWING_OVERVIEW));
+        assertTrue(mPropertyModel.get(IS_SURFACE_BODY_VISIBLE));
+        assertTrue(mPropertyModel.get(IS_FAKE_SEARCH_BOX_VISIBLE));
+        assertTrue(mPropertyModel.get(IS_LENS_BUTTON_VISIBLE));
+        assertNotNull(mPropertyModel.get(FAKE_SEARCH_BOX_CLICK_LISTENER));
+        assertNotNull(mPropertyModel.get(FAKE_SEARCH_BOX_TEXT_WATCHER));
+        assertNotNull(mPropertyModel.get(VOICE_SEARCH_BUTTON_CLICK_LISTENER));
+
+        doReturn(mTabListDelegate).when(mTabSwitcherModule).getTabListDelegate();
+        mediator.onHide();
+        verify(mTabListDelegate).postHiding();
+    }
+
     private StartSurfaceMediator createStartSurfaceMediator(boolean isStartSurfaceEnabled) {
-        return createStartSurfaceMediator(isStartSurfaceEnabled, /* hadWarmStart= */ false);
+        return createStartSurfaceMediator(isStartSurfaceEnabled, /* isRefactorEnabled */ false,
+                /* hadWarmStart= */ false);
     }
 
     private StartSurfaceMediator createStartSurfaceMediator(
-            boolean isStartSurfaceEnabled, boolean hadWarmStart) {
-        StartSurfaceMediator mediator =
-                createStartSurfaceMediatorWithoutInit(isStartSurfaceEnabled, hadWarmStart);
+            boolean isStartSurfaceEnabled, boolean isRefactorEnabled) {
+        return createStartSurfaceMediator(isStartSurfaceEnabled, isRefactorEnabled,
+                /* hadWarmStart= */ false);
+    }
+
+    private StartSurfaceMediator createStartSurfaceMediator(
+            boolean isStartSurfaceEnabled, boolean isRefactorEnabled, boolean hadWarmStart) {
+        StartSurfaceMediator mediator = createStartSurfaceMediatorWithoutInit(
+                isStartSurfaceEnabled, isRefactorEnabled, hadWarmStart);
         mediator.initWithNative(mOmniboxStub,
                 isStartSurfaceEnabled ? mExploreSurfaceCoordinatorFactory : null, mPrefService,
                 null);
@@ -1784,17 +1854,20 @@
     }
 
     private StartSurfaceMediator createStartSurfaceMediatorWithoutInit(
-            boolean isStartSurfaceEnabled, boolean hadWarmStart) {
+            boolean isStartSurfaceEnabled, boolean isRefactorEnabled, boolean hadWarmStart) {
+        boolean hasTasksView = isStartSurfaceEnabled && !isRefactorEnabled;
+        boolean hasTabSwitcherModule = isStartSurfaceEnabled && isRefactorEnabled;
         return new StartSurfaceMediator(mCarouselOrSingleTabSwitcherModuleController,
-                null /* tabSwitcherContainer */, mTabModelSelector,
-                !isStartSurfaceEnabled ? null : mPropertyModel,
-                isStartSurfaceEnabled ? mSecondaryTasksSurfaceInitializer : null,
-                isStartSurfaceEnabled, ContextUtils.getApplicationContext(),
-                mBrowserControlsStateProvider, mActivityStateChecker, true /* excludeQueryTiles */,
-                mStartSurfaceSupplier, hadWarmStart, new DummyJankTracker(),
-                mInitializeMVTilesRunnable, mParentTabSupplier, mLogoContainerView,
-                mBackPressManager, null /* feedPlaceholderParentView */,
-                mActivityLifecycleDispatcher, mTabSwitcherClickHandler);
+                null /* tabSwitcherContainer */, hasTabSwitcherModule ? mTabSwitcherModule : null,
+                mTabModelSelector, !isStartSurfaceEnabled ? null : mPropertyModel,
+                hasTasksView ? mSecondaryTasksSurfaceInitializer : null, isStartSurfaceEnabled,
+                ContextUtils.getApplicationContext(), mBrowserControlsStateProvider,
+                mActivityStateChecker, true /* excludeQueryTiles */, mStartSurfaceSupplier,
+                hadWarmStart, new DummyJankTracker(),
+                hasTasksView || hasTabSwitcherModule ? mInitializeMVTilesRunnable : null,
+                mParentTabSupplier, mLogoContainerView, mBackPressManager,
+                null /* feedPlaceholderParentView */, mActivityLifecycleDispatcher,
+                mTabSwitcherClickHandler);
     }
 
     private void onControlsOffsetChanged(int topOffset, int topControlsMinHeightOffset) {
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinderUnitTest.java
similarity index 94%
rename from chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java
rename to chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinderUnitTest.java
index f8c4a71..858da471 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinderUnitTest.java
@@ -32,10 +32,10 @@
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
-/** Tests for {@link TasksSurfaceViewBinder}. */
+/** Tests for {@link StartSurfaceWithParentViewBinder}. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
-public class TasksSurfaceViewBinderUnitTest {
+public class StartSurfaceWithParentViewBinderUnitTest {
     private Activity mActivity;
     private ViewGroup mParentView;
     private ViewGroup mTasksSurfaceView;
@@ -57,9 +57,9 @@
 
         mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
         mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
-                new TasksSurfaceViewBinder.ViewHolder(
+                new StartSurfaceWithParentViewBinder.ViewHolder(
                         mParentView, mTasksSurfaceView, mFeedSwipeRefreshLayout),
-                TasksSurfaceViewBinder::bind);
+                StartSurfaceWithParentViewBinder::bind);
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni b/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
index af329ef..aced0a98 100644
--- a/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
+++ b/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
@@ -8,7 +8,7 @@
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTestRule.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java",
-  "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java",
+  "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinderUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabViewBinderUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksSurfaceMediatorUnitTest.java",
diff --git a/chrome/android/features/start_surface/start_surface_java_sources.gni b/chrome/android/features/start_surface/start_surface_java_sources.gni
index d8eaa4d4..e17d858 100644
--- a/chrome/android/features/start_surface/start_surface_java_sources.gni
+++ b/chrome/android/features/start_surface/start_surface_java_sources.gni
@@ -11,6 +11,7 @@
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceNavigationDelegate.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceViewBinder.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/FeedPlaceholderCoordinator.java",
+  "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/MostVisitedSuggestionsUiDelegate.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinder.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurface.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java",
@@ -18,8 +19,8 @@
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceHomeLayout.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceProperties.java",
+  "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceWithParentViewBinder.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayout.java",
-  "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinder.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/MostVisitedTileNavigationDelegate.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherCoordinator.java",
   "//chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java",
diff --git a/chrome/android/features/tab_ui/public/android/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeUtil.java b/chrome/android/features/tab_ui/public/android/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeUtil.java
index 5983c6a..409d1bb 100644
--- a/chrome/android/features/tab_ui/public/android/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeUtil.java
+++ b/chrome/android/features/tab_ui/public/android/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeUtil.java
@@ -19,9 +19,10 @@
  * Internal themes are provided via @{@link TabUiThemeProvider}
  */
 public class TabUiThemeUtil {
-    private static final float MAX_TAB_STRIP_TAB_WIDTH_DP = 265.f;
     private static final String TAG = "TabUiThemeProvider";
+    private static final float MAX_TAB_STRIP_TAB_WIDTH_DP = 265.f;
     private static final float DETACHED_TAB_OVERLAY_ALPHA = 0.85f;
+    private static final float DETACHED_TAB_OVERLAY_ALPHA_EDIT_MODE = 0.2f;
 
     /**
      * Returns the color for the tab strip background.
@@ -62,12 +63,12 @@
      * @return The color for the tab container.
      */
     public static int getTabStripContainerColor(
-            Context context, boolean isIncognito, boolean foreground) {
+            Context context, boolean isIncognito, boolean foreground, boolean isReordering) {
         if (foreground) {
             if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
                 return ChromeColors.getDefaultThemeColor(context, isIncognito);
             } else if (TabManagementFieldTrial.isTabStripDetachedEnabled()) {
-                return getTabStripDetachedTabColor(context, isIncognito);
+                return getTabStripDetachedTabColor(context, isIncognito, isReordering);
             }
         } else {
             if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
@@ -88,9 +89,22 @@
      * @param isIncognito Whether the color is used for incognito mode.
      * @return The color for the detached tab container.
      */
-    private static int getTabStripDetachedTabColor(Context context, boolean isIncognito) {
+    private static int getTabStripDetachedTabColor(
+            Context context, boolean isIncognito, boolean isReordering) {
         assert TabManagementFieldTrial.isTabStripDetachedEnabled();
 
+        if (isReordering) {
+            if (isIncognito) {
+                return context.getColor(R.color.default_bg_color_dark_elev_4_baseline);
+            } else {
+                final int baseColor = getTabStripBackgroundColor(context, isIncognito);
+                final int overlayColor = SemanticColorUtils.getDefaultControlColorActive(context);
+
+                return ColorUtils.getColorWithOverlay(
+                        baseColor, overlayColor, DETACHED_TAB_OVERLAY_ALPHA_EDIT_MODE);
+            }
+        }
+
         if (isIncognito) return Color.BLACK;
 
         if (!ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index f96353b..5a38798 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2823,6 +2823,10 @@
         return mStartSurfaceSupplier.get();
     }
 
+    public TabSwitcher getTabSwitcherForTesting() {
+        return mTabSwitcherSupplier.get();
+    }
+
     private ComposedBrowserControlsVisibilityDelegate getAppBrowserControlsVisibilityDelegate() {
         // TODO(jinsukkim): Move this to RootUiCoordinator.
         return ((TabbedRootUiCoordinator) mRootUiCoordinator)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
index 834ed9a..089dcc1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
@@ -34,6 +34,7 @@
 import org.chromium.chrome.browser.flags.BooleanCachedFieldTrialParameter;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.flags.PostNativeFlag;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabUtils;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
@@ -58,6 +59,9 @@
  */
 @JNINamespace("android")
 public class TabContentManager {
+    private static PostNativeFlag sThumbnailCacheRefactor =
+            new PostNativeFlag(ChromeFeatureList.THUMBNAIL_CACHE_REFACTOR);
+
     // These are used for UMA logging, so append only. Please update the
     // GridTabSwitcherThumbnailFetchingResult enum in enums.xml if these change.
     @IntDef({ThumbnailFetchingResult.GOT_JPEG, ThumbnailFetchingResult.GOT_ETC1,
@@ -191,7 +195,8 @@
                 ChromeSwitches.APPROXIMATION_THUMBNAILS);
 
         boolean useApproximationThumbnails =
-                !DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext);
+                !DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext)
+                && !sThumbnailCacheRefactor.isEnabled();
         boolean saveJpegThumbnails = TabUiFeatureUtilities.isGridTabSwitcherEnabled(mContext);
 
         mNativeTabContentManager =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 6feeae3e..60fcc90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -918,11 +918,15 @@
 
             /**
              * Start divider should be visible when:
-             * 1. In reorder mode and currTab container is hidden
+             * 1. In reorder mode and currTab container is hidden and
+             * (a) prevTab has trailing margin (ie: currTab is start of group or an individual tab)
+             * OR (b) prevTab container is also hidden.
              * 2. Not in reorder mode and prevTab is not selected and currTab is not selected
              */
             boolean startDividerVisible =
-                    (mInReorderMode && currTab.getContainerOpacity() == TAB_OPACITY_HIDDEN)
+                    (mInReorderMode && currTab.getContainerOpacity() == TAB_OPACITY_HIDDEN
+                            && (prevTab.getTrailingMargin() > 0
+                                    || prevTab.getContainerOpacity() == TAB_OPACITY_HIDDEN))
                     || (!mInReorderMode && prevTab.getId() != selectedTabId
                             && currTab.getId() != selectedTabId);
             currTab.setStartDividerVisible(startDividerVisible);
@@ -2016,6 +2020,7 @@
         }
 
         // 7. Lift the TSR folio container off the toolbar.
+        mInteractingTab.setIsReordering(true);
         if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
             updateFolioTabAttachState(mInteractingTab, false, animationList);
         }
@@ -2060,6 +2065,7 @@
         }
 
         // 5. Reattach the TSR folio container to the toolbar.
+        mInteractingTab.setIsReordering(false);
         if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
             updateFolioTabAttachState(mInteractingTab, true, animationList);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
index 82d8671c..a388daa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -204,6 +204,7 @@
 
     private boolean mVisible = true;
     private boolean mIsDying;
+    private boolean mIsReordering;
     private boolean mCanShowCloseButton = true;
     private boolean mFolioAttached = true;
     private boolean mStartDividerVisible;
@@ -336,6 +337,14 @@
     }
 
     /**
+     * Marks if we are currently reordering this tab.
+     * @param isReordering Whether the tab is reordering.
+     */
+    public void setIsReordering(boolean isReordering) {
+        mIsReordering = isReordering;
+    }
+
+    /**
      * Marks if tab container is attached to the toolbar for the Tab Strip Redesign folio treatment.
      * @param folioAttached Whether the tab should be attached or not.
      */
@@ -385,7 +394,8 @@
         // TODO(https://crbug.com/1408276): Avoid calculating every time. Instead, store the tab's
         //  color and only re-determine when the color could have changed (i.e. on selection).
         if (ChromeFeatureList.sTabStripRedesign.isEnabled()) {
-            return TabUiThemeUtil.getTabStripContainerColor(mContext, mIncognito, foreground);
+            return TabUiThemeUtil.getTabStripContainerColor(
+                    mContext, mIncognito, foreground, mIsReordering);
         }
 
         if (foreground) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
index 661b500d..724e78c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -15,6 +15,7 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.history_clusters.HistoryClustersTabHelper;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
@@ -244,7 +245,8 @@
 
     @Override
     public boolean isSharingHubEnabled() {
-        return !mIsCustomTab;
+        return !(mIsCustomTab
+                || ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_SHEET_MIGRATION_ANDROID));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
index 9155fa0..023497a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
@@ -380,31 +380,29 @@
             return false;
         }
 
+        // TODO(shuyng): Add downgrade path support for smallestScreenWidthDp or displaySizeInInches
+        //  change.
         // If the smallest screen size in dp is below threshold, avoid default-enabling the setting.
         if (context.getResources().getConfiguration().smallestScreenWidthDp
                 < ChromeFeatureList.getFieldTrialParamByFeatureAsInt(feature,
                         PARAM_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH,
                         DEFAULT_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP)) {
-            updateNoLongerInCohort();
-            return false;
-        }
-
-        double screenSizeThreshold = ChromeFeatureList.getFieldTrialParamByFeatureAsDouble(feature,
-                PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
-        if (displaySizeInInches < screenSizeThreshold) {
-            updateNoLongerInCohort();
             return false;
         }
 
         SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
+
         boolean previouslyDefaultEnabled = sharedPreferencesManager.readBoolean(
                 ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING, false);
         boolean previouslyUpdatedByUser = sharedPreferencesManager.contains(
                 SingleCategorySettingsConstants
                         .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY);
 
-        boolean inCohort = !previouslyUpdatedByUser;
+        double screenSizeThreshold = ChromeFeatureList.getFieldTrialParamByFeatureAsDouble(feature,
+                PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
+                DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+
+        boolean inCohort = !previouslyUpdatedByUser && displaySizeInInches >= screenSizeThreshold;
         boolean wouldEnable = !previouslyDefaultEnabled && inCohort;
         if (wouldEnable) {
             // Store a SharedPreferences key to tag the device as qualified for the feature
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index d03d2eb..f9b7e47 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -782,11 +782,19 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             Layout activeLayout = getActiveLayout();
             Assert.assertEquals(LayoutType.TAB_SWITCHER, activeLayout.getLayoutType());
-            Assert.assertEquals(expectedTabListMode,
-                    mActivityTestRule.getActivity()
-                            .getStartSurface()
-                            .getGridTabListDelegate()
-                            .getListModeForTesting());
+            int tabListMode;
+            if (mIsStartSurfaceRefactorEnabled) {
+                tabListMode = mActivityTestRule.getActivity()
+                                      .getTabSwitcherForTesting()
+                                      .getTabListDelegate()
+                                      .getListModeForTesting();
+            } else {
+                tabListMode = mActivityTestRule.getActivity()
+                                      .getStartSurface()
+                                      .getGridTabListDelegate()
+                                      .getListModeForTesting();
+            }
+            Assert.assertEquals(expectedTabListMode, tabListMode);
         });
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/CookieSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/CookieSettingsTest.java
index b61d0ab..5729aefe 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/CookieSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/CookieSettingsTest.java
@@ -10,14 +10,22 @@
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import static org.chromium.ui.test.util.ViewUtils.onViewWaiting;
+
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.is;
 
+import static org.chromium.ui.test.util.ViewUtils.onViewWaiting;
+
 import android.os.Bundle;
 import android.view.View;
+
 import androidx.test.filters.SmallTest;
-import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
@@ -27,7 +35,9 @@
 import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.components.browser_ui.settings.SettingsFeatureList;
 import org.chromium.components.browser_ui.site_settings.FourStateCookieSettingsPreference;
 import org.chromium.components.browser_ui.site_settings.FourStateCookieSettingsPreference.CookieSettingsState;
 import org.chromium.components.browser_ui.site_settings.R;
@@ -36,14 +46,10 @@
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.RenderTestRule;
 import org.chromium.ui.test.util.RenderTestRule.Component;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 
-/**
- * Render tests for the Cookie page and subpages under Settings > Site Settings > Cookies.
- */
+import java.io.IOException;
+
+/** Render tests for the Cookie page and subpages under Settings > Site Settings > Cookies. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@@ -82,16 +88,34 @@
     @Test
     @SmallTest
     @Feature({"RenderTest"})
+    @EnableFeatures({ChromeFeatureList.PRIVACY_SANDBOX_FPS_UI,
+            SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID})
+    public void
+    testRenderCookieFPSSubpage_EnableHighlightManagedPrefDisclaimerAndroid() throws IOException {
+        showCookieFPSSubpage();
+        mRenderTestRule.render(
+                getRootView(R.string.website_settings_category_cookie_block_third_party_subtitle),
+                "settings_cookie_fps_subpage");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
     @EnableFeatures(ChromeFeatureList.PRIVACY_SANDBOX_FPS_UI)
-    public void testRenderCookieFPSSubpage() throws IOException {
+    @DisableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
+    public void testRenderCookieFPSSubpage_DisableHighlightManagedPrefDisclaimerAndroid()
+            throws IOException {
+        showCookieFPSSubpage();
+        mRenderTestRule.render(
+                getRootView(R.string.website_settings_category_cookie_block_third_party_subtitle),
+                "settings_cookie_fps_subpage_DisableHighlightManagedPrefDisclaimerAndroid");
+    }
+
+    private void showCookieFPSSubpage() {
         onView(withId(R.id.block_third_party_with_aux)).perform(click());
         onView(allOf(withId(R.id.expand_arrow),
                        isDescendantOfA(withId(R.id.block_third_party_with_aux))))
                 .perform(click());
-
-        mRenderTestRule.render(
-                getRootView(R.string.website_settings_category_cookie_block_third_party_subtitle),
-                "settings_cookie_fps_subpage");
     }
 
     private void setCookiesEnabled(final SettingsActivity settingsActivity, final boolean enabled) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index c093281..6a0ba41 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -146,9 +146,7 @@
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
-/**
- * Tests for everything under Settings > Site Settings.
- */
+/** Tests for everything under Settings > Site Settings. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1", "ignore-certificate-errors"})
@@ -294,9 +292,7 @@
         });
     }
 
-    /**
-     * Sets Allow Location Enabled to be true and make sure it is set correctly.
-     */
+    /** Sets Allow Location Enabled to be true and make sure it is set correctly. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -319,9 +315,7 @@
                 "/chrome/test/data/geolocation/geolocation_on_load.html", "", 0, false, true);
     }
 
-    /**
-     * Sets Allow Location Enabled to be false and make sure it is set correctly.
-     */
+    /** Sets Allow Location Enabled to be false and make sure it is set correctly. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -386,15 +380,12 @@
                 return WebsitePreferenceBridge.isCategoryEnabled(
                         getBrowserContextHandle(), ContentSettingsType.COOKIES);
             }
-
         });
     }
 
     private enum ToggleButtonState { EnabledUnchecked, EnabledChecked, Disabled }
 
-    /**
-     * Checks if the button representing the given state matches the managed expectation.
-     */
+    /** Checks if the button representing the given state matches the managed expectation. */
     private void checkFourStateCookieToggleButtonState(final SettingsActivity settingsActivity,
             final CookieSettingsState state, final ToggleButtonState toggleState) {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
@@ -490,9 +481,8 @@
     }
 
     /**
-     * Tests that the Preferences designated by keys in |expectedKeys|, and only
-     * these preferences, will be shown for the category specified by |type|. The
-     * order of Preferences matters.
+     * Tests that the Preferences designated by keys in |expectedKeys|, and only these preferences,
+     * will be shown for the category specified by |type|. The order of Preferences matters.
      */
     private void checkPreferencesForCategory(
             final @SiteSettingsCategory.Type int type, String[] expectedKeys) {
@@ -536,9 +526,7 @@
         checkPreferencesForCategory(type, enabledExpectedKeys);
     }
 
-    /**
-     * Allows cookies to be set and ensures that they are.
-     */
+    /** Allows cookies to be set and ensures that they are. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -564,9 +552,7 @@
                 "\"Foo=Bar\"", mPermissionRule.runJavaScriptCodeInCurrentTab("getCookie()"));
     }
 
-    /**
-     * Clicks on cookies radio buttons and verify the right FPS subpage is launched.
-     */
+    /** Clicks on cookies radio buttons and verify the right FPS subpage is launched. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -618,9 +604,7 @@
         });
     }
 
-    /**
-     * Blocks cookies from being set and ensures that no cookies can be set.
-     */
+    /** Blocks cookies from being set and ensures that no cookies can be set. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -644,9 +628,7 @@
         Assert.assertEquals("\"\"", mPermissionRule.runJavaScriptCodeInCurrentTab("getCookie()"));
     }
 
-    /**
-     * Blocks specific sites from setting cookies and ensures that no cookies can be set.
-     */
+    /** Blocks specific sites from setting cookies and ensures that no cookies can be set. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -683,9 +665,7 @@
         Assert.assertEquals("\"\"", mPermissionRule.runJavaScriptCodeInCurrentTab("getCookie()"));
     }
 
-    /**
-     * Blocks specific sites from setting cookies and ensures that no cookies can be set.
-     */
+    /** Blocks specific sites from setting cookies and ensures that no cookies can be set. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -719,9 +699,7 @@
         Assert.assertEquals("\"\"", mPermissionRule.runJavaScriptCodeInCurrentTab("getCookie()"));
     }
 
-    /**
-     * Set a cookie and check that it is removed when a site is cleared.
-     */
+    /** Set a cookie and check that it is removed when a site is cleared. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -786,9 +764,7 @@
                 "\"Foo=Bar\"", mPermissionRule.runJavaScriptCodeInCurrentTab("getCookie()"));
     }
 
-    /**
-     * Set cookies for domains and check that they are removed when a site is cleared.
-     */
+    /** Set cookies for domains and check that they are removed when a site is cleared. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -857,11 +833,11 @@
     }
 
     /**
-     * Set the cookie content setting to allow through policy, disable incognito
-     * mode and ensure the correct radio buttons are enabled. This test is executed with experiment
-     * {@link SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID} either enabled or
-     * disabled, and the only expected difference in both cases is the UI that shows the disclaimer
-     * that the preference is managed.
+     * Set the cookie content setting to allow through policy, disable incognito mode and ensure the
+     * correct radio buttons are enabled. This test is executed with experiment {@link
+     * SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID} either enabled or disabled,
+     * and the only expected difference in both cases is the UI that shows the disclaimer that the
+     * preference is managed.
      */
     @Test
     @SmallTest
@@ -1217,9 +1193,7 @@
         settingsActivity.finish();
     }
 
-    /**
-     * Sets Allow Popups Enabled to be false and make sure it is set correctly.
-     */
+    /** Sets Allow Popups Enabled to be false and make sure it is set correctly. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -1236,9 +1210,7 @@
         Assert.assertEquals(1, getTabCount());
     }
 
-    /**
-     * Sets Allow Popups Enabled to be true and make sure it is set correctly.
-     */
+    /** Sets Allow Popups Enabled to be true and make sure it is set correctly. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -1255,9 +1227,7 @@
         Assert.assertEquals(2, getTabCount());
     }
 
-    /**
-     * Test that showing the Site Settings menu doesn't crash (crbug.com/610576).
-     */
+    /** Test that showing the Site Settings menu doesn't crash (crbug.com/610576). */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -1266,9 +1236,7 @@
         settingsActivity.finish();
     }
 
-    /**
-     * Test that showing the Site Settings menu contains only the "Cookies" row.
-     */
+    /** Test that showing the Site Settings menu contains only the "Cookies" row. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -1300,9 +1268,8 @@
     }
 
     /**
-     * Tests that only expected Preferences are shown for a category. This
-     * santiy checks the number of categories only. Each category has its own
-     * individual test below.
+     * Tests that only expected Preferences are shown for a category. This santiy checks the number
+     * of categories only. Each category has its own individual test below.
      */
     @Test
     @SmallTest
@@ -1638,7 +1605,8 @@
         testExpectedPreferences(
                 SiteSettingsCategory.Type.REQUEST_DESKTOP_SITE, BINARY_TOGGLE, BINARY_TOGGLE);
         Assert.assertTrue(
-                "SharedPreference USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY should be updated.",
+                "SharedPreference USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY should be"
+                        + " updated.",
                 ContextUtils.getAppSharedPreferences().contains(
                         SingleCategorySettingsConstants
                                 .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY));
@@ -1652,7 +1620,8 @@
         testExpectedPreferences(SiteSettingsCategory.Type.REQUEST_DESKTOP_SITE,
                 BINARY_TOGGLE_WITH_EXCEPTION, BINARY_TOGGLE_WITH_EXCEPTION);
         Assert.assertTrue(
-                "SharedPreference USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY should be updated.",
+                "SharedPreference USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY should be"
+                        + " updated.",
                 ContextUtils.getAppSharedPreferences().contains(
                         SingleCategorySettingsConstants
                                 .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY));
@@ -1706,9 +1675,7 @@
                 SiteSettingsCategory.Type.VIRTUAL_REALITY, BINARY_TOGGLE, BINARY_TOGGLE);
     }
 
-    /**
-     * Tests system NFC support in Preferences.
-     */
+    /** Tests system NFC support in Preferences. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -1720,8 +1687,8 @@
     }
 
     /**
-     * Tests that {@link SingleWebsiteSettings#resetSite} doesn't crash
-     * (see e.g. the crash on host names in issue 600232).
+     * Tests that {@link SingleWebsiteSettings#resetSite} doesn't crash (see e.g. the crash on host
+     * names in issue 600232).
      */
     @Test
     @SmallTest
@@ -1733,6 +1700,7 @@
 
     /**
      * Sets Allow Camera Enabled to be false and make sure it is set correctly.
+     *
      * @throws Exception
      */
     @Test
@@ -2303,8 +2271,8 @@
     @Test
     @MediumTest
     @Feature({"Preferences"})
-    @DisableIf.Build(message = "https://crbug.com/1269556",
-        sdk_is_greater_than = Build.VERSION_CODES.P)
+    @DisableIf.
+    Build(message = "https://crbug.com/1269556", sdk_is_greater_than = Build.VERSION_CODES.P)
     @DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/1234530
     public void testProtectedContentAllowThenBlock() throws Exception {
         initializeUpdateWaiter(true /* expectGranted */);
@@ -2435,21 +2403,33 @@
 
     @Test
     @SmallTest
+    @EnableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
     @Feature({"RenderTest"})
-    public void testRenderLocationPage() throws Exception {
+    public void testRenderLocationPage_EnableHighlightManagedPrefDisclaimerAndroid()
+            throws Exception {
         renderCategoryPage(
                 SiteSettingsCategory.Type.DEVICE_LOCATION, "site_settings_location_page");
     }
 
     @Test
     @SmallTest
+    @DisableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
+    @Feature({"RenderTest"})
+    public void testRenderLocationPage_DisableHighlightManagedPrefDisclaimerAndroid()
+            throws Exception {
+        renderCategoryPage(SiteSettingsCategory.Type.DEVICE_LOCATION,
+                "site_settings_location_page_DisableHighlightManagedPrefDisclaimerAndroid");
+    }
+
+    @Test
+    @SmallTest
     @Feature({"RenderTest"})
     public void testRenderProtectedMediaPage() throws Exception {
         renderCategoryPage(
                 SiteSettingsCategory.Type.PROTECTED_MEDIA, "site_settings_protected_media_page");
     }
 
-    /** Test case for checking that settings with binary toggles are disabled by policy.*/
+    /** Test case for checking that settings with binary toggles are disabled by policy. */
     @Test
     @SmallTest
     @Feature({"Preferences"})
@@ -2480,8 +2460,8 @@
     }
 
     /**
-     * Allows third party cookies for a website, and tests that the UI shows a managed preference
-     * in the allowed group. Checks that it shows the toast when the preference is clicked.
+     * Allows third party cookies for a website, and tests that the UI shows a managed preference in
+     * the allowed group. Checks that it shows the toast when the preference is clicked.
      */
     @Test
     @SmallTest
@@ -2506,8 +2486,8 @@
     }
 
     /**
-     * Blocks third party cookies for a website, and tests that the UI shows a managed preference
-     * in the blocked group. Checks that it shows toast when the preference is clicked.
+     * Blocks third party cookies for a website, and tests that the UI shows a managed preference in
+     * the blocked group. Checks that it shows toast when the preference is clicked.
      */
     @Test
     @SmallTest
@@ -2622,7 +2602,7 @@
         }
     }
 
-    /** Test case for site settings with a global toggle.  */
+    /** Test case for site settings with a global toggle. */
     static class TwoStatePermissionTestCase extends PermissionTestCase {
         TwoStatePermissionTestCase(
                 String testName, int siteSettingsType, int contentSettingsType, boolean enabled) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
index e4bdbfc..3aaeab3d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -30,6 +30,7 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
@@ -47,6 +48,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.chrome.test.util.browser.signin.SigninTestRule;
+import org.chromium.components.browser_ui.settings.SettingsFeatureList;
 import org.chromium.components.signin.base.AccountInfo;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
@@ -55,6 +57,7 @@
 /** Tests {@link AccountManagementFragment}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@Batch(Batch.PER_CLASS)
 public class AccountManagementFragmentTest {
     private static final String CHILD_ACCOUNT_NAME =
             AccountManagerTestRule.generateChildEmail("account@gmail.com");
@@ -90,6 +93,7 @@
     @Feature("RenderTest")
     @DisableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS,
             ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL})
+    @EnableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
     public void
     testAccountManagementFragmentView() throws Exception {
         mSigninTestRule.addTestAccountThenSigninAndEnableSync();
@@ -102,8 +106,10 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS})
-    public void testAccountManagementFragmentViewWithAddEduAccountEnabled() throws Exception {
+    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS,
+            SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID})
+    public void
+    testAccountManagementFragmentViewWithAddEduAccountEnabled() throws Exception {
         mSigninTestRule.addTestAccountThenSigninAndEnableSync();
         mSettingsActivityTestRule.startSettingsActivity();
         View view = mSettingsActivityTestRule.getFragment().getView();
@@ -115,9 +121,10 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures({ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL})
-    public void testAccountManagementFragmentViewWithHideNonDisplayableAccountEmailEnabled()
-            throws Exception {
+    @EnableFeatures({ChromeFeatureList.HIDE_NON_DISPLAYABLE_ACCOUNT_EMAIL,
+            SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID})
+    public void
+    testAccountManagementFragmentViewWithHideNonDisplayableAccountEmailEnabled() throws Exception {
         mSigninTestRule.addTestAccountThenSigninAndEnableSync();
         mSettingsActivityTestRule.startSettingsActivity();
         View view = mSettingsActivityTestRule.getFragment().getView();
@@ -128,6 +135,7 @@
 
     @Test
     @MediumTest
+    @EnableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
     @Feature("RenderTest")
     public void testSignedInAccountShownOnTop() throws Exception {
         mSigninTestRule.addAccount("testSecondary@gmail.com");
@@ -213,9 +221,10 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS})
-    public void testAccountManagementViewForChildAccountWithAddEduAccountEnabled()
-            throws Exception {
+    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS,
+            SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID})
+    public void
+    testAccountManagementViewForChildAccountWithAddEduAccountEnabled() throws Exception {
         mSigninTestRule.addAccountAndWaitForSeeding(CHILD_ACCOUNT_NAME);
         final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
                 Profile::getLastUsedRegularProfile);
@@ -259,7 +268,8 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS})
+    @EnableFeatures({ChromeFeatureList.ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS,
+            SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID})
     public void
     testAccountManagementViewForChildAccountWithSecondaryEduAccountAndAddEduAccountEnabled()
             throws Exception {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
index 641a1de..941d291b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -25,9 +25,9 @@
 import org.chromium.base.test.params.ParameterProvider;
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.blink.mojom.DisplayMode;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -51,7 +51,6 @@
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.device.mojom.ScreenOrientationLockType;
 import org.chromium.net.test.EmbeddedTestServer;
-import org.chromium.net.test.EmbeddedTestServerRule;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -66,7 +65,7 @@
  * Tests WebApkUpdateManager. This class contains tests which cannot be done as JUnit tests.
  */
 @RunWith(ParameterizedRunner.class)
-@DoNotBatch(reason = "The update pipeline runs once per startup.")
+@Batch(Batch.PER_CLASS)
 @ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeSwitches.CHECK_FOR_WEB_MANIFEST_UPDATE_ON_STARTUP})
@@ -75,9 +74,6 @@
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
-    @Rule
-    public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
-
     /**
      * The parameters for the App Identity tests (for which flag is enabled).
      */
@@ -245,7 +241,7 @@
         mActivityTestRule.startMainActivityOnBlankPage();
         mActivity = mActivityTestRule.getActivity();
         mTab = mActivity.getActivityTab();
-        mTestServer = mTestServerRule.getServer();
+        mTestServer = mActivityTestRule.getTestServer();
 
         mTestValues = new FeatureList.TestValues();
         FeatureList.setTestValues(mTestValues);
@@ -471,6 +467,8 @@
             boolean allowShellVersion, boolean changeName, boolean changeShortName,
             boolean changeIcon) throws Exception {
         mIconOrNameUpdateDialogShown = false;
+        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID);
+        storage.updateLastWebApkUpdateHashAccepted("");
 
         CreationData creationData = defaultCreationData();
         creationData.startUrl =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
index 7b01586..d460c3d2 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -514,6 +514,35 @@
         // Setup with 5 tabs. Select 2nd tab.
         initializeTest(false, false, true, 1, 5);
         mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP);
+
+        // Start reorder mode at 2nd tab
+        mStripLayoutHelper.startReorderModeAtIndexForTesting(1);
+        // Trigger update to set divider values.
+        mStripLayoutHelper.updateLayout(TIMESTAMP);
+
+        StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabs();
+        // Verify only 4th and 5th tab's start divider is visible.
+        assertFalse(
+                "First start divider should always be hidden.", tabs[0].isStartDividerVisible());
+        assertFalse("Start divider should be hidden.", tabs[1].isStartDividerVisible());
+        assertFalse("Start divider should be hidden.", tabs[2].isStartDividerVisible());
+        assertTrue("Start divider should be hidden.", tabs[3].isStartDividerVisible());
+        assertTrue("Start divider should be visible.", tabs[4].isStartDividerVisible());
+
+        // Verify end divider visible only for 5th tab.
+        assertFalse("End divider should be hidden.", tabs[0].isEndDividerVisible());
+        assertFalse("End divider should be hidden.", tabs[1].isEndDividerVisible());
+        assertFalse("End divider should be hidden.", tabs[2].isEndDividerVisible());
+        assertFalse("End divider should be hidden.", tabs[3].isEndDividerVisible());
+        assertTrue("End divider should be visible.", tabs[4].isEndDividerVisible());
+    }
+
+    @Test
+    @Feature("Tab Strip Redesign")
+    public void testUpdateDividers_InReorderModeWithTabGroups() {
+        // Setup with 5 tabs. Select 2nd tab.
+        initializeTest(false, false, true, 1, 5);
+        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP);
         // group 2nd and 3rd tab.
         groupTabs(1, 3);
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
index 76c311f..39fd8fd7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
@@ -779,78 +779,6 @@
     }
 
     @Test
-    public void testMaybeDisableGlobalSetting_FinchParamChanged_ScreenWidthDp() {
-        // Default-enable the global setting.
-        Map<String, String> params = new HashMap<>();
-        params.put(
-                RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH, "600");
-        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
-        RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
-                RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                mProfile, mActivity);
-
-        // Update finch param and initiate downgrade.
-        params.put(
-                RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH, "800");
-        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
-        RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
-                RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                mProfile, mActivity);
-        enableFeatureWithParams(
-                ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS_DOWNGRADE, null, true);
-        boolean didDisable = RequestDesktopUtils.maybeDisableGlobalSetting(mProfile);
-
-        Assert.assertTrue(
-                "Desktop site global setting should be disabled on downgrade.", didDisable);
-        Assert.assertEquals("Desktop site content setting should be set correctly.",
-                ContentSettingValues.BLOCK, mRdsDefaultValue);
-        Assert.assertFalse(
-                "SharedPreference DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING should be removed.",
-                mSharedPreferencesManager.contains(
-                        ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING));
-        Assert.assertFalse(
-                "SharedPreference DEFAULT_ENABLE_DESKTOP_SITE_GLOBAL_SETTING_COHORT should be removed.",
-                mSharedPreferencesManager.contains(
-                        ChromePreferenceKeys.DEFAULT_ENABLE_DESKTOP_SITE_GLOBAL_SETTING_COHORT));
-    }
-
-    @Test
-    public void testMaybeDisableGlobalSetting_FinchParamChanged_ScreenSizeInches() {
-        // Default-enable the global setting.
-        Map<String, String> params = new HashMap<>();
-        params.put(
-                RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                "10.0");
-        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
-        RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
-                /*displaySizeInInches*/ 10.5, mProfile, mActivity);
-
-        // Update finch param and initiate downgrade.
-        params.put(
-                RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                "11.0");
-        enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true);
-        RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
-                /*displaySizeInInches*/ 10.5, mProfile, mActivity);
-        enableFeatureWithParams(
-                ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS_DOWNGRADE, null, true);
-        boolean didDisable = RequestDesktopUtils.maybeDisableGlobalSetting(mProfile);
-
-        Assert.assertTrue(
-                "Desktop site global setting should be disabled on downgrade.", didDisable);
-        Assert.assertEquals("Desktop site content setting should be set correctly.",
-                ContentSettingValues.BLOCK, mRdsDefaultValue);
-        Assert.assertFalse(
-                "SharedPreference DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING should be removed.",
-                mSharedPreferencesManager.contains(
-                        ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING));
-        Assert.assertFalse(
-                "SharedPreference DEFAULT_ENABLE_DESKTOP_SITE_GLOBAL_SETTING_COHORT should be removed.",
-                mSharedPreferencesManager.contains(
-                        ChromePreferenceKeys.DEFAULT_ENABLE_DESKTOP_SITE_GLOBAL_SETTING_COHORT));
-    }
-
-    @Test
     public void testShouldShowGlobalSettingOptInMessage_ExperimentControlGroup() {
         when(mTracker.wouldTriggerHelpUI(FeatureConstants.REQUEST_DESKTOP_SITE_OPT_IN_FEATURE))
                 .thenReturn(true);
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 130c4e3c..b598f96 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-112.0.5579.0_rc-r2-merged.afdo.bz2
+chromeos-chrome-arm-112.0.5583.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 20c8405..a1fc6f7 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-112.0.5579.0_rc-r2-merged.afdo.bz2
+chromeos-chrome-amd64-112.0.5583.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index 0fc1394..20bf39d6 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -388,6 +388,9 @@
   <message name="IDS_OS_SETTINGS_TAG_LOCK_SCREEN_PIN_OR_PASSWORD_ALT1" desc="Text for search result item which, when clicked, navigates the user to lock screen settings, with an option to determine whether the device can be unlocked with a PIN or a password. Alternate phrase for: 'Screen lock PIN'">
     Screen lock password
   </message>
+  <message name="IDS_OS_SETTINGS_TAG_MANAGE_OTHER_PEOPLE_PAGE" desc="Text for search result item which, when clicked, navigates the user to manage other user account privileges.">
+    Manage other people
+  </message>
   <message name="IDS_OS_SETTINGS_TAG_GUEST_BROWSING" desc="Text for search result item which, when clicked, navigates the user to account settings, with a toggle to enable/disable guest browsing.">
     Guest browsing
   </message>
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MANAGE_OTHER_PEOPLE_PAGE.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MANAGE_OTHER_PEOPLE_PAGE.png.sha1
new file mode 100644
index 0000000..77dc2839
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MANAGE_OTHER_PEOPLE_PAGE.png.sha1
@@ -0,0 +1 @@
+76337d76bb76ac05d312e72f8eef098f711a4b5d
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b9ab678..278d2be 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -642,36 +642,6 @@
 
 #endif  // BUILDFLAG(IS_ANDROID)
 
-const FeatureEntry::FeatureParam
-    kAutofillSaveCardUiExperimentEnableCurrentWithUserAvatarAndEmail[] = {
-        {"autofill_save_card_ui_experiment_selector_in_number", "3"},
-};
-
-const FeatureEntry::FeatureParam
-    kAutofillSaveCardUiExperimentEnableEncryptedAndSecure[] = {
-        {"autofill_save_card_ui_experiment_selector_in_number", "2"},
-};
-
-const FeatureEntry::FeatureParam
-    kAutofillSaveCardUiExperimentEnableFasterAndProtected[] = {
-        {"autofill_save_card_ui_experiment_selector_in_number", "1"},
-};
-
-const FeatureEntry::FeatureVariation kAutofillSaveCardUiExperimentOptions[] = {
-    {flag_descriptions::kAutofillSaveCardUiExperimentFasterAndProtected,
-     kAutofillSaveCardUiExperimentEnableFasterAndProtected,
-     std::size(kAutofillSaveCardUiExperimentEnableFasterAndProtected), nullptr},
-    {flag_descriptions::kAutofillSaveCardUiExperimentEncryptedAndSecure,
-     kAutofillSaveCardUiExperimentEnableEncryptedAndSecure,
-     std::size(kAutofillSaveCardUiExperimentEnableEncryptedAndSecure), nullptr},
-    {flag_descriptions::
-         kAutofillSaveCardUiExperimentCurrentWithUserAvatarAndEmail,
-     kAutofillSaveCardUiExperimentEnableCurrentWithUserAvatarAndEmail,
-     std::size(
-         kAutofillSaveCardUiExperimentEnableCurrentWithUserAvatarAndEmail),
-     nullptr},
-};
-
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
 const FeatureEntry::FeatureParam kForceDark_SimpleHsl[] = {
     {"inversion_method", "hsl_based"},
@@ -4496,6 +4466,11 @@
      flag_descriptions::kInfobarScrollOptimizationName,
      flag_descriptions::kInfobarScrollOptimizationDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kInfobarScrollOptimization)},
+    {"share-sheet-migration-android",
+     flag_descriptions::kShareSheetMigrationAndroidName,
+     flag_descriptions::kShareSheetMigrationAndroidDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kShareSheetMigrationAndroid)},
+
 #endif  // BUILDFLAG(IS_ANDROID)
     {"disallow-doc-written-script-loads",
      flag_descriptions::kDisallowDocWrittenScriptsUiName,
@@ -8747,14 +8722,6 @@
          permissions::features::kRecordPermissionExpirationTimestamps)},
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-    {"autofill-enable-upstream-save-card-offer-ui-experiment",
-     flag_descriptions::kAutofillSaveCardUiExperimentName,
-     flag_descriptions::kAutofillSaveCardUiExperimentDescription, kOsDesktop,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         autofill::features::kAutofillSaveCardUiExperiment,
-         kAutofillSaveCardUiExperimentOptions,
-         "AutofillSaveCardUiExperiment")},
-
 #if BUILDFLAG(IS_ANDROID)
     {"network-service-in-process",
      flag_descriptions::kNetworkServiceInProcessName,
@@ -9308,6 +9275,12 @@
      flag_descriptions::kWebViewTagMPArchBehaviorDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(extensions_features::kWebviewTagMPArchBehavior)},
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+        //
+#if BUILDFLAG(IS_ANDROID)
+    {"thumbnail-cache-refactor", flag_descriptions::kThumbnailCacheRefactorName,
+     flag_descriptions::kThumbnailCacheRefactorDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kThumbnailCacheRefactor)},
+#endif  // BUILDFLAG(IS_ANDROID)
 
     {"autofill-enable-page-load-metadata-integration",
      flag_descriptions::kAutofillEnablePageLoadMetadataIntegrationName,
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
index 4be657f7..b0199a95 100644
--- a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
@@ -81,6 +81,7 @@
     private static final String SHARED_PREF_THEME = "Theme";
     private static final String SHARED_PREF_URL_HIDING = "UrlHiding";
     private static final String SHARED_PREF_FORCE_ENGAGEMENT_SIGNALS = "ForceEngagementSignals";
+    private static final String SHARED_PREF_SIDE_SHEET_MAX_BUTTON = "SideSheetMaxButton";
     private static final int CLOSE_ICON_X = 0;
     private static final int CLOSE_ICON_BACK = 1;
     private static final int CLOSE_ICON_CHECK = 2;
@@ -88,6 +89,11 @@
     private static final int CHECKED = 1;
     private static final int ACTIVITY_HEIGHT_FIXED = 2;
     private static final int BACKGROUND_INTERACT_OFF_VALUE = 2;
+
+    /** Extra that enables the maximization button on the side sheet Custom Tab toolbar. */
+    public static final String EXTRA_ACTIVITY_SIDE_SHEET_ENABLE_MAXIMIZATION =
+            "androix.browser.customtabs.extra.EXTRA_ACTIVITY_SIDE_SHEET_ENABLE_MAXIMIZATION";
+
     /**
      * Minimal height the bottom sheet CCT should show is half of the display height.
      */
@@ -123,6 +129,7 @@
     private CheckBox mUrlHidingCheckbox;
     private CheckBox mBackgroundInteractCheckbox;
     private CheckBox mForceEngagementSignalsCheckbox;
+    private CheckBox mSideSheetMaxButtonCheckbox;
     private TextView mPcctBreakpointLabel;
     private SeekBar mPcctBreakpointSlider;
     private TextView mPcctInitialHeightLabel;
@@ -409,6 +416,9 @@
         mForceEngagementSignalsCheckbox = findViewById(R.id.force_engagement_signals_checkbox);
         mForceEngagementSignalsCheckbox.setChecked(
                 mSharedPref.getInt(SHARED_PREF_FORCE_ENGAGEMENT_SIGNALS, CHECKED) == CHECKED);
+        mSideSheetMaxButtonCheckbox = findViewById(R.id.side_sheet_max_button_checkbox);
+        mSideSheetMaxButtonCheckbox.setChecked(
+                mSharedPref.getInt(SHARED_PREF_SIDE_SHEET_MAX_BUTTON, CHECKED) == CHECKED);
     }
 
     private void initializeCctSpinner() {
@@ -699,6 +709,10 @@
                 customTabsIntent.intent.putExtra(
                         "androidx.browser.customtabs.extra.ACTIVITY_SIDE_SHEET_BREAKPOINT_DP",
                         pcctBreakpointDp);
+                if (mSideSheetMaxButtonCheckbox.isChecked()) {
+                    customTabsIntent.intent.putExtra(
+                            EXTRA_ACTIVITY_SIDE_SHEET_ENABLE_MAXIMIZATION, true);
+                }
                 if (!mPcctHeightResizableCheckbox.isChecked()) {
                     customTabsIntent.intent.putExtra(
                             "androidx.browser.customtabs.extra.ACTIVITY_HEIGHT_RESIZE_BEHAVIOR",
@@ -745,6 +759,8 @@
             editor.putInt(SHARED_PREF_CLOSE_POSITION, closeButtonPosition);
             editor.putInt(SHARED_PREF_HEIGHT_RESIZABLE,
                     mPcctHeightResizableCheckbox.isChecked() ? CHECKED : UNCHECKED);
+            editor.putInt(SHARED_PREF_SIDE_SHEET_MAX_BUTTON,
+                    mSideSheetMaxButtonCheckbox.isChecked() ? CHECKED : UNCHECKED);
             editor.apply();
         }
     }
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
index a32b619c..000f700 100644
--- a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
@@ -478,5 +478,12 @@
             android:layout_height="wrap_content"
             android:checked = "true"
             android:text="@string/background_interact_text" />
+
+        <CheckBox
+            android:id="@+id/side_sheet_max_button_checkbox"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked = "true"
+            android:text="@string/side_sheet_max_button_text" />
     </LinearLayout>
 </ScrollView>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
index 78f3265..d70c980 100644
--- a/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
@@ -55,5 +55,5 @@
     <string name="theme_button_dark">Dark</string>
     <string name="cct_type">CCT Type:</string>
     <string name="background_interact_text">Interact with Background App</string>
-
+    <string name="side_sheet_max_button_text">Add Max Button(SideSheet only)</string>
 </resources>
diff --git a/chrome/browser/apps/app_preload_service/app_preload_service.cc b/chrome/browser/apps/app_preload_service/app_preload_service.cc
index 2b077fa..d18d6909 100644
--- a/chrome/browser/apps/app_preload_service/app_preload_service.cc
+++ b/chrome/browser/apps/app_preload_service/app_preload_service.cc
@@ -12,7 +12,10 @@
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/ranges/algorithm.h"
+#include "base/strings/strcat.h"
+#include "base/time/time.h"
 #include "chrome/browser/apps/app_preload_service/app_preload_service_factory.h"
 #include "chrome/browser/apps/app_preload_service/device_info_manager.h"
 #include "chrome/browser/apps/app_preload_service/preload_app_definition.h"
@@ -43,6 +46,11 @@
 static constexpr char kFirstLoginFlowCompletedKey[] =
     "first_login_flow_completed";
 
+static constexpr char kFirstLoginFlowHistogramSuccessName[] =
+    "AppPreloadService.FirstLoginFlowTime.Success";
+static constexpr char kFirstLoginFlowHistogramFailureName[] =
+    "AppPreloadService.FirstLoginFlowTime.Failure";
+
 }  // namespace
 
 namespace apps {
@@ -84,6 +92,8 @@
 }
 
 void AppPreloadService::StartFirstLoginFlow() {
+  auto start_time = base::TimeTicks::Now();
+
   // Preloads currently run for new users only. The "completed" pref is only set
   // when preloads finish successfully, so preloads will be retried if they have
   // been "started" but never "completed".
@@ -101,22 +111,24 @@
       base::FeatureList::IsEnabled(kAppPreloadServiceForceRun)) {
     device_info_manager_->GetDeviceInfo(
         base::BindOnce(&AppPreloadService::StartAppInstallationForFirstLogin,
-                       weak_ptr_factory_.GetWeakPtr()));
+                       weak_ptr_factory_.GetWeakPtr(), start_time));
   }
 }
 
 void AppPreloadService::StartAppInstallationForFirstLogin(
+    base::TimeTicks start_time,
     DeviceInfo device_info) {
   server_connector_->GetAppsForFirstLogin(
       device_info, profile_->GetURLLoaderFactory(),
       base::BindOnce(&AppPreloadService::OnGetAppsForFirstLoginCompleted,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr(), start_time));
 }
 
 void AppPreloadService::OnGetAppsForFirstLoginCompleted(
+    base::TimeTicks start_time,
     absl::optional<std::vector<PreloadAppDefinition>> apps) {
   if (!apps.has_value()) {
-    OnFirstLoginFlowComplete(/*success=*/false);
+    OnFirstLoginFlowComplete(/*success=*/false, start_time);
     return;
   }
 
@@ -130,7 +142,7 @@
   const auto install_barrier_callback_ = base::BarrierCallback<bool>(
       apps.value().size(),
       base::BindOnce(&AppPreloadService::OnAllAppInstallationFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr(), start_time));
 
   for (const PreloadAppDefinition& app : apps.value()) {
     web_app_installer_->InstallApp(app, install_barrier_callback_);
@@ -138,17 +150,23 @@
 }
 
 void AppPreloadService::OnAllAppInstallationFinished(
+    base::TimeTicks start_time,
     const std::vector<bool>& results) {
   OnFirstLoginFlowComplete(
-      base::ranges::all_of(results, [](bool b) { return b; }));
+      base::ranges::all_of(results, [](bool b) { return b; }), start_time);
 }
 
-void AppPreloadService::OnFirstLoginFlowComplete(bool success) {
+void AppPreloadService::OnFirstLoginFlowComplete(bool success,
+                                                 base::TimeTicks start_time) {
   if (success) {
     ScopedDictPrefUpdate(profile_->GetPrefs(), prefs::kApsStateManager)
         ->Set(kFirstLoginFlowCompletedKey, true);
   }
 
+  base::UmaHistogramMediumTimes(success ? kFirstLoginFlowHistogramSuccessName
+                                        : kFirstLoginFlowHistogramFailureName,
+                                base::TimeTicks::Now() - start_time);
+
   if (installation_complete_callback_) {
     std::move(installation_complete_callback_).Run(success);
   }
diff --git a/chrome/browser/apps/app_preload_service/app_preload_service.h b/chrome/browser/apps/app_preload_service/app_preload_service.h
index 7477c3a..0b33f2a 100644
--- a/chrome/browser/apps/app_preload_service/app_preload_service.h
+++ b/chrome/browser/apps/app_preload_service/app_preload_service.h
@@ -18,6 +18,10 @@
 
 class Profile;
 
+namespace base {
+class TimeTicks;
+}  // namespace base
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }  // namespace user_prefs
@@ -66,15 +70,18 @@
   // service, processes the list and installs the app list. This call should
   // only be used the first time a profile is created on the device as this call
   // installs a set of default and OEM apps.
-  void StartAppInstallationForFirstLogin(DeviceInfo device_info);
+  void StartAppInstallationForFirstLogin(base::TimeTicks start_time,
+                                         DeviceInfo device_info);
   // Processes the list of apps retrieved by the server connector.
   void OnGetAppsForFirstLoginCompleted(
+      base::TimeTicks start_time,
       absl::optional<std::vector<PreloadAppDefinition>> apps);
-  void OnAllAppInstallationFinished(const std::vector<bool>& results);
+  void OnAllAppInstallationFinished(base::TimeTicks start_time,
+                                    const std::vector<bool>& results);
   // Called when the installation flow started by
   // `StartAppInstallationForFirstLogin` is complete, with `success` indicating
   // whether the overall flow was successful.
-  void OnFirstLoginFlowComplete(bool success);
+  void OnFirstLoginFlowComplete(bool success, base::TimeTicks start_time);
 
   bool ShouldInstallApp(const PreloadAppDefinition& app);
 
diff --git a/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc b/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc
index 8743a86..cf969499 100644
--- a/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc
+++ b/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "chrome/browser/apps/app_preload_service/app_preload_service.h"
@@ -30,7 +31,12 @@
 
 namespace {
 constexpr char kDefaultManifestUrl[] = "/manifest.json";
-}
+
+static constexpr char kFirstLoginFlowHistogramSuccessName[] =
+    "AppPreloadService.FirstLoginFlowTime.Success";
+static constexpr char kFirstLoginFlowHistogramFailureName[] =
+    "AppPreloadService.FirstLoginFlowTime.Failure";
+}  // namespace
 
 class AppPreloadServiceBrowserTest : public InProcessBrowserTest {
  public:
@@ -123,6 +129,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(AppPreloadServiceBrowserTest, OemWebAppInstall) {
+  base::HistogramTester histograms;
   proto::AppProvisioningListAppsResponse response;
   auto* app = response.add_apps_to_install();
   app->set_name("Example App");
@@ -159,6 +166,9 @@
         EXPECT_EQ(update.PublisherId(), "https://www.example.com/index.html");
       });
   ASSERT_TRUE(found);
+
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramSuccessName, 1);
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramFailureName, 0);
 }
 
 IN_PROC_BROWSER_TEST_F(AppPreloadServiceBrowserTest, IgnoreDefaultAppInstall) {
@@ -303,6 +313,7 @@
 // Verifies that failed installations are retried on the next login flow, and
 // already installed apps are ignored.
 IN_PROC_BROWSER_TEST_F(AppPreloadServiceBrowserTest, RetryFailedApps) {
+  base::HistogramTester histograms;
   constexpr char kOriginalManifestUrl1[] = "https://www.foo.com/manifest.json";
   constexpr char kOriginalManifestUrl2[] = "https://www.bar.com/manifest.json";
 
@@ -350,6 +361,9 @@
   service->StartFirstLoginFlowForTesting(result.GetCallback());
   ASSERT_FALSE(result.Get());
 
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramSuccessName, 0);
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramFailureName, 1);
+
   // bar.json should be retried, and will now succeed. foo.json is skipped
   // (ignoring the error it would give), and so the whole flow is successful.
   SetManifestResponse("/manifest/foo.json", "");
@@ -369,6 +383,9 @@
       web_app::GenerateAppId(absl::nullopt, GURL("https://www.bar.com/"));
   found = app_registry_cache().ForOneApp(app_id2, [](const AppUpdate&) {});
   ASSERT_TRUE(found);
+
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramSuccessName, 1);
+  histograms.ExpectTotalCount(kFirstLoginFlowHistogramFailureName, 1);
 }
 
 }  // namespace apps
diff --git a/chrome/browser/ash/bluetooth/debug_logs_manager.cc b/chrome/browser/ash/bluetooth/debug_logs_manager.cc
index 92ca8e1e..8befe1e 100644
--- a/chrome/browser/ash/bluetooth/debug_logs_manager.cc
+++ b/chrome/browser/ash/bluetooth/debug_logs_manager.cc
@@ -116,11 +116,13 @@
   VLOG(1) << (enable ? "Enabling" : "Disabling") << " bluetooth verbose logs";
 
   if (floss::features::IsFlossEnabled()) {
-    floss::FlossDBusManager::Get()->GetLoggingClient()->SetDebugLogging(
-        base::BindOnce(&DebugLogsManager::OnFlossSetDebugLogging,
-                       weak_ptr_factory_.GetWeakPtr(), enable,
-                       num_completed_attempts),
-        enable);
+    if (adapter_ && adapter_->IsPowered()) {
+      floss::FlossDBusManager::Get()->GetLoggingClient()->SetDebugLogging(
+          base::BindOnce(&DebugLogsManager::OnFlossSetDebugLogging,
+                         weak_ptr_factory_.GetWeakPtr(), enable,
+                         num_completed_attempts),
+          enable);
+    }
   } else {
     bluez::BluezDBusManager::Get()
         ->GetBluetoothDebugManagerClient()
diff --git a/chrome/browser/ash/bluetooth/debug_logs_manager_unittest.cc b/chrome/browser/ash/bluetooth/debug_logs_manager_unittest.cc
index 865e36c98..d1f5f64 100644
--- a/chrome/browser/ash/bluetooth/debug_logs_manager_unittest.cc
+++ b/chrome/browser/ash/bluetooth/debug_logs_manager_unittest.cc
@@ -144,6 +144,11 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  bool IsDebugEnabled() {
+    return debug_logs_manager_->GetDebugLogsState() ==
+           DebugLogsManager::DebugLogsState::kSupportedAndEnabled;
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
   bool is_debug_toggle_flag_enabled_ = false;
@@ -267,12 +272,14 @@
   EnableFlossFlag();
   InitFeatures();
 
+  // Until we're powered, setting debug logging should fail but the default
+  // state should be persisted.
   EXPECT_EQ(fake_floss_logging_client()->GetDebugEnabledForTesting(), false);
   InstantiateDebugManager(kTestGooglerEmail);
-  EXPECT_EQ(fake_floss_logging_client()->GetDebugEnabledForTesting(), true);
-
-  fake_floss_logging_client()->SetDebugEnabledForTesting(false);
   EXPECT_EQ(fake_floss_logging_client()->GetDebugEnabledForTesting(), false);
+  EXPECT_EQ(IsDebugEnabled(), true);
+
+  // Powering on should enable the flag.
   SimulatePowered(/*powered=*/true);
   EXPECT_EQ(fake_floss_logging_client()->GetDebugEnabledForTesting(), true);
   SimulatePowered(/*powered=*/false);
diff --git a/chrome/browser/ash/drive/drive_integration_service.cc b/chrome/browser/ash/drive/drive_integration_service.cc
index f5882a9..939ae1c 100644
--- a/chrome/browser/ash/drive/drive_integration_service.cc
+++ b/chrome/browser/ash/drive/drive_integration_service.cc
@@ -56,6 +56,7 @@
 #include "components/drive/drive_notification_manager.h"
 #include "components/drive/drive_pref_names.h"
 #include "components/drive/event_logger.h"
+#include "components/drive/file_errors.h"
 #include "components/drive/resource_metadata_storage.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -1208,8 +1209,7 @@
   }
 
   auto query_params = drivefs::mojom::QueryParameters::New();
-  query_params->query_source =
-      drivefs::mojom::QueryParameters::QuerySource::kLocalOnly;
+  query_params->page_size = 1000;
   query_params->available_offline = true;
 
   int64_t total_size = 0;
@@ -1232,7 +1232,10 @@
     drive::FileError error,
     absl::optional<std::vector<drivefs::mojom::QueryItemPtr>> results) {
   if (!ash::features::IsDriveFsBulkPinningEnabled() ||
-      error != drive::FILE_ERROR_OK || results->empty()) {
+      error != drive::FILE_ERROR_OK || results->empty() ||
+      callback.IsCancelled()) {
+    LOG_IF(ERROR, error != drive::FILE_ERROR_OK)
+        << "Failed to get offline size: " << drive::FileErrorToString(error);
     std::move(callback).Run(total_size);
     return;
   }
diff --git a/chrome/browser/ash/events/OWNERS b/chrome/browser/ash/events/OWNERS
index 637480f..1c7633b7 100644
--- a/chrome/browser/ash/events/OWNERS
+++ b/chrome/browser/ash/events/OWNERS
@@ -1,2 +1,3 @@
+zentaro@chromium.org
 
 per-file *event_rewriter* = kpschoedel@chromium.org
diff --git a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
index 3a853b0a..f0e2c7a0 100644
--- a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
+++ b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
@@ -26,6 +26,7 @@
 #include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
 #include "chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h"
 #include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/test/chromeos_test_utils.h"
 #include "components/language/core/browser/pref_names.h"
@@ -103,6 +104,9 @@
     // Make sure that OOBE is run as an "official" build.
     LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build =
         true;
+
+    // Clear portal list (as it is by default in OOBE).
+    NetworkHandler::Get()->network_state_handler()->SetCheckPortalList("");
   }
 
  protected:
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index 4f9c6b6f..98df496 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -16,6 +16,7 @@
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/ash_switches.h"
 #include "ash/public/cpp/session/session_controller.h"
+#include "base/barrier_closure.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/containers/adapters.h"
@@ -916,10 +917,27 @@
 
 void ChromeUserManagerImpl::RemoveNonCryptohomeData(
     const AccountId& account_id) {
-  // Wallpaper removal depends on user preference, so it must happen before
-  // `known_user::RemovePrefs`. See https://crbug.com/778077.
-  for (auto& handler : cloud_external_data_policy_handlers_)
-    handler->RemoveForAccountId(account_id);
+  // Wallpaper removal can be async if system salt is not yet received (see
+  // `WallpaperControllerClientImpl::GetFilesId`), and depends on user
+  // preference, so it must happen before `known_user::RemovePrefs`.
+  // See https://crbug.com/778077. Here we use a latch to ensure that
+  // `known_user::RemovePrefs` does indeed get invoked after wallpaper and other
+  // external data that might be associated with `account_id` are removed (in
+  // case those removal operations are async).
+  remove_non_cryptohome_data_barrier_ = base::BarrierClosure(
+      cloud_external_data_policy_handlers_.size(),
+      base::BindOnce(&ChromeUserManagerImpl::
+                         RemoveNonCryptohomeDataPostExternalDataRemoval,
+                     weak_factory_.GetWeakPtr(), account_id));
+
+  for (auto& handler : cloud_external_data_policy_handlers_) {
+    handler->RemoveForAccountId(account_id,
+                                remove_non_cryptohome_data_barrier_);
+  }
+}
+
+void ChromeUserManagerImpl::RemoveNonCryptohomeDataPostExternalDataRemoval(
+    const AccountId& account_id) {
   // TODO(tbarzic): Forward data removal request to HammerDeviceHandler,
   // instead of removing the prefs value here.
   if (GetLocalState()->FindPreference(prefs::kDetachableBaseDevices)) {
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.h b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
index 7d3b301..ed311670 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/synchronization/lock.h"
@@ -232,6 +233,15 @@
 
   void UpdateOwnerId();
 
+  // Remove non cryptohome data associated with the given `account_id` after
+  // having removed all external data (such as wallpapers and avatars)
+  // associated with that `account_id`, this function is guarded by a latch
+  // `remove_non_cryptohome_data_latch_` that ensures that all external data is
+  // removed prior to clearing prefs for `account_id`, as the removal of certain
+  // external data depends on prefs.
+  void RemoveNonCryptohomeDataPostExternalDataRemoval(
+      const AccountId& account_id);
+
   // Interface to the signed settings store.
   CrosSettings* cros_settings_;
 
@@ -281,6 +291,8 @@
 
   bool user_added_removed_reporter_intialized_ = false;
 
+  base::RepeatingClosure remove_non_cryptohome_data_barrier_;
+
   base::WeakPtrFactory<ChromeUserManagerImpl> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
index 6591aae..6075a1e 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
@@ -291,7 +291,7 @@
       WallpaperControllerClientImpl::Get();
   // `wallpaper_client` could be nullptr in tests.
   if (wallpaper_client)
-    wallpaper_client->RemoveUserWallpaper(account_id);
+    wallpaper_client->RemoveUserWallpaper(account_id, base::DoNothing());
   ProfileHelper::Get()->RemoveUserFromListForTesting(account_id);
 
   const user_manager::UserList::iterator it =
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index ab439ef..70aedb8 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -199,8 +199,11 @@
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
 #include "chromeos/ash/components/geolocation/simple_geolocation_provider.h"
+#include "chromeos/ash/components/network/network_handler.h"
+#include "chromeos/ash/components/network/network_handler_callbacks.h"
 #include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/network/portal_detector/network_portal_detector.h"
 #include "chromeos/ash/components/settings/cros_settings_names.h"
 #include "chromeos/ash/components/settings/cros_settings_provider.h"
 #include "chromeos/ash/components/settings/timezone_settings.h"
@@ -2165,7 +2168,12 @@
                    ServicesCustomizationDocument::GetInstance()
                        ->EnsureCustomizationAppliedClosure());
 
+  // Enable portal check for official builds.
+  // ChromiumOS builds would go though this code path too.
+  NetworkHandler::Get()->network_state_handler()->SetCheckPortalList(
+      NetworkStateHandler::kDefaultCheckPortalList);
   GetAutoEnrollmentController()->Start();
+  network_portal_detector::GetInstance()->Enable();
 }
 
 void WizardController::PerformOOBECompletedActions() {
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc
index c67678ad..8e2f014 100644
--- a/chrome/browser/ash/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -529,6 +529,9 @@
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_));
 
+    // Clear portal list (as it is by default in OOBE).
+    NetworkHandler::Get()->network_state_handler()->SetCheckPortalList("");
+
     // Set up the mocks for all screens.
     mock_welcome_screen_ =
         MockScreenExpectLifecycle(std::make_unique<MockWelcomeScreen>(
@@ -744,6 +747,9 @@
     EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
 
     EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
+    EXPECT_EQ("ethernet,wifi,cellular", NetworkHandler::Get()
+                                            ->network_state_handler()
+                                            ->GetCheckPortalListForTest());
 
     WaitUntilTimezoneResolved();
     EXPECT_EQ(
@@ -897,6 +903,10 @@
   EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
   EXPECT_CALL(*mock_enrollment_screen_, HideImpl()).Times(0);
   content::RunAllPendingInMessageLoop();
+
+  EXPECT_EQ("ethernet,wifi,cellular", NetworkHandler::Get()
+                                          ->network_state_handler()
+                                          ->GetCheckPortalListForTest());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
@@ -2522,6 +2532,9 @@
         WizardController::default_controller();
     wizard_controller->SetCurrentScreen(nullptr);
 
+    // Clear portal list (as it is by default in OOBE).
+    NetworkHandler::Get()->network_state_handler()->SetCheckPortalList("");
+
     // Set up the mocks for all screens.
     mock_welcome_view_ = std::make_unique<MockWelcomeView>();
     mock_welcome_screen_ =
@@ -2645,6 +2658,13 @@
     command_line->AppendSwitchPath(chromeos::switches::kFakeOobeConfiguration,
                                    configuration_file);
   }
+
+  // WizardControllerTest:
+  void SetUpOnMainThread() override {
+    WizardControllerTest::SetUpOnMainThread();
+    // Clear portal list (as it is by default in OOBE).
+    NetworkHandler::Get()->network_state_handler()->SetCheckPortalList("");
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(WizardControllerOobeConfigurationTest,
@@ -2712,8 +2732,15 @@
   run_loop.Run();
 }
 
+#if BUILDFLAG(IS_CHROMEOS)
+// Disabled due to crbug.com/1414116.
+#define MAYBE_AdvanceToEnrollmentAfterRollback \
+  DISABLED_AdvanceToEnrollmentAfterRollback
+#else
+#define MAYBE_AdvanceToEnrollmentAfterRollback AdvanceToEnrollmentAfterRollback
+#endif
 IN_PROC_BROWSER_TEST_F(WizardControllerRollbackFlowTest,
-                       AdvanceToEnrollmentAfterRollback) {
+                       MAYBE_AdvanceToEnrollmentAfterRollback) {
   CheckCurrentScreen(WelcomeView::kScreenId);
 
   EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
diff --git a/chrome/browser/ash/net/network_portal_detector_impl.cc b/chrome/browser/ash/net/network_portal_detector_impl.cc
index aba7bf7..d111b082 100644
--- a/chrome/browser/ash/net/network_portal_detector_impl.cc
+++ b/chrome/browser/ash/net/network_portal_detector_impl.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/branding_buildflags.h"
+#include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/net/system_network_context_manager.h"
@@ -142,13 +143,18 @@
   if (enabled_)
     return;
 
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  if (!StartupUtils::IsEulaAccepted()) {
+    NET_LOG(EVENT) << "NetworkPortalDetector: Eula not accepted.";
+    return;
+  }
+#endif
+
   NET_LOG(EVENT) << "NetworkPortalDetector Enabled.";
   DCHECK(is_idle());
   enabled_ = true;
 
   // Ensure that Shill portal detection is enabled.
-  // TODO(b/265806000): Remove calls to SetCheckPortalList entirely once
-  // shill/init/shill.sh is updated.
   NetworkHandler::Get()->network_state_handler()->SetCheckPortalList(
       NetworkStateHandler::kDefaultCheckPortalList);
 
diff --git a/chrome/browser/ash/policy/external_data/handlers/cloud_external_data_policy_handler.h b/chrome/browser/ash/policy/external_data/handlers/cloud_external_data_policy_handler.h
index a7cff55..137fabd 100644
--- a/chrome/browser/ash/policy/external_data/handlers/cloud_external_data_policy_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/cloud_external_data_policy_handler.h
@@ -21,7 +21,8 @@
   CloudExternalDataPolicyHandler& operator=(
       const CloudExternalDataPolicyHandler&) = delete;
 
-  virtual void RemoveForAccountId(const AccountId& account_id) = 0;
+  virtual void RemoveForAccountId(const AccountId& account_id,
+                                  base::OnceClosure on_removed) = 0;
 
   static AccountId GetAccountId(const std::string& user_id);
 };
diff --git a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
index c42f49a..e5117e0 100644
--- a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.cc
@@ -61,17 +61,20 @@
 }
 
 void CrostiniAnsiblePlaybookExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   Profile* profile =
       ash::ProfileHelper::Get()->GetProfileByAccountId(account_id);
   if (!profile) {
     LOG(ERROR) << "No profile for user is specified";
+    std::move(on_removed).Run();
     return;
   }
   profile->GetPrefs()->ClearPref(
       crostini::prefs::kCrostiniAnsiblePlaybookFilePath);
   profile->GetPrefs()->ClearPref(
       crostini::prefs::kCrostiniDefaultContainerConfigured);
+  std::move(on_removed).Run();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
index 1ab8d6cc..192dc65 100644
--- a/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/crostini_ansible_playbook_external_data_handler.h
@@ -39,7 +39,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver crostini_ansible_observer_;
diff --git a/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.cc
index 400f670..165c6e1 100644
--- a/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.cc
@@ -49,10 +49,12 @@
 }
 
 void PreconfiguredDeskTemplatesExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   DesksClient* dc = DesksClient::Get();
   if (dc)
     dc->RemovePolicyPreconfiguredTemplate(account_id);
+  std::move(on_removed).Run();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.h
index cd36889..57abca61 100644
--- a/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/preconfigured_desk_templates_external_data_handler.h
@@ -39,7 +39,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver preconfigured_desk_templates_observer_;
diff --git a/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.cc
index 024ed50..414c6a7 100644
--- a/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.cc
@@ -57,8 +57,10 @@
 }
 
 void PrintServersExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   ash::PrintServersProviderFactory::Get()->RemoveForAccountId(account_id);
+  std::move(on_removed).Run();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.h
index 36614a0..00d9b58 100644
--- a/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/print_servers_external_data_handler.h
@@ -42,7 +42,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver print_servers_observer_;
diff --git a/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.cc
index 2c3df37..3b4dd2f 100644
--- a/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.cc
@@ -70,11 +70,13 @@
 }
 
 void PrintersExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   auto* factory = ash::BulkPrintersCalculatorFactory::Get();
   if (factory) {
     factory->RemoveForUserId(account_id);
   }
+  std::move(on_removed).Run();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.h
index 8a96183..28fba2e 100644
--- a/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/printers_external_data_handler.h
@@ -37,7 +37,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver printers_observer_;
diff --git a/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.cc
index a92bd0c0..1b03b907 100644
--- a/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.cc
@@ -56,10 +56,13 @@
 }
 
 void UserAvatarImageExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   ash::ChromeUserManager::Get()
       ->GetUserImageManager(account_id)
       ->DeleteUserImage();
+
+  std::move(on_removed).Run();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.h
index 8c05c976..f864618 100644
--- a/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/user_avatar_image_external_data_handler.h
@@ -41,7 +41,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver user_avatar_image_observer_;
diff --git a/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.cc b/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.cc
index 1a318293..edaf268 100644
--- a/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.cc
@@ -42,8 +42,10 @@
 }
 
 void WallpaperImageExternalDataHandler::RemoveForAccountId(
-    const AccountId& account_id) {
-  WallpaperControllerClientImpl::Get()->RemoveUserWallpaper(account_id);
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
+  WallpaperControllerClientImpl::Get()->RemoveUserWallpaper(
+      account_id, std::move(on_removed));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.h b/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.h
index 5a48cb1..0631efc 100644
--- a/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.h
+++ b/chrome/browser/ash/policy/external_data/handlers/wallpaper_image_external_data_handler.h
@@ -39,7 +39,8 @@
                              const std::string& user_id,
                              std::unique_ptr<std::string> data,
                              const base::FilePath& file_path) override;
-  void RemoveForAccountId(const AccountId& account_id) override;
+  void RemoveForAccountId(const AccountId& account_id,
+                          base::OnceClosure on_removed) override;
 
  private:
   CloudExternalDataPolicyObserver wallpaper_image_observer_;
diff --git a/chrome/browser/ash/video_conference/video_conference_app_service_client.cc b/chrome/browser/ash/video_conference/video_conference_app_service_client.cc
index fdb9d72..1f2b5d08 100644
--- a/chrome/browser/ash/video_conference/video_conference_app_service_client.cc
+++ b/chrome/browser/ash/video_conference/video_conference_app_service_client.cc
@@ -25,7 +25,7 @@
 namespace ash {
 namespace {
 VideoConferenceAppServiceClient* g_client_instance = nullptr;
-}
+}  // namespace
 
 VideoConferenceAppServiceClient::VideoConferenceAppServiceClient()
     : client_id_(base::UnguessableToken::Create()),
@@ -148,11 +148,15 @@
 
   const bool is_capturing_camera = update.Camera().value_or(false);
   const bool is_capturing_microphone = update.Microphone().value_or(false);
+  const bool is_already_tracked = base::Contains(id_to_app_state_, app_id);
 
   // We only want to start tracking a app if it starts to accessing
   // microphone/camera.
-  if (!is_capturing_camera && !is_capturing_microphone &&
-      !base::Contains(id_to_app_state_, app_id)) {
+  if (!is_capturing_camera && !is_capturing_microphone && !is_already_tracked) {
+    return;
+  }
+
+  if (!is_already_tracked && ::video_conference::ShouldSkipId(app_id)) {
     return;
   }
 
diff --git a/chrome/browser/ash/video_conference/video_conference_app_service_client.h b/chrome/browser/ash/video_conference/video_conference_app_service_client.h
index af844ea..3a3ba62 100644
--- a/chrome/browser/ash/video_conference/video_conference_app_service_client.h
+++ b/chrome/browser/ash/video_conference/video_conference_app_service_client.h
@@ -14,6 +14,7 @@
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "chromeos/crosapi/mojom/video_conference.mojom.h"
 #include "components/services/app_service/public/cpp/app_capability_access_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
@@ -36,6 +37,8 @@
       public SessionObserver {
  public:
   using AppIdString = std::string;
+  using VideoConferencePermissions =
+      video_conference::VideoConferencePermissions;
 
   // AppState records information that is required for VideoConferenceManagerAsh
   // to show correct icons.
@@ -47,13 +50,6 @@
     bool is_capturing_camera = false;
   };
 
-  // Struct holding the granted status of media device permissions used by
-  // videoconferencing apps.
-  struct VideoConferencePermissions {
-    bool has_camera_permission = false;
-    bool has_microphone_permission = false;
-  };
-
   VideoConferenceAppServiceClient();
 
   VideoConferenceAppServiceClient(const VideoConferenceAppServiceClient&) =
diff --git a/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc b/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
index 8078487..b5583462 100644
--- a/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
+++ b/chrome/browser/ash/video_conference/video_conference_app_service_client_browsertest.cc
@@ -15,6 +15,7 @@
 #include "ash/system/video_conference/video_conference_media_state.h"
 #include "ash/test/test_window_builder.h"
 #include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
@@ -25,6 +26,7 @@
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/video_conference/video_conference_manager_ash.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -60,6 +62,9 @@
   if (app_id == kAppId2) {
     app->name = kAppName2;
   }
+  if (base::Contains(::video_conference::kSkipAppIds, app_id)) {
+    app->name = base::StrCat({"AppName-", app_id});
+  }
 
   app->publisher_id = app_id;
 
@@ -698,4 +703,18 @@
             2u);
 }
 
+IN_PROC_BROWSER_TEST_F(VideoConferenceAppServiceClientTest,
+                       SomeAppsAreNotTracked) {
+  // Install all apps that should be skipped.
+  for (const std::string& app_id : ::video_conference::kSkipAppIds) {
+    InstallApp(app_id);
+    // Accessing mic and camera should trigger tracking except the app_id is
+    // skipped.
+    SetAppCapabilityAccess(app_id, /*is_capturing_camera=*/true,
+                           /*is_capturing_microphone=*/true);
+  }
+
+  EXPECT_TRUE(GetMediaApps().empty());
+}
+
 }  // namespace ash
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 0a81177..bd7fb33 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -480,6 +480,31 @@
   EXPECT_FALSE(client.GetLoggingFileName(cmd_line).empty());
 }
 
+#if BUILDFLAG(IS_WIN)
+TEST_F(ChromeContentBrowserClientGetLoggingFileTest,
+       GetLoggingFileFromCommandLine) {
+  base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
+  cmd_line.AppendSwitchASCII(switches::kLogFile, "c:\\path\\test_log.txt");
+  ChromeContentBrowserClient client;
+  base::FilePath log_file_name;
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("test_log.txt")).value(),
+            client.GetLoggingFileName(cmd_line).BaseName().value());
+  // Path must be absolute.
+  EXPECT_TRUE(client.GetLoggingFileName(cmd_line).IsAbsolute());
+}
+TEST_F(ChromeContentBrowserClientGetLoggingFileTest,
+       GetLoggingFileFromCommandLineFallback) {
+  base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
+  cmd_line.AppendSwitchASCII(switches::kLogFile, "test_log.txt");
+  ChromeContentBrowserClient client;
+  base::FilePath log_file_name;
+  // Windows falls back to the default if an absolute path is not provided.
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrome_debug.log")).value(),
+            client.GetLoggingFileName(cmd_line).BaseName().value());
+  // Path must be absolute.
+  EXPECT_TRUE(client.GetLoggingFileName(cmd_line).IsAbsolute());
+}
+#else
 TEST_F(ChromeContentBrowserClientGetLoggingFileTest,
        GetLoggingFileFromCommandLine) {
   base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
@@ -489,6 +514,7 @@
   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("test_log.txt")).value(),
             client.GetLoggingFileName(cmd_line).value());
 }
+#endif  // BUILDFLAG(IS_WIN)
 
 class TestChromeContentBrowserClient : public ChromeContentBrowserClient {
  public:
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5cf16dd4..f8d9253 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -147,9 +147,10 @@
     "tablet_mode/chrome_content_browser_client_tablet_mode_part.h",
     "tablet_mode/tablet_mode_page_behavior.cc",
     "tablet_mode/tablet_mode_page_behavior.h",
-    "video_conference/video_conference_app_permissions.h",
     "video_conference/video_conference_manager_client.cc",
     "video_conference/video_conference_manager_client.h",
+    "video_conference/video_conference_manager_client_common.cc",
+    "video_conference/video_conference_manager_client_common.h",
     "video_conference/video_conference_media_listener.cc",
     "video_conference/video_conference_media_listener.h",
     "video_conference/video_conference_web_app.cc",
diff --git a/chrome/browser/chromeos/video_conference/video_conference_manager_client.cc b/chrome/browser/chromeos/video_conference/video_conference_manager_client.cc
index e1dfee8..c08dc950 100644
--- a/chrome/browser/chromeos/video_conference/video_conference_manager_client.cc
+++ b/chrome/browser/chromeos/video_conference/video_conference_manager_client.cc
@@ -13,7 +13,7 @@
 #include "base/logging.h"
 #include "base/unguessable_token.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/chromeos/video_conference/video_conference_app_permissions.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "chrome/browser/chromeos/video_conference/video_conference_media_listener.h"
 #include "chrome/browser/chromeos/video_conference/video_conference_web_app.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/chromeos/video_conference/video_conference_manager_client_common.cc b/chrome/browser/chromeos/video_conference/video_conference_manager_client_common.cc
new file mode 100644
index 0000000..5c1df1cb
--- /dev/null
+++ b/chrome/browser/chromeos/video_conference/video_conference_manager_client_common.cc
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
+
+#include <string>
+
+#include "base/containers/contains.h"
+
+namespace video_conference {
+
+const char* kSkipAppIds[2] = {
+    "behllobkkfkfnphdnhnkndlbkcpglgmj",  // TestExtensionID
+    "mecfefiddjlmabpeilblgegnbioikfmp",  // SigninProfileTestExtensionID
+};
+
+bool ShouldSkipId(const std::string& id) {
+  return base::Contains(kSkipAppIds, id);
+}
+
+}  // namespace video_conference
diff --git a/chrome/browser/chromeos/video_conference/video_conference_app_permissions.h b/chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h
similarity index 67%
rename from chrome/browser/chromeos/video_conference/video_conference_app_permissions.h
rename to chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h
index cc8a2ec..9dd92185 100644
--- a/chrome/browser/chromeos/video_conference/video_conference_app_permissions.h
+++ b/chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h
@@ -2,11 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_PERMISSIONS_H_
-#define CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_PERMISSIONS_H_
+#ifndef CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_MANAGER_CLIENT_COMMON_H_
+#define CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_MANAGER_CLIENT_COMMON_H_
+
+#include <array>
+#include <string>
 
 namespace video_conference {
 
+// AppIds that we want to skip tracking.
+extern const char* kSkipAppIds[2];
+
+// Returns whether we should skip the contents for tracking.
+bool ShouldSkipId(const std::string& id);
+
 // Struct holding the granted status of media device permissions used by
 // videoconferencing apps.
 struct VideoConferencePermissions {
@@ -16,4 +25,4 @@
 
 }  // namespace video_conference
 
-#endif  // CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_APP_PERMISSIONS_H_
+#endif  // CHROME_BROWSER_CHROMEOS_VIDEO_CONFERENCE_VIDEO_CONFERENCE_MANAGER_CLIENT_COMMON_H_
diff --git a/chrome/browser/chromeos/video_conference/video_conference_media_listener.cc b/chrome/browser/chromeos/video_conference/video_conference_media_listener.cc
index dee756e8..fa6eca8 100644
--- a/chrome/browser/chromeos/video_conference/video_conference_media_listener.cc
+++ b/chrome/browser/chromeos/video_conference/video_conference_media_listener.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/video_conference/video_conference_media_listener.h"
 
 #include "base/memory/scoped_refptr.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "chrome/browser/chromeos/video_conference/video_conference_web_app.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "content/public/browser/web_contents.h"
@@ -103,6 +104,11 @@
     if (!is_capturing) {
       return nullptr;
     }
+
+    if (ShouldSkipId(contents->GetURL().host())) {
+      return nullptr;
+    }
+
     vc_app = create_vc_web_app_callback_.Run(contents);
   }
 
diff --git a/chrome/browser/chromeos/video_conference/video_conference_media_listener_browsertest.cc b/chrome/browser/chromeos/video_conference/video_conference_media_listener_browsertest.cc
index 461b793..b775801 100644
--- a/chrome/browser/chromeos/video_conference/video_conference_media_listener_browsertest.cc
+++ b/chrome/browser/chromeos/video_conference/video_conference_media_listener_browsertest.cc
@@ -7,11 +7,14 @@
 #include <memory>
 
 #include "base/functional/bind.h"
+#include "base/strings/strcat.h"
 #include "base/unguessable_token.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "chrome/browser/chromeos/video_conference/video_conference_web_app.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -227,4 +230,37 @@
   EXPECT_EQ(media_listener->state().window_capture_count, 0);
 }
 
+IN_PROC_BROWSER_TEST_F(VideoConferenceMediaListenerBrowserTest,
+                       TestExtensionIDShouldNotBeTracked) {
+  std::unique_ptr<FakeVcMediaListener> media_listener =
+      std::make_unique<FakeVcMediaListener>();
+
+  // We can't directly navigate to TestExtensionUrl, so we use this workaround
+  // to set the url afterwards.
+  EXPECT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_LINK));
+  auto* web_contents = browser()->tab_strip_model()->GetWebContentsAt(0);
+
+  for (const std::string& app_id : kSkipAppIds) {
+    const GURL url = GURL(base::StrCat(
+        {"chrome-extension://", app_id, "/_generated_background_page.html"}));
+    web_contents->GetController().GetLastCommittedEntry()->SetURL(GURL(url));
+
+    // Verify that the url is indeed changed.
+    EXPECT_EQ(web_contents->GetURL().host(), app_id);
+
+    // Access video.
+    StartCapture(web_contents,
+                 blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
+
+    // Verify no app is tracked.
+    EXPECT_EQ(media_listener->state().window_capture_count, 0);
+
+    // Verify that VideoConferenceWebApp is not created for web_contents.
+    EXPECT_EQ(
+        content::WebContentsUserData<VideoConferenceWebApp>::FromWebContents(
+            web_contents),
+        nullptr);
+  }
+}
+
 }  // namespace video_conference
diff --git a/chrome/browser/chromeos/video_conference/video_conference_web_app.cc b/chrome/browser/chromeos/video_conference/video_conference_web_app.cc
index 3fd87638..d6a1957 100644
--- a/chrome/browser/chromeos/video_conference/video_conference_web_app.cc
+++ b/chrome/browser/chromeos/video_conference/video_conference_web_app.cc
@@ -9,7 +9,7 @@
 #include "base/check.h"
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
-#include "chrome/browser/chromeos/video_conference/video_conference_app_permissions.h"
+#include "chrome/browser/chromeos/video_conference/video_conference_manager_client_common.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/page.h"
 #include "content/public/browser/permission_controller.h"
diff --git a/chrome/browser/download/bubble/download_bubble_controller.cc b/chrome/browser/download/bubble/download_bubble_controller.cc
index 4aec509..aeadb8a 100644
--- a/chrome/browser/download/bubble/download_bubble_controller.cc
+++ b/chrome/browser/download/bubble/download_bubble_controller.cc
@@ -207,18 +207,21 @@
     }
   }
   if (any_new) {
-    display_controller_->OnNewItem(/*show_details=*/(
-        any_in_progress &&
-        (browser_ == chrome::FindLastActiveWithProfile(profile_.get()))));
+    display_controller_->OnNewItem(
+        /*show_details=*/(
+            any_in_progress &&
+            (browser_ == chrome::FindLastActiveWithProfile(profile_.get()))),
+        /*show_animation=*/false);
   }
 }
 
 void DownloadBubbleUIController::OnNewItem(download::DownloadItem* item,
                                            bool show_details) {
-  std::make_unique<DownloadItemModel>(item)->SetActionedOn(false);
+  auto model = std::make_unique<DownloadItemModel>(item);
+  model->SetActionedOn(false);
   display_controller_->OnNewItem(
-      (item->GetState() == download::DownloadItem::IN_PROGRESS) &&
-      show_details);
+      (item->GetState() == download::DownloadItem::IN_PROGRESS) && show_details,
+      model->ShouldShowDownloadStartedAnimation());
 }
 
 bool DownloadBubbleUIController::ShouldShowIncognitoIcon(
diff --git a/chrome/browser/download/bubble/download_bubble_controller_unittest.cc b/chrome/browser/download/bubble/download_bubble_controller_unittest.cc
index 3bfbb2a..05917ef 100644
--- a/chrome/browser/download/bubble/download_bubble_controller_unittest.cc
+++ b/chrome/browser/download/bubble/download_bubble_controller_unittest.cc
@@ -33,6 +33,7 @@
 using testing::_;
 using testing::NiceMock;
 using testing::Return;
+using testing::ReturnRef;
 using testing::ReturnRefOfCopy;
 using testing::SetArgPointee;
 
@@ -48,7 +49,7 @@
                                 DownloadBubbleUIController* bubble_controller)
       : DownloadDisplayController(nullptr, browser, bubble_controller) {}
   void MaybeShowButtonWhenCreated() override {}
-  MOCK_METHOD1(OnNewItem, void(bool));
+  MOCK_METHOD2(OnNewItem, void(bool, bool));
   MOCK_METHOD2(OnUpdatedItem, void(bool, bool));
   MOCK_METHOD1(OnRemovedItem, void(const ContentId&));
 };
@@ -165,7 +166,7 @@
     items_.push_back(std::make_unique<StrictMockDownloadItem>());
     EXPECT_CALL(item(index), GetId())
         .WillRepeatedly(Return(static_cast<uint32_t>(items_.size() + 1)));
-    EXPECT_CALL(item(index), GetGuid()).WillRepeatedly(testing::ReturnRef(id));
+    EXPECT_CALL(item(index), GetGuid()).WillRepeatedly(ReturnRef(id));
     EXPECT_CALL(item(index), GetState()).WillRepeatedly(Return(state));
     EXPECT_CALL(item(index), GetStartTime()).WillRepeatedly(Return(start_time));
     EXPECT_CALL(item(index), GetTargetFilePath())
@@ -188,6 +189,15 @@
         .WillRepeatedly(Return(download::DownloadItem::DownloadCreationType::
                                    TYPE_ACTIVE_DOWNLOAD));
     EXPECT_CALL(item(index), IsPaused()).WillRepeatedly(Return(false));
+    // Functions called when checking ShouldShowDownloadStartedAnimation().
+    EXPECT_CALL(item(index), IsSavePackageDownload())
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(item(index), GetTargetDisposition())
+        .WillRepeatedly(
+            Return(download::DownloadItem::TARGET_DISPOSITION_PROMPT));
+    EXPECT_CALL(item(index), GetMimeType()).WillRepeatedly(Return(""));
+    EXPECT_CALL(item(index), GetURL())
+        .WillRepeatedly(ReturnRef(GURL::EmptyGURL()));
     std::vector<download::DownloadItem*> items;
     for (size_t i = 0; i < items_.size(); ++i) {
       items.push_back(&item(i));
@@ -255,15 +265,15 @@
 TEST_F(DownloadBubbleUIControllerTest, ProcessesNewItems) {
   std::vector<std::string> ids = {"Download 1", "Download 2", "Offline 1",
                                   "Download 3"};
-  EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(true, true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
                    download::DownloadItem::IN_PROGRESS, ids[0]);
-  EXPECT_CALL(display_controller(), OnNewItem(false)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(false, true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar2.pdf"),
                    download::DownloadItem::COMPLETE, ids[1]);
-  EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(true, false)).Times(1);
   InitOfflineItem(OfflineItemState::IN_PROGRESS, ids[2]);
-  EXPECT_CALL(display_controller(), OnNewItem(false)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(false, true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
                    download::DownloadItem::IN_PROGRESS, ids[3],
                    /*is_transient=*/false, base::Time::Now(),
@@ -272,7 +282,7 @@
 
 TEST_F(DownloadBubbleUIControllerTest, ProcessesUpdatedItems) {
   std::vector<std::string> ids = {"Download 1", "Offline 1"};
-  EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(true, true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
                    download::DownloadItem::IN_PROGRESS, ids[0]);
   EXPECT_CALL(display_controller(), OnUpdatedItem(false, true)).Times(1);
@@ -280,7 +290,7 @@
   EXPECT_CALL(display_controller(), OnUpdatedItem(true, true)).Times(1);
   UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE);
 
-  EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
+  EXPECT_CALL(display_controller(), OnNewItem(true, false)).Times(1);
   InitOfflineItem(OfflineItemState::IN_PROGRESS, ids[1]);
   EXPECT_CALL(display_controller(), OnUpdatedItem(true, true)).Times(1);
   UpdateOfflineItem(/*item_index=*/0, OfflineItemState::COMPLETE);
diff --git a/chrome/browser/download/bubble/download_display.h b/chrome/browser/download/bubble/download_display.h
index 8843ef6..25759419 100644
--- a/chrome/browser/download/bubble/download_display.h
+++ b/chrome/browser/download/bubble/download_display.h
@@ -21,7 +21,8 @@
   virtual void UpdateDownloadIcon() = 0;
   // Shows detailed information on the download display. It can be a popup or
   // dialog or partial view, essentially anything other than the main view.
-  virtual void ShowDetails() = 0;
+  // If |show_animation| is true, an animated icon will be shown.
+  virtual void ShowDetails(bool show_animation) = 0;
   // Hide the detailed information on the download display.
   virtual void HideDetails() = 0;
   // Returns whether the details are visible.
diff --git a/chrome/browser/download/bubble/download_display_controller.cc b/chrome/browser/download/bubble/download_display_controller.cc
index f85d020..71a5f83 100644
--- a/chrome/browser/download/bubble/download_display_controller.cc
+++ b/chrome/browser/download/bubble/download_display_controller.cc
@@ -118,7 +118,8 @@
   base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
-void DownloadDisplayController::OnNewItem(bool show_details) {
+void DownloadDisplayController::OnNewItem(bool show_details,
+                                          bool show_animation) {
   if (!download::ShouldShowDownloadBubble(browser_->profile())) {
     return;
   }
@@ -142,7 +143,7 @@
           /*force_update=*/true);
     }
   } else {
-    display_->ShowDetails();
+    display_->ShowDetails(show_animation);
   }
 }
 
@@ -242,7 +243,7 @@
   int in_progress_count = InProgressDownloadCount(all_models);
   if (in_progress_count > 0 &&
       download::ShouldShowDownloadBubble(browser_->profile())) {
-    display_->ShowDetails();
+    display_->ShowDetails(/*show_animation=*/false);
   }
 }
 
diff --git a/chrome/browser/download/bubble/download_display_controller.h b/chrome/browser/download/bubble/download_display_controller.h
index bec4689..a6e75fa 100644
--- a/chrome/browser/download/bubble/download_display_controller.h
+++ b/chrome/browser/download/bubble/download_display_controller.h
@@ -80,9 +80,10 @@
   // Common methods for new downloads or new offline items.
   // Called from bubble controller when new item(s) are added, with
   // |show_details| as argument if the partial view should be shown.
+  // |show_animation| specifies whether a small animated arrow should be shown.
   // These methods are virtual so that they can be overridden for fake
   // controllers in testing.
-  virtual void OnNewItem(bool show_details);
+  virtual void OnNewItem(bool show_details, bool show_animation);
   // Called from bubble controller when an item is updated, with |is_done|
   // indicating if it was marked done, and with
   // |show_details_if_done| as argument if the partial view should be shown.
diff --git a/chrome/browser/download/bubble/download_display_controller_unittest.cc b/chrome/browser/download/bubble/download_display_controller_unittest.cc
index aeb6452..13fbff5 100644
--- a/chrome/browser/download/bubble/download_display_controller_unittest.cc
+++ b/chrome/browser/download/bubble/download_display_controller_unittest.cc
@@ -79,7 +79,7 @@
     is_active_ = controller_->GetIconInfo().is_active;
   }
 
-  void ShowDetails() override { detail_shown_ = true; }
+  void ShowDetails(bool show_animation) override { detail_shown_ = true; }
   void HideDetails() override { detail_shown_ = false; }
   bool IsShowingDetails() override { return detail_shown_; }
   bool IsFullscreenWithParentViewHidden() override { return is_fullscreen_; }
@@ -259,15 +259,17 @@
     item(index).AddObserver(&controller().get_download_notifier_for_testing());
     content::DownloadItemUtils::AttachInfoForTesting(&(item(index)), profile_,
                                                      nullptr);
-    controller().OnNewItem((state == download::DownloadItem::IN_PROGRESS) &&
-                           show_details);
+    controller().OnNewItem(
+        (state == download::DownloadItem::IN_PROGRESS) && show_details,
+        /*show_animation=*/false);
   }
 
   void InitOfflineItem(OfflineItemState state) {
     OfflineItem item;
     item.state = state;
     bubble_controller().AddOfflineItem(item);
-    controller().OnNewItem(state == OfflineItemState::IN_PROGRESS);
+    controller().OnNewItem(state == OfflineItemState::IN_PROGRESS,
+                           /*show_animation=*/false);
   }
 
   void UpdateOfflineItem(int item_index, OfflineItemState state) {
@@ -583,7 +585,7 @@
   EXPECT_CALL(item(0), GetTargetFilePath())
       .WillRepeatedly(
           ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("bar.pdf"))));
-  controller().OnNewItem(/*show_details=*/true);
+  controller().OnNewItem(/*show_details=*/true, /*show_animation=*/false);
   EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true,
                                  /*icon_state=*/DownloadIconState::kProgress,
                                  /*is_active=*/true));
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 9405e5d..0844db4c 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -3769,15 +3769,8 @@
   return std::move(response);
 }
 
-// TODO(https://crbug.com/1244128): Flaky on Win7
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_AltClickDownloadReferrerPolicy \
-  DISABLED_AltClickDownloadReferrerPolicy
-#else
-#define MAYBE_AltClickDownloadReferrerPolicy AltClickDownloadReferrerPolicy
-#endif
 IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest,
-                       MAYBE_AltClickDownloadReferrerPolicy) {
+                       AltClickDownloadReferrerPolicy) {
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&EchoReferrerRequestHandler));
   embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory());
@@ -3854,17 +3847,10 @@
   }
 }
 
-// TODO(https://crbug.com/1244128): Flaky on Win7
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_SaveLinkAsReferrerPolicy DISABLED_SaveLinkAsReferrerPolicy
-#else
-#define MAYBE_SaveLinkAsReferrerPolicy SaveLinkAsReferrerPolicy
-#endif
 // This test ensures that the Referer header is properly sanitized when
 // Save Link As is chosen from the context menu from a page with all possible
 // referrer policies.
-IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest,
-                       MAYBE_SaveLinkAsReferrerPolicy) {
+IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest, SaveLinkAsReferrerPolicy) {
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&EchoReferrerRequestHandler));
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -3943,9 +3929,8 @@
   }
 }
 
-// TODO(https://crbug.com/1244128): Flaky on Win7
 // TODO(crbug.com/1269422): Flaky on Lacros
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_SaveLinkAsVsCrossOriginResourcePolicy \
   DISABLED_SaveLinkAsVsCrossOriginResourcePolicy
 #else
@@ -4109,18 +4094,10 @@
   }
 }
 
-// TODO(https://crbug.com/1244128): Flaky on Win7
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_DownloadCrossDomainReferrerPolicy \
-  DISABLED_DownloadCrossDomainReferrerPolicy
-#else
-#define MAYBE_DownloadCrossDomainReferrerPolicy \
-  DownloadCrossDomainReferrerPolicy
-#endif
 // This test ensures that a cross-domain download correctly sets the referrer
 // according to the referrer policy.
 IN_PROC_BROWSER_TEST_P(DownloadReferrerPolicyTest,
-                       MAYBE_DownloadCrossDomainReferrerPolicy) {
+                       DownloadCrossDomainReferrerPolicy) {
   embedded_test_server()->RegisterRequestHandler(
       base::BindRepeating(&ServerRedirectRequestHandler));
   embedded_test_server()->RegisterRequestHandler(
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index c75ba8af..44f87b8 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -223,8 +223,8 @@
                                      base::Value::Dict& manifest_dict) {
   base::ScopedAllowBlockingForTesting allow_blocking;
 
-  // Retrieve the value of the "background" key and verify that it has
-  // the "persistent" key and specifies JS files.
+  // Retrieve the value of the `background` key and verify that it has
+  // the `persistent` key and specifies JS files.
   // Background pages that specify HTML files are not supported.
   base::Value::Dict* background_dict = manifest_dict.FindDict("background");
   if (!background_dict) {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index db21b17..19d82aff 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -5507,7 +5507,7 @@
     // This flag is used by ChromeOS for some accessibility users.
     // TODO(b/172341945): Fix this asap.
     "name": "overscroll-history-navigation",
-    "owners": [ "mohsen", "jinsukkim" ],
+    "owners": [ "jinsukkim" ],
     "expiry_milestone": 118
   },
   {
@@ -6256,6 +6256,11 @@
     "expiry_milestone": 96
   },
   {
+    "name": "share-sheet-migration-android",
+    "owners": [ "wenyufu" ],
+    "expiry_milestone": 121
+  },
+  {
     "name": "shared-highlighting-amp",
     "owners": ["cheickcisse@google.com"],
     "expiry_milestone": 97
@@ -6731,6 +6736,11 @@
     "expiry_milestone": 114
   },
   {
+    "name": "thumbnail-cache-refactor",
+    "owners": [ "ckitagawa", "fredmello" ],
+    "expiry_milestone": 118
+  },
+  {
     "name": "tint-composited-content",
     "owners": [ "chromeos-gfx@google.com" ],
     // This flag is used for QA & development on ChromeOS, which has no way to
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index fe052a2..5226211 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -534,18 +534,6 @@
     "it will offer to save it. If saved, it will be offered for filling in "
     "fields which expect a VPA.";
 
-const char kAutofillSaveCardUiExperimentName[] =
-    "Enable different UI variants for the upload credit card save bubble";
-const char kAutofillSaveCardUiExperimentDescription[] =
-    "When enabled, it will trigger slightly different UI variants along with "
-    "notification texts, when the upload credit card save bubble is shown.";
-const char kAutofillSaveCardUiExperimentCurrentWithUserAvatarAndEmail[] =
-    "Current with Avatar and Email";
-const char kAutofillSaveCardUiExperimentEncryptedAndSecure[] =
-    "Encrypted and Secure";
-const char kAutofillSaveCardUiExperimentFasterAndProtected[] =
-    "Faster and Protected";
-
 const char kAutofillShowManualFallbackInContextMenuName[] =
     "Show Autofill options in Context Menu";
 const char kAutofillShowManualFallbackInContextMenuDescription[] =
@@ -3004,6 +2992,11 @@
         "the frame has zero viewport intersection, a non-zero area, and is "
         "not display:none.";
 
+const char kThumbnailCacheRefactorName[] = "Thumbnail Cache Refactor";
+const char kThumbnailCacheRefactorDescription[] =
+    "When enabled the thumbnail cache for Android is updated to improve "
+    "memory usage and performance.";
+
 const char kNewBaseUrlInheritanceBehaviorName[] =
     "Enable new base url inheritance behaviors for srcdoc and about:blank";
 const char kNewBaseUrlInheritanceBehaviorDescription[] =
@@ -3986,6 +3979,10 @@
     "When enabled, sets the market URL for use in testing the update menu "
     "item.";
 
+const char kShareSheetMigrationAndroidName[] = "Share sheet refactor Android";
+const char kShareSheetMigrationAndroidDescription[] =
+    "When enabled, use the Android OS share sheet.";
+
 const char kSiteIsolationForPasswordSitesName[] =
     "Site Isolation For Password Sites";
 const char kSiteIsolationForPasswordSitesDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e4b8630..f6855ce1 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -290,12 +290,6 @@
 extern const char kAutofillSaveAndFillVPAName[];
 extern const char kAutofillSaveAndFillVPADescription[];
 
-extern const char kAutofillSaveCardUiExperimentName[];
-extern const char kAutofillSaveCardUiExperimentDescription[];
-extern const char kAutofillSaveCardUiExperimentCurrentWithUserAvatarAndEmail[];
-extern const char kAutofillSaveCardUiExperimentEncryptedAndSecure[];
-extern const char kAutofillSaveCardUiExperimentFasterAndProtected[];
-
 extern const char kAutofillShowManualFallbackInContextMenuName[];
 extern const char kAutofillShowManualFallbackInContextMenuDescription[];
 
@@ -1712,6 +1706,9 @@
 extern const char
     kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframesDescription[];
 
+extern const char kThumbnailCacheRefactorName[];
+extern const char kThumbnailCacheRefactorDescription[];
+
 extern const char kNewBaseUrlInheritanceBehaviorName[];
 extern const char kNewBaseUrlInheritanceBehaviorDescription[];
 
@@ -2280,6 +2277,9 @@
 extern const char kSetMarketUrlForTestingName[];
 extern const char kSetMarketUrlForTestingDescription[];
 
+extern const char kShareSheetMigrationAndroidName[];
+extern const char kShareSheetMigrationAndroidDescription[];
+
 extern const char kSiteIsolationForPasswordSitesName[];
 extern const char kSiteIsolationForPasswordSitesDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 1869bfa..153ad90a 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -246,6 +246,7 @@
     &kOmniboxModernizeVisualUpdate,
     &kOpaqueOriginForIncomingIntents,
     &kOptimizeGeolocationHeaderGeneration,
+    &kPartnerHomepageInitialLoadImprovement,
     &kPostTaskFocusTab,
     &kProbabilisticCryptidRenderer,
     &kQuickDeleteForAndroid,
@@ -276,6 +277,7 @@
     &kShowScrollableMVTOnNTPAndroid,
     &kFeedPositionAndroid,
     &kSearchResumptionModuleAndroid,
+    &kShareSheetMigrationAndroid,
     &kShouldIgnoreIntentSkipInternalCheck,
     &kSpecialLocaleWrapper,
     &kSpecialUserDecision,
@@ -297,6 +299,7 @@
     &kTabToGTSAnimation,
     &kTestDefaultDisabled,
     &kTestDefaultEnabled,
+    &kThumbnailCacheRefactor,
     &kToolbarMicIphAndroid,
     &kToolbarScrollAblationAndroid,
     &kTrustedWebActivityPostMessage,
@@ -777,6 +780,10 @@
              "OptimizeGeolocationHeaderGeneration",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kPartnerHomepageInitialLoadImprovement,
+             "PartnerHomepageInitialLoadImprovement",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kPostTaskFocusTab,
              "PostTaskFocusTab",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -889,6 +896,10 @@
              "ShowScrollableMVTOnNTPAndroid",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kShareSheetMigrationAndroid,
+             "ShareSheetMigrationAndroid",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kSpecialLocaleWrapper,
              "SpecialLocaleWrapper",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -969,6 +980,10 @@
              "TestDefaultEnabled",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kThumbnailCacheRefactor,
+             "ThumbnailCacheRefactor",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kToolbarMicIphAndroid,
              "ToolbarMicIphAndroid",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index f9881e6..e3fa33a0 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -110,6 +110,7 @@
 BASE_DECLARE_FEATURE(kBackGestureRefactorActivityAndroid);
 BASE_DECLARE_FEATURE(kBackGestureRefactorAndroid);
 BASE_DECLARE_FEATURE(kOpaqueOriginForIncomingIntents);
+BASE_DECLARE_FEATURE(kPartnerHomepageInitialLoadImprovement);
 BASE_DECLARE_FEATURE(kPostTaskFocusTab);
 BASE_DECLARE_FEATURE(kProbabilisticCryptidRenderer);
 BASE_DECLARE_FEATURE(kQuickDeleteForAndroid);
@@ -142,6 +143,7 @@
 BASE_DECLARE_FEATURE(kSafeModeForCachedFlags);
 BASE_DECLARE_FEATURE(kSearchResumptionModuleAndroid);
 BASE_DECLARE_FEATURE(kShouldIgnoreIntentSkipInternalCheck);
+BASE_DECLARE_FEATURE(kShareSheetMigrationAndroid);
 BASE_DECLARE_FEATURE(kSpecialLocaleWrapper);
 BASE_DECLARE_FEATURE(kSpecialUserDecision);
 BASE_DECLARE_FEATURE(kSplitCompositorTask);
@@ -162,6 +164,7 @@
 BASE_DECLARE_FEATURE(kTabToGTSAnimation);
 BASE_DECLARE_FEATURE(kTestDefaultDisabled);
 BASE_DECLARE_FEATURE(kTestDefaultEnabled);
+BASE_DECLARE_FEATURE(kThumbnailCacheRefactor);
 BASE_DECLARE_FEATURE(kToolbarMicIphAndroid);
 BASE_DECLARE_FEATURE(kToolbarScrollAblationAndroid);
 BASE_DECLARE_FEATURE(kToolbarUseHardwareBitmapDraw);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 7533a96..44ea32f 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -404,6 +404,8 @@
             "PageInfoAboutThisSiteImprovedBottomSheet";
     public static final String PAINT_PREVIEW_DEMO = "PaintPreviewDemo";
     public static final String PAINT_PREVIEW_SHOW_ON_STARTUP = "PaintPreviewShowOnStartup";
+    public static final String PARTNER_HOMEPAGE_INITIAL_LOAD_IMPROVEMENT =
+            "PartnerHomepageInitialLoadImprovement";
     public static final String PASSWORD_DOMAIN_CAPABILITIES_FETCHING =
             "PasswordDomainCapabilitiesFetching";
     public static final String PASSWORD_EDIT_DIALOG_WITH_DETAILS = "PasswordEditDialogWithDetails";
@@ -463,6 +465,7 @@
     public static final String SEARCH_RESUMPTION_MODULE_ANDROID = "SearchResumptionModuleAndroid";
     public static final String SHOULD_IGNORE_INTENT_SKIP_INTERNAL_CHECK =
             "ShouldIgnoreIntentSkipInternalCheck";
+    public static final String SHARE_SHEET_MIGRATION_ANDROID = "ShareSheetMigrationAndroid";
     public static final String SEND_TAB_TO_SELF_SIGNIN_PROMO = "SendTabToSelfSigninPromo";
     public static final String SEND_TAB_TO_SELF_V2 = "SendTabToSelfV2";
     public static final String SHARED_HIGHLIGHTING_AMP = "SharedHighlightingAmp";
@@ -506,6 +509,7 @@
     public static final String TANGIBLE_SYNC = "TangibleSync";
     public static final String TEST_DEFAULT_DISABLED = "TestDefaultDisabled";
     public static final String TEST_DEFAULT_ENABLED = "TestDefaultEnabled";
+    public static final String THUMBNAIL_CACHE_REFACTOR = "ThumbnailCacheRefactor";
     public static final String TOOLBAR_MIC_IPH_ANDROID = "ToolbarMicIphAndroid";
     public static final String TOOLBAR_SCROLL_ABLATION_ANDROID = "ToolbarScrollAblationAndroid";
     public static final String TOOLBAR_USE_HARDWARE_BITMAP_DRAW = "ToolbarUseHardwareBitmapDraw";
@@ -627,6 +631,8 @@
     public static final CachedFlag sOptimizationGuidePushNotifications =
             new CachedFlag(OPTIMIZATION_GUIDE_PUSH_NOTIFICATIONS, false);
     public static final CachedFlag sPaintPreviewDemo = new CachedFlag(PAINT_PREVIEW_DEMO, false);
+    public static final CachedFlag sPartnerHomepageInitialLoadImprovement =
+            new CachedFlag(PARTNER_HOMEPAGE_INITIAL_LOAD_IMPROVEMENT, true);
     public static final CachedFlag sPrefetchNotificationSchedulingIntegration =
             new CachedFlag(PREFETCH_NOTIFICATION_SCHEDULING_INTEGRATION, false);
     public static final CachedFlag sQueryTiles = new CachedFlag(QUERY_TILES, false);
diff --git a/chrome/browser/lacros/input_method_lacros_browsertest.cc b/chrome/browser/lacros/input_method_lacros_browsertest.cc
index 47da4b74..c9be4787 100644
--- a/chrome/browser/lacros/input_method_lacros_browsertest.cc
+++ b/chrome/browser/lacros/input_method_lacros_browsertest.cc
@@ -140,34 +140,53 @@
   return ExecJs(web_content, script);
 }
 
-mojom::KeyEventPtr CreateKeyPressEvent(uint32_t dom_key, ui::DomCode dom_code) {
-  return mojom::KeyEvent::New(
-      mojom::KeyEventType::kKeyPress,
-      static_cast<int>(ui::DomKey::FromCharacter(dom_key)),
-      static_cast<int>(dom_code),
-      static_cast<int>(ui::KeyboardCode::VKEY_UNKNOWN));
+mojom::KeyEventPtr CreateKeyPressEvent(ui::DomKey dom_key,
+                                       ui::DomCode dom_code) {
+  return mojom::KeyEvent::New(mojom::KeyEventType::kKeyPress,
+                              static_cast<int>(dom_key),
+                              static_cast<int>(dom_code),
+                              static_cast<int>(ui::KeyboardCode::VKEY_UNKNOWN));
 }
 
-mojom::KeyEventPtr CreateKeyReleaseEvent(uint32_t dom_key,
+mojom::KeyEventPtr CreateKeyReleaseEvent(ui::DomKey dom_key,
                                          ui::DomCode dom_code) {
-  return mojom::KeyEvent::New(
-      mojom::KeyEventType::kKeyRelease,
-      static_cast<int>(ui::DomKey::FromCharacter(dom_key)),
-      static_cast<int>(dom_code),
-      static_cast<int>(ui::KeyboardCode::VKEY_UNKNOWN));
+  return mojom::KeyEvent::New(mojom::KeyEventType::kKeyRelease,
+                              static_cast<int>(dom_key),
+                              static_cast<int>(dom_code),
+                              static_cast<int>(ui::KeyboardCode::VKEY_UNKNOWN));
 }
 
-// Send the key event to the input method. The input method will not handle the
-// given key event.
+std::vector<mojom::KeyEventPtr> CreateKeyPressAndReleaseEvents(
+    ui::DomKey dom_key,
+    ui::DomCode dom_code) {
+  std::vector<mojom::KeyEventPtr> key_events;
+  key_events.push_back(CreateKeyPressEvent(dom_key, dom_code));
+  key_events.push_back(CreateKeyReleaseEvent(dom_key, dom_code));
+  return key_events;
+}
+
+// Sends the key events to the input method. The input method will not handle
+// the given key events.
+void SendKeyEventsSync(
+    InputMethodTestInterfaceAsyncWaiter& input_method_async_waiter,
+    std::vector<mojom::KeyEventPtr> key_events) {
+  uint64_t key_event_id;
+  for (mojom::KeyEventPtr& key_event : key_events) {
+    input_method_async_waiter.SendKeyEvent(std::move(key_event), &key_event_id);
+    input_method_async_waiter.KeyEventHandled(key_event_id, false);
+  }
+}
+
+// Convenient version of `SendKeyEventsSync` for a single key event.
 void SendKeyEventSync(
     InputMethodTestInterfaceAsyncWaiter& input_method_async_waiter,
     mojom::KeyEventPtr key_event) {
-  uint64_t key_event_id;
-  input_method_async_waiter.SendKeyEvent(std::move(key_event), &key_event_id);
-  input_method_async_waiter.KeyEventHandled(key_event_id, false);
+  std::vector<mojom::KeyEventPtr> key_events;
+  key_events.push_back(std::move(key_event));
+  SendKeyEventsSync(input_method_async_waiter, std::move(key_events));
 }
 
-// Send the key event to the input method. The input method will handle the
+// Sends the key event to the input method. The input method will handle the
 // given key event by running `callback`.
 void SendKeyEventAsync(
     InputMethodTestInterfaceAsyncWaiter& input_method_async_waiter,
@@ -418,18 +437,15 @@
       input_method.get());
   input_method_async_waiter.WaitForFocus();
 
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('a', ui::DomCode::US_A));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('a', ui::DomCode::US_A));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('b', ui::DomCode::US_B));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('b', ui::DomCode::US_B));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('c', ui::DomCode::US_C));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('c', ui::DomCode::US_C));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(
+                        ui::DomKey::FromCharacter('a'), ui::DomCode::US_A));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(
+                        ui::DomKey::FromCharacter('b'), ui::DomCode::US_B));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(
+                        ui::DomKey::FromCharacter('c'), ui::DomCode::US_C));
 
   EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
                                          "abc", gfx::Range(3)));
@@ -452,24 +468,21 @@
       input_method.get());
   input_method_async_waiter.WaitForFocus();
 
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('\b', ui::DomCode::BACKSPACE));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('\b', ui::DomCode::BACKSPACE));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(ui::DomKey::BACKSPACE,
+                                                   ui::DomCode::BACKSPACE));
   EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
                                          "helo", gfx::Range(2)));
 
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('\b', ui::DomCode::BACKSPACE));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('\b', ui::DomCode::BACKSPACE));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(ui::DomKey::BACKSPACE,
+                                                   ui::DomCode::BACKSPACE));
   EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
                                          "hlo", gfx::Range(1)));
 
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyPressEvent('\b', ui::DomCode::BACKSPACE));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('\b', ui::DomCode::BACKSPACE));
+  SendKeyEventsSync(input_method_async_waiter,
+                    CreateKeyPressAndReleaseEvents(ui::DomKey::BACKSPACE,
+                                                   ui::DomCode::BACKSPACE));
   EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
                                          "lo", gfx::Range(0)));
 }
@@ -492,14 +505,16 @@
   input_method_async_waiter.WaitForFocus();
 
   SendKeyEventAsync(
-      input_method_async_waiter, CreateKeyPressEvent('g', ui::DomCode::US_A),
+      input_method_async_waiter,
+      CreateKeyPressEvent(ui::DomKey::FromCharacter('g'), ui::DomCode::US_G),
       base::BindOnce(
           [](InputMethodTestInterfaceAsyncWaiter& input_method_async_waiter) {
             input_method_async_waiter.SetComposition("ã…Ž", 1);
             return true;
           }));
-  SendKeyEventSync(input_method_async_waiter,
-                   CreateKeyReleaseEvent('g', ui::DomCode::US_A));
+  SendKeyEventSync(
+      input_method_async_waiter,
+      CreateKeyReleaseEvent(ui::DomKey::FromCharacter('g'), ui::DomCode::US_G));
 
   EXPECT_TRUE(WaitUntilInputFieldHasText(GetActiveWebContents(browser()), id,
                                          "ã…Ž", gfx::Range(1)));
diff --git a/chrome/browser/lacros/ui_metric_recorder_lacros.cc b/chrome/browser/lacros/ui_metric_recorder_lacros.cc
index 785a1583..145ccb5 100644
--- a/chrome/browser/lacros/ui_metric_recorder_lacros.cc
+++ b/chrome/browser/lacros/ui_metric_recorder_lacros.cc
@@ -10,9 +10,15 @@
 UiMetricRecorderLacros::~UiMetricRecorderLacros() = default;
 
 void UiMetricRecorderLacros::ReportPercentDroppedFramesInOneSecondWindow(
-    double percentage) {
+    double percent) {
   UMA_HISTOGRAM_PERCENTAGE(
-      "Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow", percentage);
+      "Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow", percent);
+}
+
+void UiMetricRecorderLacros::ReportPercentDroppedFramesInOneSecondWindow2(
+    double percent) {
+  UMA_HISTOGRAM_PERCENTAGE(
+      "Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow2", percent);
 }
 
 // A stub method for CustomMetricRecorder::ReportEventLatency.
diff --git a/chrome/browser/lacros/ui_metric_recorder_lacros.h b/chrome/browser/lacros/ui_metric_recorder_lacros.h
index 03a97f6..1b235ea8 100644
--- a/chrome/browser/lacros/ui_metric_recorder_lacros.h
+++ b/chrome/browser/lacros/ui_metric_recorder_lacros.h
@@ -14,7 +14,8 @@
   ~UiMetricRecorderLacros() override;
 
   // cc::CustomMetricRecorder:
-  void ReportPercentDroppedFramesInOneSecondWindow(double percentage) override;
+  void ReportPercentDroppedFramesInOneSecondWindow(double percent) override;
+  void ReportPercentDroppedFramesInOneSecondWindow2(double percent) override;
   void ReportEventLatency(
       std::vector<cc::EventLatencyTracker::LatencyData> latencies) override;
 };
diff --git a/chrome/browser/logging_chrome_unittest.cc b/chrome/browser/logging_chrome_unittest.cc
index 2e89407..9c3f964c 100644
--- a/chrome/browser/logging_chrome_unittest.cc
+++ b/chrome/browser/logging_chrome_unittest.cc
@@ -55,42 +55,83 @@
   base::FilePath filename = logging::GetLogFileName(cmd_line());
   ASSERT_NE(base::FilePath::StringType::npos,
             filename.value().find(FILE_PATH_LITERAL("chrome_debug.log")));
+#if BUILDFLAG(IS_WIN)
+  ASSERT_TRUE(filename.IsAbsolute());
+#endif  // BUILDFLAG(IS_WIN)
 
   RestoreEnvironmentVariable();
 }
 
 // Tests the log file name getter with an environment variable.
+#if BUILDFLAG(IS_WIN)
 TEST_F(ChromeLoggingTest, EnvironmentLogFileName) {
-  SaveEnvironmentVariable("test env value");
-
+  SaveEnvironmentVariable("c:\\path\\test env value");
   base::FilePath filename = logging::GetLogFileName(cmd_line());
-  ASSERT_EQ(base::FilePath(FILE_PATH_LITERAL("test env value")).value(),
-            filename.value());
-
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test env value")));
+  ASSERT_TRUE(filename.IsAbsolute());
   RestoreEnvironmentVariable();
 }
+#else
+TEST_F(ChromeLoggingTest, EnvironmentLogFileName) {
+  SaveEnvironmentVariable("test env value");
+  base::FilePath filename = logging::GetLogFileName(cmd_line());
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test env value")));
+  RestoreEnvironmentVariable();
+}
+#endif  // BUILDFLAG(IS_WIN)
 
 // Tests the log file name getter with a command-line flag.
+#if BUILDFLAG(IS_WIN)
+TEST_F(ChromeLoggingTest, FlagLogFileName) {
+  SetLogFileFlag("c:\\path\\test flag value");
+  base::FilePath filename = logging::GetLogFileName(cmd_line());
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test flag value")));
+  ASSERT_TRUE(filename.IsAbsolute());
+}
+// Non-absolute path falls back to default.
+TEST_F(ChromeLoggingTest, FlagLogFileNameNonAbsolute) {
+  SetLogFileFlag("test file value");
+  base::FilePath filename = logging::GetLogFileName(cmd_line());
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("chrome_debug.log")));
+  ASSERT_TRUE(filename.IsAbsolute());
+}
+#else
 TEST_F(ChromeLoggingTest, FlagLogFileName) {
   SetLogFileFlag("test flag value");
-
   base::FilePath filename = logging::GetLogFileName(cmd_line());
-  ASSERT_EQ(base::FilePath(FILE_PATH_LITERAL("test flag value")).value(),
-            filename.value());
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test flag value")));
 }
+#endif  // BUILDFLAG(IS_WIN)
 
 // Tests the log file name getter with with an environment variable and a
 // command-line flag. The flag takes precedence.
+#if BUILDFLAG(IS_WIN)
+TEST_F(ChromeLoggingTest, EnvironmentAndFlagLogFileName) {
+  SaveEnvironmentVariable("c:\\path\\test env value");
+  SetLogFileFlag("d:\\path\\test flag value");
+
+  base::FilePath filename = logging::GetLogFileName(cmd_line());
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test flag value")));
+  ASSERT_TRUE(filename.IsAbsolute());
+  RestoreEnvironmentVariable();
+}
+#else
 TEST_F(ChromeLoggingTest, EnvironmentAndFlagLogFileName) {
   SaveEnvironmentVariable("test env value");
   SetLogFileFlag("test flag value");
 
   base::FilePath filename = logging::GetLogFileName(cmd_line());
-  ASSERT_EQ(base::FilePath(FILE_PATH_LITERAL("test flag value")).value(),
-            filename.value());
-
+  ASSERT_NE(base::FilePath::StringType::npos,
+            filename.value().find(FILE_PATH_LITERAL("test flag value")));
   RestoreEnvironmentVariable();
 }
+#endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ChromeLoggingTest, TimestampedName) {
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
index faa7c969..221084af 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
@@ -43,11 +43,16 @@
     return;
   }
 
-  pref_change_registrar_.Init(profile_->GetPrefs());
-  pref_change_registrar_.Add(
-      prefs::kSafeBrowsingScoutReportingEnabled,
+  base::RepeatingClosure refresh_state_callback =
       base::BindRepeating(&TrialComparisonCertVerifierController::RefreshState,
-                          base::Unretained(this)));
+                          base::Unretained(this));
+  pref_change_registrar_.Init(profile_->GetPrefs());
+  pref_change_registrar_.Add(prefs::kSafeBrowsingEnabled,
+                             refresh_state_callback);
+  pref_change_registrar_.Add(prefs::kSafeBrowsingEnhanced,
+                             refresh_state_callback);
+  pref_change_registrar_.Add(prefs::kSafeBrowsingScoutReportingEnabled,
+                             refresh_state_callback);
 }
 
 TrialComparisonCertVerifierController::
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
index 625ca9e..0e528b9 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
@@ -98,7 +98,8 @@
       receiver_;
 };
 
-class TrialComparisonCertVerifierControllerTest : public testing::Test {
+class TrialComparisonCertVerifierControllerTest
+    : public testing::TestWithParam<bool> {
  public:
   void SetUp() override {
     cert_chain_1_ = CreateCertificateChainFromFile(
@@ -148,6 +149,21 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void SetExtendedReportingPref(bool enabled) {
+    if (GetParam()) {
+      // SetEnhancedProtectionPrefForTests sets both kSafeBrowsingEnabled and
+      // kSafeBrowsingEnhanced.
+      safe_browsing::SetEnhancedProtectionPrefForTests(pref_service(), enabled);
+    } else {
+      // SetExtendedReportingPrefForTests only sets
+      // kSafeBrowsingScoutReportingEnabled, so first set kSafeBrowsingEnabled.
+      // Keeping this consistent between the branches makes the test conditions
+      // easier to write.
+      safe_browsing::SetStandardProtectionPref(pref_service(), enabled);
+      safe_browsing::SetExtendedReportingPrefForTests(pref_service(), enabled);
+    }
+  }
+
   void CreateController(Profile* profile) {
     mojo::PendingRemote<
         cert_verifier::mojom::TrialComparisonCertVerifierConfigClient>
@@ -228,7 +244,7 @@
       mock_config_client_;
 };
 
-TEST_F(TrialComparisonCertVerifierControllerTest, NothingEnabled) {
+TEST_P(TrialComparisonCertVerifierControllerTest, NothingEnabled) {
   CreateController();
 
   // Trial should not be allowed.
@@ -236,7 +252,7 @@
 
   // Enable the SBER pref, shouldn't matter since it's a non-official build and
   // field trial isn't enabled.
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial still not allowed, and OnTrialConfigUpdated should not be called
   // either.
@@ -253,13 +269,13 @@
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest,
+TEST_P(TrialComparisonCertVerifierControllerTest,
        OfficialBuildTrialNotEnabled) {
   TrialComparisonCertVerifierController::SetFakeOfficialBuildForTesting(true);
   CreateController();
 
   EXPECT_FALSE(trial_controller().IsAllowed());
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial still not allowed, and OnTrialConfigUpdated should not be called
   // either.
@@ -278,7 +294,7 @@
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest,
+TEST_P(TrialComparisonCertVerifierControllerTest,
        NotOfficialBuildTrialEnabled) {
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
@@ -301,7 +317,7 @@
   // In a real official build, expect the trial config to be updated.
   EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(true)).Times(1);
 #endif
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
 #if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // In a real official build, expect the trial to be allowed now.  (Don't
@@ -327,7 +343,7 @@
 #endif
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest, OfficialBuildTrialEnabled) {
+TEST_P(TrialComparisonCertVerifierControllerTest, OfficialBuildTrialEnabled) {
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
     // If ChromeRootStoreUsed feature is enabled by default,
@@ -349,8 +365,9 @@
 
   // Enable the SBER pref, which should trigger the OnTrialConfigUpdated
   // callback.
+  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(1);
   EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(true)).Times(1);
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial should now be allowed.
   EXPECT_TRUE(trial_controller().IsAllowed());
@@ -401,8 +418,8 @@
 
   // Disable the SBER pref again, which should trigger the OnTrialConfigUpdated
   // callback.
-  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(1);
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), false);
+  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(2);
+  SetExtendedReportingPref(false);
 
   // Not allowed now.
   EXPECT_FALSE(trial_controller().IsAllowed());
@@ -418,7 +435,7 @@
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest,
+TEST_P(TrialComparisonCertVerifierControllerTest,
        OfficialBuildTrialEnabledTwoClients) {
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
@@ -456,9 +473,12 @@
 
   // Enable the SBER pref, which should trigger the OnTrialConfigUpdated
   // callback.
+  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(1);
   EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(true)).Times(1);
+
+  EXPECT_CALL(mock_config_client_2, OnTrialConfigUpdated(false)).Times(1);
   EXPECT_CALL(mock_config_client_2, OnTrialConfigUpdated(true)).Times(1);
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial should now be allowed.
   EXPECT_TRUE(trial_controller().IsAllowed());
@@ -516,9 +536,9 @@
 
   // Disable the SBER pref again, which should trigger the OnTrialConfigUpdated
   // callback.
-  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(1);
-  EXPECT_CALL(mock_config_client_2, OnTrialConfigUpdated(false)).Times(1);
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), false);
+  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(2);
+  EXPECT_CALL(mock_config_client_2, OnTrialConfigUpdated(false)).Times(2);
+  SetExtendedReportingPref(false);
 
   // Not allowed now.
   EXPECT_FALSE(trial_controller().IsAllowed());
@@ -538,7 +558,7 @@
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest,
+TEST_P(TrialComparisonCertVerifierControllerTest,
        OfficialBuildTrialEnabledUmaOnly) {
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
@@ -561,8 +581,9 @@
 
   // Enable the SBER pref, which should trigger the OnTrialConfigUpdated
   // callback.
+  EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(false)).Times(1);
   EXPECT_CALL(mock_config_client(), OnTrialConfigUpdated(true)).Times(1);
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial should now be allowed.
   EXPECT_TRUE(trial_controller().IsAllowed());
@@ -585,7 +606,7 @@
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
 
-TEST_F(TrialComparisonCertVerifierControllerTest,
+TEST_P(TrialComparisonCertVerifierControllerTest,
        IncognitoOfficialBuildTrialEnabled) {
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
@@ -607,7 +628,7 @@
   EXPECT_FALSE(trial_controller().IsAllowed());
 
   // Enable the SBER pref, shouldn't matter since it's an incognito profile.
-  safe_browsing::SetExtendedReportingPrefForTests(pref_service(), true);
+  SetExtendedReportingPref(true);
 
   // Trial still not allowed, and OnTrialConfigUpdated should not be called
   // either.
@@ -623,3 +644,7 @@
   // Expect no report since the trial is not allowed.
   reporting_service_test_helper()->ExpectNoRequests(reporting_service());
 }
+
+INSTANTIATE_TEST_SUITE_P(Impl,
+                         TrialComparisonCertVerifierControllerTest,
+                         testing::Bool());
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
index abd30ae..ea0ced3 100644
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
@@ -125,7 +125,8 @@
     "MainFrame";
 
 const char kHistogramFromGWSMaxCumulativeShiftScoreSessionWindow[] =
-    "PageLoad.LayoutInstability.MaxCumulativeShiftScore.SessionWindow.Gap1000ms"
+    "PageLoad.Clients.FromGoogleSearch.LayoutInstability."
+    "MaxCumulativeShiftScore.SessionWindow.Gap1000ms"
     ".Max5000ms2";
 
 const char kHistogramFromGWSFromSidePanelFirstInputDelay[] =
diff --git a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
index 21c91ee0..c81a725 100644
--- a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
+++ b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
@@ -14,6 +14,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.PostTask;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
@@ -204,14 +205,23 @@
                     CustomizationProviderDelegateImpl delegate =
                             new CustomizationProviderDelegateImpl();
 
+                    if (ChromeFeatureList.sPartnerHomepageInitialLoadImprovement.isEnabled()) {
+                        // Refresh the homepage first, as it has potential impact on the URL to use
+                        // for the initial tab.
+                        if (isCancelled()) return null;
+                        mHomepageUriChanged = refreshHomepage(delegate);
+                    }
+
                     if (isCancelled()) return null;
                     refreshIncognitoModeDisabled(delegate);
 
                     if (isCancelled()) return null;
                     refreshBookmarksEditingDisabled(delegate);
 
-                    if (isCancelled()) return null;
-                    mHomepageUriChanged = refreshHomepage(delegate);
+                    if (!ChromeFeatureList.sPartnerHomepageInitialLoadImprovement.isEnabled()) {
+                        if (isCancelled()) return null;
+                        mHomepageUriChanged = refreshHomepage(delegate);
+                    }
                 } catch (Exception e) {
                     Log.w(TAG, "Fetching partner customizations failed", e);
                 }
diff --git a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
index ebc9fc8d..986ab342 100644
--- a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
+++ b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.cc
@@ -161,27 +161,27 @@
   FrozenDataImpl::GetOrCreate(page_impl);
 }
 
-base::Value FrozenFrameAggregator::DescribePageNodeData(
+base::Value::Dict FrozenFrameAggregator::DescribePageNodeData(
     const PageNode* node) const {
   FrozenDataImpl* data = FrozenDataImpl::Get(PageNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
-  ret.SetIntKey("current_frame_count", data->current_frame_count);
-  ret.SetIntKey("frozen_frame_count", data->frozen_frame_count);
+  base::Value::Dict ret;
+  ret.Set("current_frame_count", static_cast<int>(data->current_frame_count));
+  ret.Set("frozen_frame_count", static_cast<int>(data->frozen_frame_count));
   return ret;
 }
 
-base::Value FrozenFrameAggregator::DescribeProcessNodeData(
+base::Value::Dict FrozenFrameAggregator::DescribeProcessNodeData(
     const ProcessNode* node) const {
   FrozenDataImpl* data = FrozenDataImpl::Get(ProcessNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
-  ret.SetIntKey("current_frame_count", data->current_frame_count);
-  ret.SetIntKey("frozen_frame_count", data->frozen_frame_count);
+  base::Value::Dict ret;
+  ret.Set("current_frame_count", static_cast<int>(data->current_frame_count));
+  ret.Set("frozen_frame_count", static_cast<int>(data->frozen_frame_count));
   return ret;
 }
 
diff --git a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h
index 442963d5..668772e 100644
--- a/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h
+++ b/chrome/browser/performance_manager/decorators/frozen_frame_aggregator.h
@@ -52,8 +52,9 @@
   void OnPageNodeAdded(const PageNode* page_node) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
 
  protected:
   friend class FrozenFrameAggregatorTest;
diff --git a/chrome/browser/performance_manager/decorators/page_aggregator.cc b/chrome/browser/performance_manager/decorators/page_aggregator.cc
index a3d83a08..d9774e4b 100644
--- a/chrome/browser/performance_manager/decorators/page_aggregator.cc
+++ b/chrome/browser/performance_manager/decorators/page_aggregator.cc
@@ -243,18 +243,19 @@
   graph->RemoveFrameNodeObserver(this);
 }
 
-base::Value PageAggregator::DescribePageNodeData(const PageNode* node) const {
+base::Value::Dict PageAggregator::DescribePageNodeData(
+    const PageNode* node) const {
   Data* data = Data::Get(PageNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
-  ret.SetIntKey("num_frames_holding_web_lock",
-                data->num_frames_holding_web_lock_);
-  ret.SetIntKey("num_frames_holding_indexeddb_lock",
-                data->num_frames_holding_web_lock_);
-  ret.SetIntKey("num_current_frames_with_form_interaction",
-                data->num_current_frames_with_form_interaction_);
+  base::Value::Dict ret;
+  ret.Set("num_frames_holding_web_lock",
+          static_cast<int>(data->num_frames_holding_web_lock_));
+  ret.Set("num_frames_holding_indexeddb_lock",
+          static_cast<int>(data->num_frames_holding_web_lock_));
+  ret.Set("num_current_frames_with_form_interaction",
+          static_cast<int>(data->num_current_frames_with_form_interaction_));
   return ret;
 }
 
diff --git a/chrome/browser/performance_manager/decorators/page_aggregator.h b/chrome/browser/performance_manager/decorators/page_aggregator.h
index 43127a3..0c6092f8 100644
--- a/chrome/browser/performance_manager/decorators/page_aggregator.h
+++ b/chrome/browser/performance_manager/decorators/page_aggregator.h
@@ -45,7 +45,7 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/decorators/process_priority_aggregator.cc b/chrome/browser/performance_manager/decorators/process_priority_aggregator.cc
index 9dc66e5..4d14bf2 100644
--- a/chrome/browser/performance_manager/decorators/process_priority_aggregator.cc
+++ b/chrome/browser/performance_manager/decorators/process_priority_aggregator.cc
@@ -147,15 +147,15 @@
   graph->RemoveGraphObserver(this);
 }
 
-base::Value ProcessPriorityAggregator::DescribeProcessNodeData(
+base::Value::Dict ProcessPriorityAggregator::DescribeProcessNodeData(
     const ProcessNode* node) const {
   DataImpl* data = DataImpl::Get(ProcessNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
-  ret.SetIntKey("user_visible_count", data->user_visible_count_);
-  ret.SetIntKey("user_blocking_count", data->user_blocking_count_);
+  base::Value::Dict ret;
+  ret.Set("user_visible_count", static_cast<int>(data->user_visible_count_));
+  ret.Set("user_blocking_count", static_cast<int>(data->user_blocking_count_));
   return ret;
 }
 
diff --git a/chrome/browser/performance_manager/decorators/process_priority_aggregator.h b/chrome/browser/performance_manager/decorators/process_priority_aggregator.h
index 308a2c2..e43b787 100644
--- a/chrome/browser/performance_manager/decorators/process_priority_aggregator.h
+++ b/chrome/browser/performance_manager/decorators/process_priority_aggregator.h
@@ -44,7 +44,8 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
 
   // ProcessNodeObserver implementation:
   void OnProcessNodeAdded(const ProcessNode* process_node) override;
diff --git a/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc b/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc
index 544574c..e3833f17e 100644
--- a/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc
+++ b/chrome/browser/performance_manager/policies/background_tab_loading_policy.cc
@@ -292,28 +292,27 @@
   }
 };
 
-base::Value BackgroundTabLoadingPolicy::DescribePageNodeData(
+base::Value::Dict BackgroundTabLoadingPolicy::DescribePageNodeData(
     const PageNode* node) const {
-  base::Value dict(base::Value::Type::DICT);
+  base::Value::Dict dict;
   if (base::Contains(page_nodes_load_initiated_, node)) {
     // Transient state between InitiateLoad() and OnLoadingStateChanged(),
     // shouldn't be sticking around for long.
-    dict.SetBoolKey("page_load_initiated", true);
+    dict.Set("page_load_initiated", true);
   }
   if (base::Contains(page_nodes_loading_, node)) {
-    dict.SetBoolKey("page_loading", true);
+    dict.Set("page_loading", true);
   }
-  return !dict.DictEmpty() ? std::move(dict) : base::Value();
+  return !dict.empty() ? std::move(dict) : base::Value::Dict();
 }
 
-base::Value BackgroundTabLoadingPolicy::DescribeSystemNodeData(
+base::Value::Dict BackgroundTabLoadingPolicy::DescribeSystemNodeData(
     const SystemNode* node) const {
-  base::Value dict(base::Value::Type::DICT);
-  dict.SetIntKey("max_simultaneous_tab_loads",
-                 base::saturated_cast<int>(max_simultaneous_tab_loads_));
-  dict.SetIntKey("tab_loads_started",
-                 base::saturated_cast<int>(tab_loads_started_));
-  dict.SetIntKey("tabs_scored", base::saturated_cast<int>(tabs_scored_));
+  base::Value::Dict dict;
+  dict.Set("max_simultaneous_tab_loads",
+           base::saturated_cast<int>(max_simultaneous_tab_loads_));
+  dict.Set("tab_loads_started", base::saturated_cast<int>(tab_loads_started_));
+  dict.Set("tabs_scored", base::saturated_cast<int>(tabs_scored_));
   return dict;
 }
 
diff --git a/chrome/browser/performance_manager/policies/background_tab_loading_policy.h b/chrome/browser/performance_manager/policies/background_tab_loading_policy.h
index f976f88..bcb3024 100644
--- a/chrome/browser/performance_manager/policies/background_tab_loading_policy.h
+++ b/chrome/browser/performance_manager/policies/background_tab_loading_policy.h
@@ -113,8 +113,9 @@
   struct ScoredTabComparator;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
-  base::Value DescribeSystemNodeData(const SystemNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribeSystemNodeData(
+      const SystemNode* node) const override;
 
   // SystemNodeObserver:
   void OnMemoryPressure(
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper.cc b/chrome/browser/performance_manager/policies/page_discarding_helper.cc
index e7f5637a..ed49a7b7 100644
--- a/chrome/browser/performance_manager/policies/page_discarding_helper.cc
+++ b/chrome/browser/performance_manager/policies/page_discarding_helper.cc
@@ -400,14 +400,14 @@
   return !it->second->MatchURL(url).empty();
 }
 
-base::Value PageDiscardingHelper::DescribePageNodeData(
+base::Value::Dict PageDiscardingHelper::DescribePageNodeData(
     const PageNode* node) const {
   auto* data = DiscardAttemptMarker::Get(PageNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
-  ret.SetKey("has_discard_attempt_marker", base::Value("true"));
+  base::Value::Dict ret;
+  ret.Set("has_discard_attempt_marker", base::Value("true"));
 
   return ret;
 }
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper.h b/chrome/browser/performance_manager/policies/page_discarding_helper.h
index e795b525..564a527f 100644
--- a/chrome/browser/performance_manager/policies/page_discarding_helper.h
+++ b/chrome/browser/performance_manager/policies/page_discarding_helper.h
@@ -147,7 +147,7 @@
                                   const GURL& url) const;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
 
   // Called after each discard attempt. |success| will indicate whether or not
   // the attempt has been successful. |post_discard_cb| will be called once
diff --git a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
index f43376a..b377a605 100644
--- a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
+++ b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.cc
@@ -101,16 +101,16 @@
   return false;
 }
 
-base::Value WorkingSetTrimmerPolicy::DescribeProcessNodeData(
+base::Value::Dict WorkingSetTrimmerPolicy::DescribeProcessNodeData(
     const ProcessNode* node) const {
   auto* data = WorkingSetTrimData::Get(ProcessNodeImpl::FromNode(node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
-  base::Value ret(base::Value::Type::DICT);
+  base::Value::Dict ret;
   auto last_trim_age = base::TimeTicks::Now() - data->last_trim_;
 
-  ret.SetKey(
+  ret.Set(
       "last_trim",
       base::Value(base::StrCat(
           {base::NumberToString(last_trim_age.InSeconds()), " seconds ago"})));
diff --git a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.h b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.h
index 0e3c243..9b62cde2 100644
--- a/chrome/browser/performance_manager/policies/working_set_trimmer_policy.h
+++ b/chrome/browser/performance_manager/policies/working_set_trimmer_policy.h
@@ -82,7 +82,8 @@
   void SetLastTrimTime(const ProcessNode* process_node, base::TimeTicks time);
 
   // NodeDataDescriber implementation:
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
 };
 
 }  // namespace policies
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragmentV3Test.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragmentV3Test.java
index dced11e..da49df41 100644
--- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragmentV3Test.java
+++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSettingsFragmentV3Test.java
@@ -60,6 +60,7 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.components.browser_ui.settings.SettingsFeatureList;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.RenderTestRule;
@@ -69,9 +70,7 @@
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 
-/**
- * Tests {@link PrivacySandboxSettingsFragment}.
- */
+/** Tests {@link PrivacySandboxSettingsFragment}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@@ -156,7 +155,9 @@
     @Test
     @SmallTest
     @Feature({"RenderTest"})
-    public void testRenderMainPage() throws IOException {
+    @Features.EnableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
+    public void testRenderMainPage_EnableHighlightManagedPrefDisclaimerAndroid()
+            throws IOException {
         openPrivacySandboxSettings();
         mRenderTestRule.render(
                 getRootView(R.string.privacy_sandbox_trials_title), "privacy_sandbox_main_view");
@@ -165,6 +166,17 @@
     @Test
     @SmallTest
     @Feature({"RenderTest"})
+    @Features.DisableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
+    public void testRenderMainPage_DisableHighlightManagedPrefDisclaimerAndroid()
+            throws IOException {
+        openPrivacySandboxSettings();
+        mRenderTestRule.render(getRootView(R.string.privacy_sandbox_trials_title),
+                "privacy_sandbox_main_view_DisableHighlightManagedPrefDisclaimerAndroid");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest"})
     public void testRenderAdPersonalizationView() throws IOException {
         mFakePrivacySandboxBridge.setCurrentTopTopics("Generated sample data", "More made up data");
         mFakePrivacySandboxBridge.setCurrentFledgeSites("a.com", "b.com");
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/v4/AdMeasurementFragmentV4Test.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/v4/AdMeasurementFragmentV4Test.java
index f3a46d9..8a54f19 100644
--- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/v4/AdMeasurementFragmentV4Test.java
+++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/v4/AdMeasurementFragmentV4Test.java
@@ -45,8 +45,10 @@
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
-import org.chromium.components.policy.test.annotations.Policies;
+import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.components.browser_ui.settings.SettingsFeatureList;
+import org.chromium.components.policy.test.annotations.Policies;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -55,9 +57,7 @@
 
 import java.io.IOException;
 
-/**
- * Tests {@link AdMeasurementFragmentV4}
- */
+/** Tests {@link AdMeasurementFragmentV4} */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@@ -124,8 +124,10 @@
 
     @Test
     @SmallTest
+    @EnableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
     @Feature({"RenderTest"})
-    public void testRenderAdMeasurement() throws IOException {
+    public void testRenderAdMeasurement_EnableHighlightManagedPrefDisclaimerAndroid()
+            throws IOException {
         setAdMeasurementPrefEnabled(true);
         startAdMeasuremenSettings();
         mRenderTestRule.render(getRootView(R.string.settings_ad_measurement_page_toggle_sub_label),
@@ -134,6 +136,18 @@
 
     @Test
     @SmallTest
+    @DisableFeatures(SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID)
+    @Feature({"RenderTest"})
+    public void testRenderAdMeasurement_DisableHighlightManagedPrefDisclaimerAndroid()
+            throws IOException {
+        setAdMeasurementPrefEnabled(true);
+        startAdMeasuremenSettings();
+        mRenderTestRule.render(getRootView(R.string.settings_ad_measurement_page_toggle_sub_label),
+                "ad_measurement_page_toggle_on_DisableHighlightManagedPrefDisclaimerAndroid");
+    }
+
+    @Test
+    @SmallTest
     public void testToggleUncheckedWhenAdMeasurementOff() {
         setAdMeasurementPrefEnabled(false);
         startAdMeasuremenSettings();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
index c93b1c2..e03d5fb 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
@@ -7,8 +7,6 @@
  */
 import {BrailleKeyEvent} from '../../common/braille/braille_key_types.js';
 import {NavBraille} from '../../common/braille/nav_braille.js';
-import {BridgeConstants} from '../../common/bridge_constants.js';
-import {BridgeHelper} from '../../common/bridge_helper.js';
 import {LogType} from '../../common/log_types.js';
 import {SettingsManager} from '../../common/settings_manager.js';
 import {ChromeVoxState} from '../chromevox_state.js';
@@ -20,9 +18,6 @@
 import {BrailleKeyEventRewriter} from './braille_key_event_rewriter.js';
 import {BrailleTranslatorManager} from './braille_translator_manager.js';
 
-const Action = BridgeConstants.BrailleBackground.Action;
-const TARGET = BridgeConstants.BrailleBackground.TARGET;
-
 /** @implements {BrailleInterface} */
 export class BrailleBackground {
   /**
@@ -64,8 +59,8 @@
   static init() {
     BrailleBackground.instance = new BrailleBackground();
 
-    BridgeHelper.registerHandler(
-        TARGET, Action.REFRESH_BRAILLE_TABLE,
+    SettingsManager.addListenerForKey(
+        'brailleTable',
         brailleTable =>
             BrailleBackground.instance.getTranslatorManager().refresh(
                 brailleTable));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js
index fee128b..aa399b6 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js
@@ -42,7 +42,6 @@
     });
 
 BridgeHelper.registerHandler(
-    BridgeConstants.BrailleBackground.TARGET,
-    BridgeConstants.BrailleBackground.Action.WRITE,
+    BridgeConstants.Braille.TARGET, BridgeConstants.Braille.Action.WRITE,
     text =>
         ChromeVox.braille.write(new NavBraille({text: new Spannable(text)})));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
index 81fb9a8..3adde0fa7 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
@@ -29,19 +29,6 @@
         BridgeConstants.Braille.TARGET,
         BridgeConstants.Braille.Action.BACK_TRANSLATE, cells);
   },
-};
-
-BackgroundBridge.BrailleBackground = {
-  /**
-   * @param {string} brailleTable The table for this translator to use.
-   * @return {!Promise<boolean>}
-   */
-  async refreshBrailleTable(brailleTable) {
-    return BridgeHelper.sendMessage(
-        BridgeConstants.BrailleBackground.TARGET,
-        BridgeConstants.BrailleBackground.Action.REFRESH_BRAILLE_TABLE,
-        brailleTable);
-  },
 
   /**
    * @param {!string} text The text to write in Braille.
@@ -49,8 +36,8 @@
    */
   async write(text) {
     return BridgeHelper.sendMessage(
-        BridgeConstants.BrailleBackground.TARGET,
-        BridgeConstants.BrailleBackground.Action.WRITE, text);
+        BridgeConstants.Braille.TARGET, BridgeConstants.Braille.Action.WRITE,
+        text);
   },
 };
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
index bad2b832..449e115 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
@@ -39,14 +39,6 @@
   TARGET: 'Braille',
   Action: {
     BACK_TRANSLATE: 'backTranslate',
-  },
-};
-
-/** @public {!BridgeEntry} */
-BridgeConstants.BrailleBackground = {
-  TARGET: 'BrailleBackground',
-  Action: {
-    REFRESH_BRAILLE_TABLE: 'refreshBrailleTable',
     WRITE: 'write',
   },
 };
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
index 39c6857..b8f968e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
@@ -287,7 +287,7 @@
         LearnMode.shouldFlushSpeech_ ? QueueMode.CATEGORY_FLUSH :
                                        QueueMode.QUEUE,
         new TtsSpeechProperties({endCallback: opt_outputCallback}));
-    BackgroundBridge.BrailleBackground.write(text);
+    BackgroundBridge.Braille.write(text);
     LearnMode.shouldFlushSpeech_ = false;
     if (opt_outputCallback) {
       opt_outputCallback();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
index dddfdfe3..f1cf0a8 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
@@ -341,8 +341,6 @@
         const sel = node.options[selIndex];
         SettingsManager.set('brailleTable', sel.id);
         SettingsManager.set(node.id, sel.id);
-        BackgroundBridge.BrailleBackground.refreshBrailleTable(
-            SettingsManager.getString('brailleTable'));
       };
     };
 
@@ -376,8 +374,6 @@
         tableTypeButton.textContent =
             Msgs.getMsg('options_braille_table_type_8');
       }
-      BackgroundBridge.BrailleBackground.refreshBrailleTable(
-          SettingsManager.getString('brailleTable'));
     };
     updateTableType(false);
 
diff --git a/chrome/browser/resources/chromeos/accessibility/common/local_storage.js b/chrome/browser/resources/chromeos/accessibility/common/local_storage.js
index 553d303..a80f35a 100644
--- a/chrome/browser/resources/chromeos/accessibility/common/local_storage.js
+++ b/chrome/browser/resources/chromeos/accessibility/common/local_storage.js
@@ -11,7 +11,7 @@
   constructor(onInit) {
     /** @private {?Object} */
     this.values_ = null;
-    /** @private {!Object<string, Function>} */
+    /** @private {!Object<string, !Array<!Function>>} */
     this.keyCallbacks_ = {};
 
     chrome.storage.local.get(
@@ -42,7 +42,12 @@
    * @param {Function} callback
    */
   static addListenerForKey(key, callback) {
-    LocalStorage.instance.keyCallbacks_[key] = callback;
+    if (!LocalStorage.instance.keyCallbacks_[key]) {
+      LocalStorage.instance.keyCallbacks_[key] = [];
+    }
+    if (callback) {
+      LocalStorage.instance.keyCallbacks_[key].push(callback);
+    }
   }
 
   /**
@@ -158,7 +163,8 @@
     for (const key in updates) {
       this.values_[key] = updates[key].newValue;
       if (this.keyCallbacks_[key]) {
-        this.keyCallbacks_[key](updates[key].newValue);
+        this.keyCallbacks_[key].forEach(
+            callback => callback(updates[key].newValue));
       }
     }
   }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/constants.ts b/chrome/browser/resources/chromeos/emoji_picker/constants.ts
index eff8d2a..d922ca8 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/constants.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/constants.ts
@@ -57,3 +57,31 @@
 // 24 hours is equivalent to 86400000 milliseconds.
 export const TWENTY_FOUR_HOURS = 86400000;
 export const GIF_VALIDATION_DATE = 'gifValidationDate';
+
+export const V2_5_EMOJI_PICKER_SIDE_PADDING = 18;
+export const V2_5_GROUP_ICON_SIZE =
+    (EMOJI_PICKER_WIDTH - 2 * V2_5_EMOJI_PICKER_SIDE_PADDING) / EMOJI_PER_ROW;
+export const V2_5_VISUAL_CONTENT_WIDTH =
+    (EMOJI_PICKER_WIDTH - 2 * V2_5_EMOJI_PICKER_SIDE_PADDING) / 2 -
+    VISUAL_CONTENT_PADDING / 2;
+
+export const V2_5_EMOJI_SPACING =
+    (EMOJI_PICKER_WIDTH - 2 * V2_5_EMOJI_PICKER_SIDE_PADDING -
+     EMOJI_PER_ROW * EMOJI_ICON_SIZE) /
+    (EMOJI_PER_ROW - 1);
+export const V2_5_EMOJI_SPACING_PX = `${V2_5_EMOJI_SPACING}px`;
+export const V2_5_EMOJI_GROUP_SIZE_PX = `${V2_5_GROUP_ICON_SIZE}px`;
+export const V2_5_EMOJI_PICKER_SIDE_PADDING_PX =
+    `${V2_5_EMOJI_PICKER_SIDE_PADDING}px`;
+export const V2_5_VISUAL_CONTENT_WIDTH_PX = `${V2_5_VISUAL_CONTENT_WIDTH}px`;
+
+export const V2_5_EMOJI_GROUP_SPACING =
+    (EMOJI_PICKER_WIDTH - 2 * V2_5_EMOJI_PICKER_SIDE_PADDING -
+     GROUP_PER_ROW * EMOJI_ICON_SIZE) /
+    (GROUP_PER_ROW - 1);
+export const V2_5_EMOJI_PICKER_TOTAL_EMOJI_WIDTH =
+    EMOJI_ICON_SIZE + V2_5_EMOJI_GROUP_SPACING;
+
+export const V2_5_EMOJI_GROUP_SPACING_PX = `${V2_5_EMOJI_GROUP_SPACING}px`;
+export const V2_5_EMOJI_PICKER_TOTAL_EMOJI_WIDTH_PX =
+    `${V2_5_EMOJI_PICKER_TOTAL_EMOJI_WIDTH}px`;
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
index cd3fb67..bbb9530e 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.ts
@@ -263,10 +263,16 @@
                 )
             .then(values => values[0]);  // Map to the fetched data only.
 
-    this.updateStyles({
-      '--emoji-size': constants.EMOJI_ICON_SIZE_PX,
-      '--emoji-spacing': constants.EMOJI_SPACING_PX,
-    });
+    if (this.gifSupport) {
+      this.updateStyles({
+        '--emoji-group-button-size': constants.V2_5_EMOJI_GROUP_SIZE_PX,
+        '--emoji-picker-side-padding':
+            constants.V2_5_EMOJI_PICKER_SIDE_PADDING_PX,
+        '--emoji-spacing': constants.V2_5_EMOJI_SPACING_PX,
+        '--emoji-group-spacing': constants.V2_5_EMOJI_GROUP_SPACING_PX,
+        '--visual-content-width': constants.V2_5_VISUAL_CONTENT_WIDTH_PX,
+      });
+    }
 
     // Update UI and relevant features based on the initial data.
     this.updateCategoryData(
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 39d895a..b324dd88 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -27,19 +27,35 @@
 # for convenience.
 # -----------------------------------------------------------------------------
 grit("conditional_resources") {
+  defines = chrome_grit_defines
+
   # Needed since some of the files are generated during build time.
   enable_input_discovery_for_gn_analyze = false
 
-  source = "oobe_conditional_resources.grd"
+  source = "$target_gen_dir/oobe_conditional_resources.grd"
   outputs = [
     "grit/oobe_conditional_resources.h",
+    "grit/oobe_conditional_resources_map.h",
+    "grit/oobe_conditional_resources_map.cc",
     "oobe_conditional_resources.pak",
   ]
 
-  deps = [ ":preprocess_conditional" ]
+  deps = [ ":build_oobe_conditional_grd" ]
   output_dir = "$root_gen_dir/chrome"
 }
 
+generate_grd("build_oobe_conditional_grd") {
+  grd_prefix = "oobe_conditional"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  deps = [ ":preprocess_conditional" ]
+  manifest_files = [ "$target_gen_dir/$conditional_files_manifest" ]
+  input_files_base_dir = rebase_path(".", "//")
+  input_files = [
+    "debug/no_debug.js",
+    "test_api/no_test_api.js",
+  ]
+}
+
 # Files that are served conditionally
 preprocess_if_expr("preprocess_conditional") {
   deps = [
diff --git a/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd b/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd
deleted file mode 100644
index 30c556d9..0000000
--- a/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/oobe_conditional_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="oobe_conditional_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <!-- Resources that are dynamically chosen to be served in runtime -->
-      <!-- OOBE Custom CSS Variables -->
-      <include name="IDR_OOBE_COMPONENTS_OOBE_CUSTOM_VARS_CSS_JS" use_base_dir="false" type="chrome_html"
-               file="${root_gen_dir}/chrome/browser/resources/chromeos/login/oobe_preprocessed/components/oobe_vars/oobe_custom_vars.css.js" />
-      <include name="IDR_OOBE_COMPONENTS_OOBE_CUSTOM_VARS_REMORA_CSS_JS" use_base_dir="false" type="chrome_html"
-               file="${root_gen_dir}/chrome/browser/resources/chromeos/login/oobe_preprocessed/components/oobe_vars/oobe_custom_vars_remora.css.js" />
-
-      <!-- OOBE Test API -->
-      <include name="IDR_OOBE_TEST_API_JS" use_base_dir="false" type="chrome_html"
-               file="${root_gen_dir}/chrome/browser/resources/chromeos/login/oobe_preprocessed/test_api/test_api.js" />
-      <include name="IDR_OOBE_TEST_API_STUB_JS" file="test_api/no_test_api.js" type="chrome_html" />
-
-      <!-- OOBE Debugger -->
-      <include name="IDR_OOBE_DEBUGGER_JS" use_base_dir="false" type="chrome_html"
-               file="${root_gen_dir}/chrome/browser/resources/chromeos/login/oobe_preprocessed/debug/debug.js" />
-      <include name="IDR_OOBE_DEBUGGER_STUB_JS" file="debug\no_debug.js" type="chrome_html" />
-
-    </includes>
-  </release>
-</grit>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/OWNERS b/chrome/browser/resources/settings/chromeos/device_page/OWNERS
index 84da6c79..1167dbbe 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/OWNERS
+++ b/chrome/browser/resources/settings/chromeos/device_page/OWNERS
@@ -2,3 +2,4 @@
 zentaro@chromium.org
 michaelcheco@google.com
 dpad@google.com
+gavinwill@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts b/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
index d3731112..42bfd90 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/fake_input_device_data.ts
@@ -23,6 +23,11 @@
         [ModifierKey.META, ModifierKey.VOID],
         [ModifierKey.CAPS_LOCK, ModifierKey.ASSISTANT],
       ]),
+      topRowAreFKeys: false,
+      suppressMetaFKeyRewrites: false,
+      autoRepeatEnabled: false,
+      autoRepeatDelay: 2000,
+      autoRepeatInterval: 2000,
     },
   },
   {
@@ -40,6 +45,11 @@
     ],
     settings: {
       modifierRemappings: new Map<ModifierKey, ModifierKey>(),
+      topRowAreFKeys: true,
+      suppressMetaFKeyRewrites: true,
+      autoRepeatEnabled: true,
+      autoRepeatDelay: 150,
+      autoRepeatInterval: 20,
     },
   },
 ];
@@ -50,12 +60,36 @@
     name: 'Default Touchpad',
     isExternal: false,
     isHaptic: true,
+    settings: {
+      sensitivity: 1,
+      reverseScrolling: false,
+      accelerationEnabled: false,
+      tapToClickEnabled: false,
+      threeFingerClickEnabled: false,
+      tapDraggingEnabled: false,
+      scrollSensitivity: 1,
+      scrollAcceleration: false,
+      hapticSensitivity: 1,
+      hapticEnabled: false,
+    },
   },
   {
     id: 3,
     name: 'Logitech T650',
     isExternal: true,
     isHaptic: false,
+    settings: {
+      sensitivity: 5,
+      reverseScrolling: true,
+      accelerationEnabled: true,
+      tapToClickEnabled: true,
+      threeFingerClickEnabled: true,
+      tapDraggingEnabled: true,
+      scrollSensitivity: 5,
+      scrollAcceleration: true,
+      hapticSensitivity: 5,
+      hapticEnabled: true,
+    },
   },
 ];
 
@@ -64,11 +98,27 @@
     id: 4,
     name: 'Razer Basilisk V3',
     isExternal: true,
+    settings: {
+      swapRight: true,
+      sensitivity: 5,
+      reverseScrolling: true,
+      accelerationEnabled: true,
+      scrollSensitivity: 5,
+      scrollAcceleration: true,
+    },
   },
   {
     id: 5,
     name: 'MX Anywhere 2S',
     isExternal: false,
+    settings: {
+      swapRight: false,
+      sensitivity: 1,
+      reverseScrolling: false,
+      accelerationEnabled: false,
+      scrollSensitivity: 1,
+      scrollAcceleration: false,
+    },
   },
 ];
 
@@ -77,10 +127,20 @@
     id: 6,
     name: 'Default Pointing Stick',
     isExternal: false,
+    settings: {
+      swapRight: false,
+      sensitivity: 1,
+      accelerationEnabled: false,
+    },
   },
   {
     id: 7,
     name: 'Lexmark-Unicomp FSR',
     isExternal: true,
+    settings: {
+      swapRight: true,
+      sensitivity: 5,
+      accelerationEnabled: true,
+    },
   },
 ];
diff --git a/chrome/browser/resources/settings/chromeos/device_page/input_device_settings_types.ts b/chrome/browser/resources/settings/chromeos/device_page/input_device_settings_types.ts
index 32a843a..e9ab1474 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/input_device_settings_types.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/input_device_settings_types.ts
@@ -48,6 +48,7 @@
   isExternal: boolean;
   // Some settings are only available on haptic touchpads.
   isHaptic: boolean;
+  settings: TouchpadSettings;
 }
 
 export interface Mouse {
@@ -55,6 +56,7 @@
   name: string;
   // This property represents whether or not the mouse is an external device.
   isExternal: boolean;
+  settings: MouseSettings;
 }
 
 export interface PointingStick {
@@ -63,11 +65,44 @@
   // This property represents whether or not the pointing stick is an
   // external device.
   isExternal: boolean;
+  settings: PointingStickSettings;
 }
 
 export interface KeyboardSettings {
   modifierRemappings: Map<ModifierKey, ModifierKey>;
-  // TODO: Populate other KeyboardSettings interface.
+  topRowAreFKeys: boolean;
+  suppressMetaFKeyRewrites: boolean;
+  autoRepeatEnabled: boolean;
+  autoRepeatDelay: number;
+  autoRepeatInterval: number;
+}
+
+export interface TouchpadSettings {
+  sensitivity: number;
+  reverseScrolling: boolean;
+  accelerationEnabled: boolean;
+  tapToClickEnabled: boolean;
+  threeFingerClickEnabled: boolean;
+  tapDraggingEnabled: boolean;
+  scrollSensitivity: number;
+  scrollAcceleration: boolean;
+  hapticSensitivity: number;
+  hapticEnabled: boolean;
+}
+
+export interface MouseSettings {
+  swapRight: boolean;
+  sensitivity: number;
+  reverseScrolling: boolean;
+  accelerationEnabled: boolean;
+  scrollSensitivity: number;
+  scrollAcceleration: boolean;
+}
+
+export interface PointingStickSettings {
+  swapRight: boolean;
+  sensitivity: number;
+  accelerationEnabled: boolean;
 }
 
 export interface KeyboardObserverInterface {
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_toggle.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_toggle.html
index 37eace30..b0e01a6 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_toggle.html
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_feature_toggle.html
@@ -1,3 +1,4 @@
+<style include="cr-shared-style settings-shared"></style>
 <cr-toggle id="toggle"
     aria-label$="[[getToggleA11yLabel_(feature)]]"
     checked="{{checked_}}"
diff --git a/chrome/browser/task_manager/providers/render_process_host_task_provider.cc b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
index 96911c5..1ae4b2c5 100644
--- a/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
+++ b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
@@ -53,8 +53,6 @@
     }
   }
 
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
                  content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
@@ -104,6 +102,11 @@
   tasks_by_rph_id_.erase(itr);
 }
 
+void RenderProcessHostTaskProvider::OnRenderProcessHostCreated(
+    content::RenderProcessHost* host) {
+  CreateTask(host->GetID());
+}
+
 void RenderProcessHostTaskProvider::Observe(
     int type,
     const content::NotificationSource& source,
@@ -112,9 +115,6 @@
       content::Source<content::RenderProcessHost>(source).ptr();
   ChildProcessData data(content::PROCESS_TYPE_RENDERER);
   switch (type) {
-    case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
-      CreateTask(host->GetID());
-      break;
     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
       DeleteTask(host->GetID());
diff --git a/chrome/browser/task_manager/providers/render_process_host_task_provider.h b/chrome/browser/task_manager/providers/render_process_host_task_provider.h
index bf0dba8..d33a9d6 100644
--- a/chrome/browser/task_manager/providers/render_process_host_task_provider.h
+++ b/chrome/browser/task_manager/providers/render_process_host_task_provider.h
@@ -13,6 +13,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
 
 namespace task_manager {
 
@@ -21,8 +22,10 @@
 // This provides tasks that represent RenderProcessHost processes. It does so by
 // listening to the notification service for the creation and destruction of the
 // RenderProcessHost.
-class RenderProcessHostTaskProvider : public TaskProvider,
-                                      public content::NotificationObserver {
+class RenderProcessHostTaskProvider
+    : public TaskProvider,
+      public content::RenderProcessHostCreationObserver,
+      public content::NotificationObserver {
  public:
   RenderProcessHostTaskProvider();
   RenderProcessHostTaskProvider(const RenderProcessHostTaskProvider&) = delete;
@@ -33,6 +36,9 @@
   // task_manager::TaskProvider:
   Task* GetTaskOfUrlRequest(int child_id, int route_id) override;
 
+  // content::RenderProcessHostCreationObserver:
+  void OnRenderProcessHostCreated(content::RenderProcessHost* host) override;
+
   // content::NotificationObserver:
   void Observe(int type,
                const content::NotificationSource& source,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f9a230ad..4ad88038 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -4509,6 +4509,8 @@
       "views/download/bubble/download_bubble_row_view.h",
       "views/download/bubble/download_bubble_security_view.cc",
       "views/download/bubble/download_bubble_security_view.h",
+      "views/download/bubble/download_bubble_started_animation_views.cc",
+      "views/download/bubble/download_bubble_started_animation_views.h",
       "views/download/bubble/download_dialog_view.cc",
       "views/download/bubble/download_dialog_view.h",
       "views/download/bubble/download_toolbar_button_view.cc",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
index 389ca3de..01c6f65 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -162,7 +162,7 @@
                 Drawable bdgTabImage = ResourcesCompat.getDrawable(getContext().getResources(),
                         TabUiThemeUtil.getTSRTabResource(), getContext().getTheme());
                 bdgTabImage.setTint(
-                        TabUiThemeUtil.getTabStripContainerColor(getContext(), false, true));
+                        TabUiThemeUtil.getTabStripContainerColor(getContext(), false, true, false));
                 LayerDrawable backgroundDrawable =
                         new LayerDrawable(new Drawable[] {bgdColor, bdgTabImage});
                 // Set image size to match tab size.
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.cc b/chrome/browser/ui/ash/test_wallpaper_controller.cc
index 15fb9930..805304a 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.cc
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.cc
@@ -215,7 +215,9 @@
   ++remove_always_on_top_wallpaper_count_;
 }
 
-void TestWallpaperController::RemoveUserWallpaper(const AccountId& account_id) {
+void TestWallpaperController::RemoveUserWallpaper(
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
   ++remove_user_wallpaper_count_;
 }
 
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.h b/chrome/browser/ui/ash/test_wallpaper_controller.h
index 46de456..bb73889 100644
--- a/chrome/browser/ui/ash/test_wallpaper_controller.h
+++ b/chrome/browser/ui/ash/test_wallpaper_controller.h
@@ -140,7 +140,8 @@
   void ShowOneShotWallpaper(const gfx::ImageSkia& image) override;
   void ShowAlwaysOnTopWallpaper(const base::FilePath& image_path) override;
   void RemoveAlwaysOnTopWallpaper() override;
-  void RemoveUserWallpaper(const AccountId& account_id) override;
+  void RemoveUserWallpaper(const AccountId& account_id,
+                           base::OnceClosure on_removed) override;
   void RemovePolicyWallpaper(const AccountId& account_id) override;
   void SetAnimationDuration(base::TimeDelta animation_duration) override;
   void OpenWallpaperPickerIfAllowed() override;
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
index 03abc70d..01cfa12 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.cc
@@ -354,11 +354,14 @@
 }
 
 void WallpaperControllerClientImpl::RemoveUserWallpaper(
-    const AccountId& account_id) {
-  if (!IsKnownUser(account_id))
+    const AccountId& account_id,
+    base::OnceClosure on_removed) {
+  if (!IsKnownUser(account_id)) {
+    std::move(on_removed).Run();
     return;
+  }
 
-  wallpaper_controller_->RemoveUserWallpaper(account_id);
+  wallpaper_controller_->RemoveUserWallpaper(account_id, std::move(on_removed));
 }
 
 void WallpaperControllerClientImpl::RemovePolicyWallpaper(
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
index 9d9618f..71719938 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_impl.h
@@ -120,7 +120,8 @@
   void ShowSigninWallpaper();
   void ShowAlwaysOnTopWallpaper(const base::FilePath& image_path);
   void RemoveAlwaysOnTopWallpaper();
-  void RemoveUserWallpaper(const AccountId& account_id);
+  void RemoveUserWallpaper(const AccountId& account_id,
+                           base::OnceClosure on_removed);
   void RemovePolicyWallpaper(const AccountId& account_id);
   void SetAnimationDuration(const base::TimeDelta& animation_duration);
   void OpenWallpaperPickerIfAllowed();
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
index 7f3add6..0fead82 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -46,27 +46,6 @@
 #include "content/public/browser/navigation_handle.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace {
-
-autofill::SaveCardUiExperiment GetSaveCardUiExperimentArm() {
-  if (!base::FeatureList::IsEnabled(
-          autofill::features::kAutofillSaveCardUiExperiment)) {
-    return autofill::SaveCardUiExperiment::DEFAULT;
-  }
-
-  switch (
-      autofill::features::kAutofillSaveCardUiExperimentSelectorInNumber.Get()) {
-    case 1:
-      return autofill::SaveCardUiExperiment::FASTER_AND_PROTECTED;
-    case 2:
-      return autofill::SaveCardUiExperiment::ENCRYPTED_AND_SECURE;
-    default:
-      return autofill::SaveCardUiExperiment::DEFAULT;
-  }
-}
-
-}  // namespace
-
 namespace autofill {
 
 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl(
@@ -187,16 +166,6 @@
       return l10n_util::GetStringUTF16(
           IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
     case BubbleType::UPLOAD_SAVE:
-      if (GetSaveCardUiExperimentArm() ==
-          SaveCardUiExperiment::FASTER_AND_PROTECTED) {
-        return l10n_util::GetStringUTF16(
-            IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_EXPERIMENT_FASTER_AND_PROTECTED);
-      }
-      if (GetSaveCardUiExperimentArm() ==
-          SaveCardUiExperiment::ENCRYPTED_AND_SECURE) {
-        return l10n_util::GetStringUTF16(
-            IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_EXPERIMENT_ENCRYPTED_AND_SECURE);
-      }
       return features::ShouldShowImprovedUserConsentForCreditCardSave()
                  ? l10n_util::GetStringUTF16(
                        IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V4)
@@ -225,17 +194,8 @@
         IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME);
   }
 
-  switch (GetSaveCardUiExperimentArm()) {
-    case SaveCardUiExperiment::FASTER_AND_PROTECTED:
-      return l10n_util::GetStringUTF16(
-          IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_EXPERIMENT_FASTER_AND_PROTECTED);
-    case SaveCardUiExperiment::ENCRYPTED_AND_SECURE:
-      return l10n_util::GetStringUTF16(
-          IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_EXPERIMENT_ENCRYPTED_AND_SECURE);
-    default:
-      return l10n_util::GetStringUTF16(
-          IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3);
-  }
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3);
 }
 
 std::u16string SaveCardBubbleControllerImpl::GetAcceptButtonText() const {
diff --git a/chrome/browser/ui/autofill/payments/save_card_ui.h b/chrome/browser/ui/autofill/payments/save_card_ui.h
index a59d560..693e7532 100644
--- a/chrome/browser/ui/autofill/payments/save_card_ui.h
+++ b/chrome/browser/ui/autofill/payments/save_card_ui.h
@@ -31,18 +31,6 @@
   INACTIVE
 };
 
-// The type of experiment running for the save card ui.
-enum SaveCardUiExperiment {
-  // Show the text for default/current image.
-  DEFAULT = 0,
-
-  // Show the text for faster and protected image.
-  FASTER_AND_PROTECTED = 1,
-
-  // Show the text for encrypted and secure image.
-  ENCRYPTED_AND_SECURE = 2
-};
-
 }  // namespace autofill
 
 #endif  // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_SAVE_CARD_UI_H_
diff --git a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.cc
index 1e927d0..86f20099 100644
--- a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -45,6 +47,7 @@
   }
 
   iban_ = iban;
+  is_reshow_ = false;
   local_save_iban_prompt_callback_ = std::move(save_iban_prompt_callback);
   current_bubble_type_ = IbanBubbleType::kLocalSave;
 
@@ -55,12 +58,13 @@
   }
 }
 
-void SaveIbanBubbleControllerImpl::EnsureBubbleShown() {
+void SaveIbanBubbleControllerImpl::ReshowBubble() {
   // Don't show the bubble if it's already visible.
   if (bubble_view()) {
     return;
   }
 
+  is_reshow_ = true;
   ShowBubble();
 }
 
@@ -107,6 +111,8 @@
       // Show an animated IBAN saved confirmation message next time
       // UpdatePageActionIcon() is called.
       should_show_iban_saved_label_animation_ = true;
+      autofill_metrics::LogSaveIbanBubbleResultSavedWithNicknameMetric(
+          !nickname.empty());
       std::move(local_save_iban_prompt_callback_)
           .Run(AutofillClient::SaveIBANOfferUserDecision::kAccepted, nickname);
       break;
@@ -127,16 +133,36 @@
     PaymentsBubbleClosedReason closed_reason) {
   set_bubble_view(nullptr);
 
-  // Handles `current_bubble_type_` change according to its current type and the
-  // `closed_reason`.
-  if (closed_reason == PaymentsBubbleClosedReason::kAccepted) {
-    if (current_bubble_type_ == IbanBubbleType::kLocalSave) {
-      // TODO(crbug.com/1349109): Add kManageIban type to open IBAN bubble for
-      // managing the saved IBAN.
-    } else {
-      current_bubble_type_ = IbanBubbleType::kInactive;
+  // Log save IBAN prompt result according to the closed reason.
+  if (current_bubble_type_ == IbanBubbleType::kLocalSave) {
+    autofill_metrics::SaveIbanBubbleResult metric;
+    switch (closed_reason) {
+      case PaymentsBubbleClosedReason::kAccepted:
+        metric = autofill_metrics::SaveIbanBubbleResult::kAccepted;
+        break;
+      case PaymentsBubbleClosedReason::kCancelled:
+        metric = autofill_metrics::SaveIbanBubbleResult::kCancelled;
+        break;
+      case PaymentsBubbleClosedReason::kClosed:
+        metric = autofill_metrics::SaveIbanBubbleResult::kClosed;
+        break;
+      case PaymentsBubbleClosedReason::kNotInteracted:
+        metric = autofill_metrics::SaveIbanBubbleResult::kNotInteracted;
+        break;
+      case PaymentsBubbleClosedReason::kLostFocus:
+        metric = autofill_metrics::SaveIbanBubbleResult::kLostFocus;
+        break;
+      case PaymentsBubbleClosedReason::kUnknown:
+        metric = autofill_metrics::SaveIbanBubbleResult::kUnknown;
+        NOTREACHED();
+        break;
     }
-  } else if (closed_reason == PaymentsBubbleClosedReason::kCancelled) {
+    autofill_metrics::LogSaveIbanBubbleResultMetric(metric, is_reshow_);
+  }
+
+  // Handles `current_bubble_type_` change according to the `closed_reason`.
+  if (closed_reason == PaymentsBubbleClosedReason::kAccepted ||
+      closed_reason == PaymentsBubbleClosedReason::kCancelled) {
     current_bubble_type_ = IbanBubbleType::kInactive;
   }
 
@@ -217,9 +243,18 @@
            current_bubble_type_ == IbanBubbleType::kLocalSave));
   DCHECK(!bubble_view());
   Show();
+  switch (current_bubble_type_) {
+    case IbanBubbleType::kLocalSave:
+      autofill_metrics::LogSaveIbanBubbleOfferMetric(
+          autofill_metrics::SaveIbanPromptOffer::kShown, is_reshow_);
+      break;
+    case IbanBubbleType::kInactive:
+      NOTREACHED();
+  }
 }
 
 void SaveIbanBubbleControllerImpl::ShowIconOnly() {
+  DCHECK(!is_reshow_);
   DCHECK(current_bubble_type_ != IbanBubbleType::kInactive);
   // Local save callback should not be null for LOCAL_SAVE state.
   DCHECK(!local_save_iban_prompt_callback_.is_null() ||
@@ -230,6 +265,16 @@
   // explicitly clicks the icon.
   UpdatePageActionIcon();
 
+  switch (current_bubble_type_) {
+    case IbanBubbleType::kLocalSave:
+      autofill_metrics::LogSaveIbanBubbleOfferMetric(
+          autofill_metrics::SaveIbanPromptOffer::kNotShownMaxStrikesReached,
+          is_reshow_);
+      break;
+    case IbanBubbleType::kInactive:
+      NOTREACHED();
+  }
+
   if (observer_for_testing_) {
     observer_for_testing_->OnIconShown();
   }
diff --git a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.h
index 99fecf7..7c80587 100644
--- a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.h
@@ -48,7 +48,7 @@
       AutofillClient::LocalSaveIBANPromptCallback save_iban_prompt_callback);
 
   // No-op if the bubble is already shown, otherwise, shows the bubble.
-  void EnsureBubbleShown();
+  void ReshowBubble();
 
   // SaveIbanBubbleController:
   std::u16string GetWindowTitle() const override;
@@ -109,6 +109,9 @@
   // IBAN offer-to-save prompt.
   AutofillClient::LocalSaveIBANPromptCallback local_save_iban_prompt_callback_;
 
+  // Whether the bubble is shown after user interacted with the omnibox icon.
+  bool is_reshow_ = false;
+
   // Contains the details of the IBAN that will be saved if the user accepts.
   IBAN iban_;
 
diff --git a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl_unittest.cc
index 3d2b220d..18d995c0 100644
--- a/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl_unittest.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/browser/ui/autofill/payments/save_iban_bubble_controller_impl.h"
 
+#include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/ui/autofill/autofill_bubble_base.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/iban.h"
+#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -55,6 +57,10 @@
     }
   }
 
+  void CloseBubble(PaymentsBubbleClosedReason closed_reason) {
+    controller()->OnBubbleClosed(closed_reason);
+  }
+
   std::u16string saved_nickname() { return saved_nickname_; }
 
  protected:
@@ -84,4 +90,72 @@
   EXPECT_EQ(nickname, saved_nickname());
 }
 
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanOffered) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanResult_Accepted) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  CloseBubble(PaymentsBubbleClosedReason::kAccepted);
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kAccepted, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanResult_Cancelled) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  CloseBubble(PaymentsBubbleClosedReason::kCancelled);
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kCancelled, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest,
+       Metrics_LocalIbanResult_NotInteracted) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  CloseBubble(PaymentsBubbleClosedReason::kNotInteracted);
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kNotInteracted, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanResult_LostFocus) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  CloseBubble(PaymentsBubbleClosedReason::kLostFocus);
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kLostFocus, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanSaved_WithNickname) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  ClickSaveButton(u"My doctor's IBAN");
+
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.SavedWithNickname", true, 1);
+}
+
+TEST_F(SaveIbanBubbleControllerImplTest, Metrics_LocalIbanSaved_NoNickname) {
+  base::HistogramTester histogram_tester;
+  ShowLocalBubble(autofill::test::GetIBAN());
+  ClickSaveButton(u"");
+
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.SavedWithNickname", false, 1);
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 62ceedc..17c134b 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1276,7 +1276,7 @@
       browser->tab_strip_model()->GetActiveWebContents();
   autofill::SaveIbanBubbleControllerImpl* controller =
       autofill::SaveIbanBubbleControllerImpl::FromWebContents(web_contents);
-  controller->EnsureBubbleShown();
+  controller->ReshowBubble();
 }
 
 void MigrateLocalCards(Browser* browser) {
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index 43fe9836..0f15f72 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -63,6 +63,8 @@
   E_CPONLY(kColorDownloadShelfForeground) \
   E_CPONLY(kColorDownloadStartedAnimationForeground) \
   E_CPONLY(kColorDownloadToolbarButtonActive) \
+  E_CPONLY(kColorDownloadToolbarButtonAnimationBackground) \
+  E_CPONLY(kColorDownloadToolbarButtonAnimationForeground) \
   E_CPONLY(kColorDownloadToolbarButtonInactive) \
   E_CPONLY(kColorDownloadToolbarButtonRingBackground) \
   /* Extension colors. */ \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc
index 6fd69309..0fad10c 100644
--- a/chrome/browser/ui/color/chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -191,6 +191,13 @@
   mixer[kColorDownloadToolbarButtonActive] =
       ui::PickGoogleColor(ui::kColorThrobber, kColorToolbar,
                           color_utils::kMinimumVisibleContrastRatio);
+  // TODO(chlily): The opacity should be kToolbarInkDropHighlightVisibleOpacity
+  // (same as used in AdjustHighlightColorForContrast()). Pull out usages of the
+  // constant.
+  mixer[kColorDownloadToolbarButtonAnimationBackground] = ui::AlphaBlend(
+      kColorDownloadToolbarButtonAnimationForeground, kColorToolbar, 0x14);
+  mixer[kColorDownloadToolbarButtonAnimationForeground] =
+      AdjustHighlightColorForContrast(ui::kColorAccent, kColorToolbar);
   mixer[kColorDownloadToolbarButtonInactive] = {kColorToolbarButtonIcon};
   mixer[kColorDownloadToolbarButtonRingBackground] = {
       SkColorSetA(kColorDownloadToolbarButtonInactive, 0x33)};
diff --git a/chrome/browser/ui/views/autofill/payments/dialog_view_ids.h b/chrome/browser/ui/views/autofill/payments/dialog_view_ids.h
index 8876454..7d2fbed 100644
--- a/chrome/browser/ui/views/autofill/payments/dialog_view_ids.h
+++ b/chrome/browser/ui/views/autofill/payments/dialog_view_ids.h
@@ -50,6 +50,7 @@
 
   // The following are views::Textfield objects.
   CARDHOLDER_NAME_TEXTFIELD,  // Used for cardholder name entry/confirmation
+  NICKNAME_TEXTFIELD,         // Used for IBAN nickname entry/confirmation
 
   // The following are views::TooltipIcon objects.
   CARDHOLDER_NAME_TOOLTIP,  // Appears during cardholder name entry/confirmation
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
index 0640bf4..efaec77 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
@@ -53,28 +53,6 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/style/typography.h"
 
-namespace {
-
-ui::ImageModel GetProfileAvatar(AccountInfo account_info) {
-  // Get the user avatar icon.
-  gfx::Image account_avatar = account_info.account_image;
-
-  // Check for avatar being empty and replacing it with a
-  // placeholder if that is the case.
-  if (account_avatar.IsEmpty()) {
-    account_avatar = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-        profiles::GetPlaceholderAvatarIconResourceID());
-  }
-
-  int avatar_size = views::style::GetLineHeight(
-      views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_SECONDARY);
-
-  return ui::ImageModel::FromImage(profiles::GetSizedAvatarIcon(
-      account_avatar, avatar_size, avatar_size, profiles::SHAPE_CIRCLE));
-}
-
-}  // namespace
-
 namespace autofill {
 
 SaveCardOfferBubbleViews::SaveCardOfferBubbleViews(
@@ -86,21 +64,11 @@
   const LegalMessageLines message_lines = controller->GetLegalMessageLines();
 
   if (!message_lines.empty()) {
-    if (IsSaveCardUiExperimentEnabled()) {
-      std::string user_email = controller->GetAccountInfo().email;
-      // Display TOS with user avatar and email present in the footer.
-      legal_message_view_ = SetFootnoteView(std::make_unique<LegalMessageView>(
-          message_lines, base::UTF8ToUTF16(user_email),
-          GetProfileAvatar(controller->GetAccountInfo()),
-          base::BindRepeating(&SaveCardOfferBubbleViews::LinkClicked,
-                              base::Unretained(this))));
-    } else {
-      legal_message_view_ = SetFootnoteView(std::make_unique<LegalMessageView>(
-          message_lines, /*user_email=*/absl::nullopt,
-          /*user_avatar=*/absl::nullopt,
-          base::BindRepeating(&SaveCardOfferBubbleViews::LinkClicked,
-                              base::Unretained(this))));
-    }
+    legal_message_view_ = SetFootnoteView(std::make_unique<LegalMessageView>(
+        message_lines, /*user_email=*/absl::nullopt,
+        /*user_avatar=*/absl::nullopt,
+        base::BindRepeating(&SaveCardOfferBubbleViews::LinkClicked,
+                            base::Unretained(this))));
     InitFootnoteView(legal_message_view_);
   }
 
@@ -180,24 +148,13 @@
   // Set the header image.
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
 
-  // Boolean to show the shield image for save card bubble. It is
-  // active/shown only when save card ui experiment is enabled and when the
-  // active experiment selected != 3 (existing option with user information
-  // view).
-  bool show_shield_header_image =
-      IsSaveCardUiExperimentEnabled() &&
-      features::kAutofillSaveCardUiExperimentSelectorInNumber.Get() != 3;
-
   // Ternary operator added for the save card ui experiment where the feature
   // flag and the experiment selected would determine if the experiment is
   // active or not. Currently, any option != 0 and experiment flag enabled
   // should trigger the experiment.
   auto image_view = std::make_unique<ThemeTrackingNonAccessibleImageView>(
-      *bundle.GetImageSkiaNamed(
-          show_shield_header_image ? IDR_SAVE_CARD_SECURELY : IDR_SAVE_CARD),
-      *bundle.GetImageSkiaNamed(show_shield_header_image
-                                    ? IDR_SAVE_CARD_SECURELY_DARK
-                                    : IDR_SAVE_CARD_DARK),
+      *bundle.GetImageSkiaNamed(IDR_SAVE_CARD),
+      *bundle.GetImageSkiaNamed(IDR_SAVE_CARD_DARK),
       base::BindRepeating(&views::BubbleDialogDelegate::GetBackgroundColor,
                           base::Unretained(this)));
   GetBubbleFrameView()->SetHeaderView(std::move(image_view));
@@ -384,12 +341,6 @@
   return upload_explanation_tooltip;
 }
 
-bool SaveCardOfferBubbleViews::IsSaveCardUiExperimentEnabled() {
-  return (
-      base::FeatureList::IsEnabled(features::kAutofillSaveCardUiExperiment) &&
-      features::kAutofillSaveCardUiExperimentSelectorInNumber.Get() != 0);
-}
-
 void SaveCardOfferBubbleViews::LinkClicked(const GURL& url) {
   if (controller())
     controller()->OnLegalMessageLinkClicked(url);
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
index b9981183..767c6af3 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
@@ -54,10 +54,6 @@
   std::unique_ptr<views::View> CreateRequestExpirationDateView();
   std::unique_ptr<views::View> CreateUploadExplanationView();
 
-  // Method to check if the save card ui experiment is enabled where one of the
-  // 3 experimental save card bubble UI treatments are shown.
-  bool IsSaveCardUiExperimentEnabled();
-
   void LinkClicked(const GURL& url);
 
   raw_ptr<views::Textfield> cardholder_name_textfield_ = nullptr;
diff --git a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc
index b446d4d3..2dbeac1 100644
--- a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc
@@ -201,6 +201,10 @@
 
   DCHECK(iban_value_);
   iban_value_->SetID(DialogViewId::IBAN_VALUE_LABEL);
+
+  if (nickname_textfield_) {
+    nickname_textfield_->SetID(DialogViewId::NICKNAME_TEXTFIELD);
+  }
 }
 
 void SaveIbanBubbleView::OnDialogAccepted() {
diff --git a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view_uitest.cc b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view_uitest.cc
index 78a91dd..2d1f2aa 100644
--- a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view_uitest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view_uitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/autofill/autofill_uitest_util.h"
@@ -19,6 +20,7 @@
 #include "components/autofill/content/browser/test_autofill_manager_injector.h"
 #include "components/autofill/core/browser/browser_autofill_manager.h"
 #include "components/autofill/core/browser/form_data_importer.h"
+#include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
 #include "components/autofill/core/browser/payments/iban_save_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/iban_save_strike_database.h"
@@ -338,6 +340,11 @@
     EXPECT_FALSE(GetSaveIbanBubbleView());
   }
 
+  views::Textfield* nickname_input() {
+    return static_cast<views::Textfield*>(
+        FindViewInBubbleById(DialogViewId::NICKNAME_TEXTFIELD));
+  }
+
   void WaitForObservedEvent() { event_waiter_->Wait(); }
 
   raw_ptr<IBANSaveManager, DanglingUntriaged> iban_save_manager_ = nullptr;
@@ -352,6 +359,7 @@
 // successfully causes the bubble to go away, and causes a strike to be added.
 IN_PROC_BROWSER_TEST_F(SaveIbanBubbleViewFullFormBrowserTest,
                        Local_ClickingNoThanksClosesBubble) {
+  base::HistogramTester histogram_tester;
   FillForm(kIbanValue);
   SubmitFormAndWaitForIbanLocalSaveBubble();
 
@@ -364,6 +372,12 @@
   EXPECT_EQ(
       1, iban_save_manager_->GetIBANSaveStrikeDatabaseForTesting()->GetStrikes(
              kIbanValue));
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kCancelled, 1);
 }
 
 // Tests overall StrikeDatabase interaction with the local save bubble. Runs an
@@ -372,6 +386,7 @@
 // strikes are added if the IBAN already has max strikes.
 IN_PROC_BROWSER_TEST_F(SaveIbanBubbleViewFullFormBrowserTest,
                        StrikeDatabase_Local_FullFlowTest) {
+  base::HistogramTester histogram_tester;
   // Show and ignore the bubble enough times in order to accrue maximum strikes.
   for (int i = 0; i < iban_save_manager_->GetIBANSaveStrikeDatabaseForTesting()
                           ->GetMaxStrikesLimit();
@@ -408,15 +423,25 @@
   WaitForObservedEvent();
   EXPECT_TRUE(FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL)
                   ->GetVisible());
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptOffer.Local.Reshows",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
 
   ClickOnCancelButton();
   WaitForObservedEvent();
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kNotShownMaxStrikesReached, 1);
+  histogram_tester.ExpectBucketCount(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 3);
 }
 
 // Tests the local save bubble. Ensures that clicking the 'Save' button
 // successfully causes the bubble to go away.
 IN_PROC_BROWSER_TEST_F(SaveIbanBubbleViewFullFormBrowserTest,
                        Local_ClickingSaveClosesBubble) {
+  base::HistogramTester histogram_tester;
   FillForm();
   SubmitFormAndWaitForIbanLocalSaveBubble();
 
@@ -425,18 +450,57 @@
   WaitForObservedEvent();
 
   EXPECT_FALSE(GetSaveIbanBubbleView());
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kAccepted, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.SavedWithNickname", false, 1);
+}
+
+// Tests the local save bubble. Ensures that clicking the 'Save' button
+// successfully causes the bubble to go away.
+IN_PROC_BROWSER_TEST_F(SaveIbanBubbleViewFullFormBrowserTest,
+                       Local_ClickingSaveClosesBubble_WithNickname) {
+  base::HistogramTester histogram_tester;
+  FillForm();
+  SubmitFormAndWaitForIbanLocalSaveBubble();
+  nickname_input()->SetText(u"My doctor's IBAN");
+
+  ResetEventWaiterForSequence({DialogEvent::ACCEPT_SAVE_IBAN_COMPLETE});
+  ClickOnSaveButton();
+  WaitForObservedEvent();
+
+  EXPECT_FALSE(GetSaveIbanBubbleView());
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kAccepted, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.SavedWithNickname", true, 1);
 }
 
 // Tests the local save bubble. Ensures that clicking the [X] button will still
 // see the omnibox icon.
 IN_PROC_BROWSER_TEST_F(SaveIbanBubbleViewFullFormBrowserTest,
                        Local_ClickingClosesBubbleStillShowOmnibox) {
+  base::HistogramTester histogram_tester;
   FillForm();
   SubmitFormAndWaitForIbanLocalSaveBubble();
 
   ClickOnCloseButton();
   EXPECT_TRUE(GetSaveIbanIconView()->GetVisible());
   EXPECT_FALSE(GetSaveIbanBubbleView());
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptOffer.Local.FirstShow",
+      autofill_metrics::SaveIbanPromptOffer::kShown, 1);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.SaveIbanPromptResult.Local.FirstShow",
+      autofill_metrics::SaveIbanBubbleResult::kClosed, 1);
 }
 
 // Tests the local save bubble. Ensures that clicking the eye icon button
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.cc b/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.cc
new file mode 100644
index 0000000..2e26c3c
--- /dev/null
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.cc
@@ -0,0 +1,135 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.h"
+
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/views/download/download_started_animation_views.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/paint_vector_icon.h"
+
+namespace {
+
+// The animation is piecewise linear, composed of 2 phases, phase one is 300 ms
+// and phase two is 200 ms.
+constexpr base::TimeDelta kAnimationDuration = base::Milliseconds(500);
+constexpr double kAnimationPhaseSwitchProgress = 0.6;
+constexpr int kIconSize = 26;
+constexpr int kIconBackgroundRadius = 32;
+
+ui::ImageModel GetDownloadIconImageModel(SkColor image_foreground_color,
+                                         SkColor image_background_color) {
+  gfx::ImageSkia icon = gfx::CreateVectorIcon(gfx::IconDescription(
+      kDownloadToolbarButtonIcon, kIconSize, image_foreground_color));
+  gfx::ImageSkia image =
+      gfx::ImageSkiaOperations::CreateImageWithCircleBackground(
+          kIconBackgroundRadius, image_background_color, icon);
+  return ui::ImageModel::FromImageSkia(image);
+}
+
+// Rescales the current progress value of the animation such that the progress
+// goes from 0.0 to 1.0 within phase one.
+double GetPhaseOneProgress(double current_value) {
+  DCHECK_LE(current_value, kAnimationPhaseSwitchProgress);
+  return current_value / kAnimationPhaseSwitchProgress;
+}
+
+// Rescales the current progress value of the animation such that the progress
+// goes from 0.0 to 1.0 within phase two.
+double GetPhaseTwoProgress(double current_value) {
+  DCHECK_GE(current_value, kAnimationPhaseSwitchProgress);
+  return (current_value - kAnimationPhaseSwitchProgress) /
+         (1.0 - kAnimationPhaseSwitchProgress);
+}
+
+// Breaks down the y-axis movement for each phase for simplicity.
+int GetYForPhaseOne(double phase_one_progress,
+                    const gfx::Rect& web_contents_bounds,
+                    const gfx::Rect& toolbar_icon_bounds,
+                    const gfx::Size& image_size) {
+  // Start centered at 50% of viewport height.
+  const int start =
+      web_contents_bounds.CenterPoint().y() - image_size.height() / 2;
+  // End phase one at 40 px below the center of the toolbar icon.
+  const int end = toolbar_icon_bounds.bottom_center().y() + 40;
+  return static_cast<int>(start + (end - start) * phase_one_progress);
+}
+
+int GetYForPhaseTwo(double phase_two_progress,
+                    const gfx::Rect& web_contents_bounds,
+                    const gfx::Rect& toolbar_icon_bounds,
+                    const gfx::Size& image_size) {
+  // Start where phase one ended.
+  const int start = toolbar_icon_bounds.bottom_center().y() + 40;
+  // End centered over the toolbar icon.
+  const int end =
+      toolbar_icon_bounds.CenterPoint().y() - image_size.height() / 2;
+  return static_cast<int>(start + (end - start) * phase_two_progress);
+}
+
+// Breaks down the opacity changes for each phase for simplicity.
+float GetOpacityForPhaseOne(double phase_one_progress) {
+  // Go from 0 to 1 opacity.
+  return static_cast<float>(phase_one_progress);
+}
+
+float GetOpacityForPhaseTwo(double phase_two_progress) {
+  // Go from 1 to 0 opacity.
+  return static_cast<float>(1 - phase_two_progress);
+}
+
+}  // namespace
+
+DownloadBubbleStartedAnimationViews::DownloadBubbleStartedAnimationViews(
+    content::WebContents* web_contents,
+    const gfx::Rect& toolbar_icon_bounds,
+    SkColor image_foreground_color,
+    SkColor image_background_color)
+    : DownloadStartedAnimationViews(
+          web_contents,
+          kAnimationDuration,
+          GetDownloadIconImageModel(image_foreground_color,
+                                    image_background_color)),
+      toolbar_icon_bounds_(toolbar_icon_bounds) {}
+
+DownloadBubbleStartedAnimationViews::~DownloadBubbleStartedAnimationViews() =
+    default;
+
+int DownloadBubbleStartedAnimationViews::GetX() const {
+  // Align the centers of the animation and the toolbar icon.
+  return toolbar_icon_bounds_.CenterPoint().x() -
+         GetPreferredSize().width() / 2;
+}
+
+int DownloadBubbleStartedAnimationViews::GetY() const {
+  if (GetCurrentValue() <= kAnimationPhaseSwitchProgress) {
+    return GetYForPhaseOne(GetPhaseOneProgress(GetCurrentValue()),
+                           web_contents_bounds(), toolbar_icon_bounds_,
+                           GetPreferredSize());
+  }
+  return GetYForPhaseTwo(GetPhaseTwoProgress(GetCurrentValue()),
+                         web_contents_bounds(), toolbar_icon_bounds_,
+                         GetPreferredSize());
+}
+
+float DownloadBubbleStartedAnimationViews::GetOpacity() const {
+  if (GetCurrentValue() <= kAnimationPhaseSwitchProgress) {
+    return GetOpacityForPhaseOne(GetPhaseOneProgress(GetCurrentValue()));
+  }
+  return GetOpacityForPhaseTwo(GetPhaseTwoProgress(GetCurrentValue()));
+}
+
+bool DownloadBubbleStartedAnimationViews::WebContentsTooSmall(
+    const gfx::Size& image_size) const {
+  return web_contents_bounds().height() < image_size.height() + 40;
+}
+
+BEGIN_METADATA(DownloadBubbleStartedAnimationViews,
+               DownloadStartedAnimationViews)
+END_METADATA
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.h b/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.h
new file mode 100644
index 0000000..0eff523
--- /dev/null
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.h
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_STARTED_ANIMATION_VIEWS_H_
+#define CHROME_BROWSER_UI_VIEWS_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_STARTED_ANIMATION_VIEWS_H_
+
+#include "chrome/browser/ui/views/download/download_started_animation_views.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace gfx {
+class Rect;
+class Size;
+}  // namespace gfx
+
+// An animation that starts halfway down the screen and moves upwards towards
+// the download bubble toolbar icon. The animation is piecewise linear, composed
+// of 2 phases. During phase one, the icon moves upwards and fades in. During
+// phase two, the icon continues moving upwards and fades out.
+// TODO(crbug.com/1414062): Investigate writing this using more modern
+// frameworks like layers and views animation builder.
+class DownloadBubbleStartedAnimationViews
+    : public DownloadStartedAnimationViews {
+ public:
+  METADATA_HEADER(DownloadBubbleStartedAnimationViews);
+  DownloadBubbleStartedAnimationViews(content::WebContents* web_contents,
+                                      const gfx::Rect& toolbar_icon_bounds,
+                                      SkColor image_foreground_color,
+                                      SkColor image_background_color);
+  DownloadBubbleStartedAnimationViews(
+      const DownloadBubbleStartedAnimationViews&) = delete;
+  DownloadBubbleStartedAnimationViews& operator=(
+      const DownloadBubbleStartedAnimationViews&) = delete;
+  ~DownloadBubbleStartedAnimationViews() override;
+
+ private:
+  // DownloadStartedAnimationViews
+  int GetX() const override;
+  int GetY() const override;
+  float GetOpacity() const override;
+  bool WebContentsTooSmall(const gfx::Size& image_size) const override;
+
+  // Bounds of the download bubble icon in the screen coordinate system.
+  gfx::Rect toolbar_icon_bounds_;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_DOWNLOAD_BUBBLE_DOWNLOAD_BUBBLE_STARTED_ANIMATION_VIEWS_H_
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
index f13857c..61f07833 100644
--- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/download/bubble/download_bubble_controller.h"
 #include "chrome/browser/download/bubble/download_display_controller.h"
 #include "chrome/browser/download/download_ui_model.h"
+#include "chrome/browser/platform_util.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/ui/views/download/bubble/download_bubble_row_list_view.h"
 #include "chrome/browser/ui/views/download/bubble/download_bubble_row_view.h"
 #include "chrome/browser/ui/views/download/bubble/download_bubble_security_view.h"
+#include "chrome/browser/ui/views/download/bubble/download_bubble_started_animation_views.h"
 #include "chrome/browser/ui/views/download/bubble/download_dialog_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -30,6 +32,8 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/color/color_id.h"
+#include "ui/color/color_provider.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point.h"
@@ -267,11 +271,17 @@
 // This function shows the partial view. If the main view is already showing,
 // we do not show the partial view. If the partial view is already showing,
 // there is nothing to do here, the controller should update the partial view.
-void DownloadToolbarButtonView::ShowDetails() {
+void DownloadToolbarButtonView::ShowDetails(bool show_animation) {
   if (!bubble_delegate_) {
     is_primary_partial_view_ = true;
     CreateBubbleDialogDelegate(GetPrimaryView());
   }
+  if (show_animation && gfx::Animation::ShouldRenderRichAnimation()) {
+    has_pending_download_started_animation_ = true;
+    if (!needs_layout()) {
+      ShowPendingDownloadStartedAnimation();
+    }
+  }
 }
 
 void DownloadToolbarButtonView::HideDetails() {
@@ -334,6 +344,10 @@
   }
   badge_image_view_->SetBoundsRect(
       gfx::Rect(badge_offset_x, badge_offset_y, badge_height, badge_height));
+
+  // If there is a pending animation, show it now after we have laid out the
+  // view properly.
+  ShowPendingDownloadStartedAnimation();
 }
 
 std::unique_ptr<views::View> DownloadToolbarButtonView::GetPrimaryView() {
@@ -460,6 +474,25 @@
   return std::move(scroll_view);
 }
 
+void DownloadToolbarButtonView::ShowPendingDownloadStartedAnimation() {
+  if (!has_pending_download_started_animation_) {
+    return;
+  }
+  content::WebContents* const web_contents =
+      browser_->tab_strip_model()->GetActiveWebContents();
+  if (!web_contents ||
+      !platform_util::IsVisible(web_contents->GetNativeView())) {
+    return;
+  }
+  const ui::ColorProvider* color_provider = GetColorProvider();
+  // Animation cleans itself up after it's done.
+  new DownloadBubbleStartedAnimationViews(
+      web_contents, image()->GetBoundsInScreen(),
+      color_provider->GetColor(kColorDownloadToolbarButtonAnimationForeground),
+      color_provider->GetColor(kColorDownloadToolbarButtonAnimationBackground));
+  has_pending_download_started_animation_ = false;
+}
+
 SkColor DownloadToolbarButtonView::GetIconColor() const {
   return icon_color_.value_or(
       controller_->GetIconInfo().is_active
diff --git a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h
index 16cc406..9ea13b94 100644
--- a/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h
+++ b/chrome/browser/ui/views/download/bubble/download_toolbar_button_view.h
@@ -53,7 +53,7 @@
   void Enable() override;
   void Disable() override;
   void UpdateDownloadIcon() override;
-  void ShowDetails() override;
+  void ShowDetails(bool show_animation) override;
   void HideDetails() override;
   bool IsShowingDetails() override;
   bool IsFullscreenWithParentViewHidden() override;
@@ -101,6 +101,10 @@
   std::unique_ptr<View> CreateRowListView(
       std::vector<DownloadUIModel::DownloadUIModelPtr> model_list);
 
+  // If |has_pending_download_started_animation_| is true, shows an animation of
+  // a download icon moving upwards towards the toolbar icon.
+  void ShowPendingDownloadStartedAnimation();
+
   SkColor GetProgressColor(bool is_disabled, bool is_active) const;
 
   raw_ptr<Browser> browser_;
@@ -113,6 +117,12 @@
   raw_ptr<View> primary_view_ = nullptr;
   raw_ptr<DownloadBubbleSecurityView> security_view_ = nullptr;
 
+  // Marks whether there is a pending download started animation. This is needed
+  // because the animation should only be triggered after the view has been
+  // laid out properly, so this provides a way to remember to show the animation
+  // if needed, when calling Layout().
+  bool has_pending_download_started_animation_ = false;
+
   // RenderTexts used for the number in the badge. Stores the text for "n" at
   // index n - 1, and stores the text for the placeholder ("9+") at index 0.
   // This is done to avoid re-creating the same RenderText on each paint. Text
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 325cd86..4535b3b 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -357,9 +357,7 @@
   if (has_icon) {
     views::ImageView* app_icon_view = container->AddChildView(CreateAppIconView(
         /*icon_resource_id=*/0, icon_bitmap,
-        // TODO(crbug.com/1414090): Determine correct text (used for both
-        // tooltip and screen reader).
-        /*tooltip_text=*/GetPaymentHandlerDialogTitle(web_contents())));
+        /*tooltip_text=*/l10n_util::GetStringUTF16(IDS_PAYMENT_HANDLER_ICON)));
     app_icon_view->SetID(
         static_cast<int>(DialogViewID::PAYMENT_APP_HEADER_ICON));
     float adjusted_width =
diff --git a/chrome/browser/ui/webui/ash/login/oobe_ui.cc b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
index 0a7abe8..ef42b7d 100644
--- a/chrome/browser/ui/webui/ash/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
@@ -233,18 +233,18 @@
     base::SysInfo::CrashIfChromeOSNonTestImage();
   }
 
-  source->AddResourcePath(kDebuggerMJSPath, enabled ?
-                                            IDR_OOBE_DEBUGGER_JS :
-                                            IDR_OOBE_DEBUGGER_STUB_JS);
+  source->AddResourcePath(kDebuggerMJSPath,
+                          enabled ? IDR_OOBE_CONDITIONAL_DEBUG_DEBUG_JS
+                                  : IDR_OOBE_CONDITIONAL_DEBUG_NO_DEBUG_JS);
 }
 
 void AddTestAPIResources(content::WebUIDataSource* source) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   const bool enabled = command_line->HasSwitch(switches::kEnableOobeTestAPI);
 
-  source->AddResourcePath(kTestAPIJsMPath, enabled ?
-                                           IDR_OOBE_TEST_API_JS :
-                                           IDR_OOBE_TEST_API_STUB_JS);
+  source->AddResourcePath(
+      kTestAPIJsMPath, enabled ? IDR_OOBE_CONDITIONAL_TEST_API_TEST_API_JS
+                               : IDR_OOBE_CONDITIONAL_TEST_API_NO_TEST_API_JS);
 }
 
 // Creates a WebUIDataSource for chrome://oobe
@@ -604,10 +604,11 @@
   if (policy::EnrollmentRequisitionManager::IsRemoraRequisition()) {
     source->AddResourcePath(
         kOobeCustomVarsCssJs,
-        IDR_OOBE_COMPONENTS_OOBE_CUSTOM_VARS_REMORA_CSS_JS);
+        IDR_OOBE_CONDITIONAL_COMPONENTS_OOBE_VARS_OOBE_CUSTOM_VARS_REMORA_CSS_JS);
   } else {
-    source->AddResourcePath(kOobeCustomVarsCssJs,
-                            IDR_OOBE_COMPONENTS_OOBE_CUSTOM_VARS_CSS_JS);
+    source->AddResourcePath(
+        kOobeCustomVarsCssJs,
+        IDR_OOBE_CONDITIONAL_COMPONENTS_OOBE_VARS_OOBE_CUSTOM_VARS_CSS_JS);
   }
 
   source->OverrideContentSecurityPolicy(
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.cc b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
index 405502d..027c0bb1 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
@@ -34,7 +34,7 @@
 namespace {
 
 // Best effort convert |value| to a string.
-std::string ToJSON(const base::Value& value) {
+std::string ToJSON(const base::Value::Dict& value) {
   std::string result;
   JSONStringValueSerializer serializer(&result);
   if (serializer.Serialize(value))
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
index ed15a288..cecf97e 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
@@ -147,25 +147,35 @@
 class TestNodeDataDescriber : public performance_manager::NodeDataDescriber {
  public:
   // NodeDataDescriber implementations:
-  base::Value DescribeFrameNodeData(
+  base::Value::Dict DescribeFrameNodeData(
       const performance_manager::FrameNode* node) const override {
-    return base::Value("frame");
+    base::Value::Dict dict;
+    dict.Set("type", "frame");
+    return dict;
   }
-  base::Value DescribePageNodeData(
+  base::Value::Dict DescribePageNodeData(
       const performance_manager::PageNode* node) const override {
-    return base::Value("page");
+    base::Value::Dict dict;
+    dict.Set("type", "page");
+    return dict;
   }
-  base::Value DescribeProcessNodeData(
+  base::Value::Dict DescribeProcessNodeData(
       const performance_manager::ProcessNode* node) const override {
-    return base::Value("process");
+    base::Value::Dict dict;
+    dict.Set("type", "process");
+    return dict;
   }
-  base::Value DescribeSystemNodeData(
+  base::Value::Dict DescribeSystemNodeData(
       const performance_manager::SystemNode* node) const override {
-    return base::Value("system");
+    base::Value::Dict dict;
+    dict.Set("type", "system");
+    return dict;
   }
-  base::Value DescribeWorkerNodeData(
+  base::Value::Dict DescribeWorkerNodeData(
       const performance_manager::WorkerNode* node) const override {
-    return base::Value("worker");
+    base::Value::Dict dict;
+    dict.Set("type", "worker");
+    return dict;
   }
 };
 
@@ -222,18 +232,18 @@
   for (const auto& kv : change_stream.process_map()) {
     const auto* process_info = kv.second.get();
     EXPECT_NE(0u, process_info->id);
-    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"process\"}"),
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":{\"type\":\"process\"}}"),
               base::JSONReader::Read(process_info->description_json));
   }
 
   EXPECT_EQ(3u, change_stream.frame_map().size());
   for (const auto& kv : change_stream.frame_map()) {
-    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"frame\"}"),
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":{\"type\":\"frame\"}}"),
               base::JSONReader::Read(kv.second->description_json));
   }
   EXPECT_EQ(1u, change_stream.worker_map().size());
   for (const auto& kv : change_stream.worker_map()) {
-    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"worker\"}"),
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":{\"type\":\"worker\"}}"),
               base::JSONReader::Read(kv.second->description_json));
   }
 
@@ -263,7 +273,7 @@
     const auto& page = kv.second;
     EXPECT_NE(0u, page->id);
     EXPECT_EQ(kExampleUrl, page->main_frame_url);
-    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"page\"}"),
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":{\"type\":\"page\"}}"),
               base::JSONReader::Read(kv.second->description_json));
   }
 
@@ -315,7 +325,9 @@
                 absl::optional<base::Value> v =
                     base::JSONReader::Read(kv.second);
                 EXPECT_TRUE(v->is_dict());
-                std::string* str = v->GetDict().FindString("test");
+                base::Value::Dict* dict = v->GetDict().FindDict("test");
+                EXPECT_TRUE(dict);
+                std::string* str = dict->FindString("type");
                 EXPECT_TRUE(str);
                 if (str) {
                   EXPECT_TRUE(*str == "frame" || *str == "page" ||
diff --git a/chrome/browser/ui/webui/settings/ash/privacy_section.cc b/chrome/browser/ui/webui/settings/ash/privacy_section.cc
index 1c9b709..2b1b34a 100644
--- a/chrome/browser/ui/webui/settings/ash/privacy_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/privacy_section.cc
@@ -69,7 +69,13 @@
     if (!IsGuestModeActive()) {
       all_tags.insert(
           all_tags.end(),
-          {{IDS_OS_SETTINGS_TAG_GUEST_BROWSING,
+          {{IDS_OS_SETTINGS_TAG_MANAGE_OTHER_PEOPLE_PAGE,
+            mojom::kManageOtherPeopleSubpagePathV2,
+            mojom::SearchResultIcon::kAvatar,
+            mojom::SearchResultDefaultRank::kMedium,
+            mojom::SearchResultType::kSubpage,
+            {.subpage = mojom::Subpage::kManageOtherPeopleV2}},
+           {IDS_OS_SETTINGS_TAG_GUEST_BROWSING,
             mojom::kManageOtherPeopleSubpagePathV2,
             mojom::SearchResultIcon::kAvatar,
             mojom::SearchResultDefaultRank::kMedium,
diff --git a/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc b/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc
index f49b6dd..05efbdc 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc
@@ -190,6 +190,13 @@
 
   if (state_provider() && state_provider()->GetLastActiveWindowState(
                               bounds_in_screen, show_state)) {
+    // TODO(crbug.com/1413902): This is broken when the last active window is
+    // minimized as bounds_in_screen doesn't get updated. If
+    // GetLastActiveWindowState can return false for minimized windows, this
+    // code can be reverted.
+    if (bounds_in_screen->IsEmpty()) {
+      return false;
+    }
     bounds_in_screen->Offset(kWindowTilePixels, kWindowTilePixels);
     // Adjusting bounds_in_screen to fit on the display as returned by
     // GetDisplayForNewWindow here matches behavior for tabbed browsers above.
diff --git a/chrome/browser/updater/browser_updater_client.cc b/chrome/browser/updater/browser_updater_client.cc
index ad69cad8..15502bb8 100644
--- a/chrome/browser/updater/browser_updater_client.cc
+++ b/chrome/browser/updater/browser_updater_client.cc
@@ -80,11 +80,7 @@
   update_service_->Update(
       GetAppId(), {}, updater::UpdateService::Priority::kForeground,
       updater::UpdateService::PolicySameVersionUpdate::kNotAllowed,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
       /*do_update_check_only=*/false,
-#endif  // BUILDFLAG(IS_WIN)
       base::BindPostTaskToCurrentDefault(version_updater_callback),
       base::BindPostTaskToCurrentDefault(
           base::BindOnce(&BrowserUpdaterClient::UpdateCompleted, this,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index af8b28b..cefc09c 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1675857453-00018d09b9488676f4e62fc4f098a70b914f341a.profdata
+chrome-linux-main-1675879071-de5449db0835d4307884608d78cf4d6584967438.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index babe15ee..e18b902a 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1675857453-c87864e17e0f2a3bd15e535ebfe767753033cf18.profdata
+chrome-mac-arm-main-1675879071-6cd22de8f284233159de30900fd9fc75243c54f7.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index c31e4c96..388bd0b5 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1675857453-c29bcc0492cb2a435201d8b25ab39d03f6d9b35c.profdata
+chrome-mac-main-1675879071-c69d906359361007cc25c3ef6e5ea3cd157e520b.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index a2a8407..67b99b7 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1675868378-1e5d86b1ee35f4a2c318fa716bb9027e93de9907.profdata
+chrome-win32-main-1675879071-8fca267e557ec8e1bab890f1c20615c0722cf40e.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 518173e..05e3e35b 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1675857453-9990fd0751f03d7fab84708b7f6d36993476a38e.profdata
+chrome-win64-main-1675879071-77b76da3619883a65bed54afa16213373c0343a7.profdata
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index 30bb27e5..a5b0e4db0 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -173,15 +173,14 @@
       return LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR;
     } else if (logging_destination != "") {
       PLOG(ERROR) << "Invalid logging destination: " << logging_destination;
-    }
 #if BUILDFLAG(IS_WIN)
-    else if (base::IsCurrentProcessInAppContainer() &&
-             !command_line.HasSwitch(switches::kLogFile)) {
+    } else if (base::IsCurrentProcessInAppContainer() &&
+               !command_line.HasSwitch(switches::kLogFile)) {
       // Sandboxed appcontainer processes are unable to resolve the default log
       // file path without asserting.
       return kDefaultLoggingMode & ~LOG_TO_FILE;
-    }
 #endif
+    }
   }
   return kDefaultLoggingMode;
 }
@@ -494,15 +493,38 @@
 }
 
 base::FilePath GetLogFileName(const base::CommandLine& command_line) {
+  // Try the command line.
   auto filename = command_line.GetSwitchValueNative(switches::kLogFile);
-  if (!filename.empty())
-    return base::FilePath(filename);
+  // Try the environment.
+  if (filename.empty()) {
+    std::string env_filename;
+    base::Environment::Create()->GetVar(env_vars::kLogFileName, &env_filename);
+#if BUILDFLAG(IS_WIN)
+    filename = base::UTF8ToWide(env_filename);
+#else
+    filename = env_filename;
+#endif  // BUILDFLAG(IS_WIN)
+  }
 
-  std::string env_filename;
-  base::Environment::Create()->GetVar(env_vars::kLogFileName, &env_filename);
-  if (!env_filename.empty())
-    return base::FilePath::FromUTF8Unsafe(env_filename);
+  if (!filename.empty()) {
+    base::FilePath candidate_path(filename);
+#if BUILDFLAG(IS_WIN)
+    // Windows requires an absolute path for the --log-file switch. Windows
+    // cannot log to the current directory as it cds() to the exe's directory
+    // earlier than this function runs.
+    candidate_path = candidate_path.NormalizePathSeparators();
+    if (candidate_path.IsAbsolute()) {
+      return candidate_path;
+    } else {
+      PLOG(ERROR) << "Invalid logging destination: " << filename;
+    }
+#else
+    return candidate_path;
+#endif  // BUILDFLAG(IS_WIN)
+  }
 
+  // If command line and environment do not provide a log file we can use,
+  // fallback to the default.
   const base::FilePath log_filename(FILE_PATH_LITERAL("chrome_debug.log"));
   base::FilePath log_path;
 
@@ -510,8 +532,13 @@
     log_path = log_path.Append(log_filename);
     return log_path;
   } else {
-    // error with path service, just use some default file somewhere
+#if BUILDFLAG(IS_WIN)
+    // On Windows we cannot use a non-absolute path so we cannot provide a file.
+    return base::FilePath();
+#else
+    // Error with path service, just use the default in our current directory.
     return log_filename;
+#endif  // BUILDFLAG(IS_WIN)
   }
 }
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java
index 69e71d25..d73dae01 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java
@@ -39,7 +39,7 @@
     // Increase the default timeout, as it can take a long time for Android to
     // fully stop/start Chrome.
     private static final long CHROME_STOP_START_TIMEOUT_MS =
-            Math.max(20000L, CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL);
+            Math.max(10000L, CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL);
 
     private static PowerManager.WakeLock sWakeLock;
 
diff --git a/chrome/test/data/extensions/api_test/tabs/basics/duplicate.js b/chrome/test/data/extensions/api_test/tabs/basics/duplicate.js
index cd57818..a796c3d 100644
--- a/chrome/test/data/extensions/api_test/tabs/basics/duplicate.js
+++ b/chrome/test/data/extensions/api_test/tabs/basics/duplicate.js
@@ -34,8 +34,7 @@
       }));
   },
 
-  // TODO(crbug.com/149924): This test was broken by
-  // https://chromium-review.googlesource.com/c/chromium/src/+/3029302
+  // TODO(crbug.com/149924): This test was broken by crrev.com/c/3029302.
 /*
   function duplicateTabFromNewPopupWindow() {
     chrome.windows.create({
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
index e155569..8aee938c 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -80,25 +80,6 @@
             '#toggleRowPlaceholder');
     assertTrue(!!toggleRowPlaceholder);
 
-    personalizationStore.data.ambient.ambientModeEnabled = false;
-    personalizationStore.notifyObservers();
-    await waitAfterNextRender(ambientSubpageElement);
-
-    // Ambient mode is loaded, should not show toggle row placeholder.
-    assertTrue(!!toggleRowPlaceholder);
-    assertEquals(getComputedStyle(toggleRowPlaceholder).display, 'none');
-
-    const toggleRow =
-        ambientSubpageElement.shadowRoot!.querySelector('toggle-row');
-    assertTrue(!!toggleRow, 'toggle-row element exists');
-    const toggleButton = toggleRow!.shadowRoot!.querySelector('cr-toggle');
-    assertTrue(!!toggleButton, 'cr-toggle element exists');
-    assertFalse(toggleButton!.checked);
-
-    personalizationStore.data.ambient.ambientModeEnabled = true;
-    personalizationStore.notifyObservers();
-    await waitAfterNextRender(ambientSubpageElement);
-
     // Preview element should show placeholders for preview images, preview
     // album info and preview album collage.
     const ambientPreview = ambientSubpageElement.shadowRoot!.querySelector(
@@ -138,6 +119,7 @@
             '#weatherUnitTextPlaceholder:not([hidden])');
     assertEquals(2, weatherUnitItemPlaceholders!.length);
 
+    personalizationStore.data.ambient.ambientModeEnabled = false;
     personalizationStore.data.ambient.albums = ambientProvider.albums;
     personalizationStore.data.ambient.topicSource = TopicSource.kGooglePhotos;
     personalizationStore.data.ambient.temperatureUnit =
@@ -145,6 +127,18 @@
     personalizationStore.notifyObservers();
     await waitAfterNextRender(ambientSubpageElement);
 
+    // Loading finished, should not show toggle row placeholder.
+    assertTrue(!!toggleRowPlaceholder);
+    assertEquals(getComputedStyle(toggleRowPlaceholder).display, 'none');
+
+    // Toggle row is shown but in off status (the button is unchecked).
+    const toggleRow =
+        ambientSubpageElement.shadowRoot!.querySelector('toggle-row');
+    assertTrue(!!toggleRow, 'toggle-row element exists');
+    const toggleButton = toggleRow!.shadowRoot!.querySelector('cr-toggle');
+    assertTrue(!!toggleButton, 'cr-toggle element exists');
+    assertFalse(toggleButton!.checked);
+
     // Placeholders will be hidden for animation theme, topic source
     // and temperature unit elements.
     assertTrue(!!animationThemePlaceholder);
diff --git a/chrome/updater/app/app_install.cc b/chrome/updater/app/app_install.cc
index dc7ba861..d6fd19f9 100644
--- a/chrome/updater/app/app_install.cc
+++ b/chrome/updater/app/app_install.cc
@@ -10,13 +10,10 @@
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/command_line.h"
-#include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/i18n/icu_util.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/notreached.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
@@ -24,7 +21,6 @@
 #include "build/build_config.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/external_constants.h"
-#include "chrome/updater/persisted_data.h"
 #include "chrome/updater/prefs.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/service_proxy_factory.h"
diff --git a/chrome/updater/app/app_install_win.cc b/chrome/updater/app/app_install_win.cc
index 98e3ff13..c773a3b 100644
--- a/chrome/updater/app/app_install_win.cc
+++ b/chrome/updater/app/app_install_win.cc
@@ -25,7 +25,6 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/process/launch.h"
 #include "base/sequence_checker.h"
 #include "base/strings/escape.h"
 #include "base/strings/strcat.h"
@@ -39,11 +38,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "base/win/atl.h"
 #include "base/win/registry.h"
-#include "base/win/scoped_bstr.h"
-#include "base/win/scoped_variant.h"
-#include "base/win/shlwapi.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/service_proxy_factory.h"
 #include "chrome/updater/update_service.h"
@@ -54,9 +49,7 @@
 #include "chrome/updater/util/win_util.h"
 #include "chrome/updater/win/install_progress_observer.h"
 #include "chrome/updater/win/manifest_util.h"
-#include "chrome/updater/win/scoped_impersonation.h"
 #include "chrome/updater/win/ui/resources/resources.grh"
-#include "chrome/updater/win/user_info.h"
 #include "chrome/updater/win/win_constants.h"
 
 #pragma clang diagnostic push
@@ -65,7 +58,6 @@
 #include "chrome/updater/win/ui/progress_wnd.h"
 #include "chrome/updater/win/ui/resources/updater_installer_strings.h"
 #include "chrome/updater/win/ui/splash_screen.h"
-#include "chrome/updater/win/ui/ui_util.h"
 #pragma clang diagnostic pop
 
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -495,10 +487,12 @@
   request.app_id = app_id_;
   absl::optional<tagging::AppArgs> app_args = GetAppArgs(app_id_);
   absl::optional<tagging::TagArgs> tag_args = GetTagArgs().tag_args;
-  if (app_args)
+  if (app_args) {
     request.ap = app_args->ap;
-  if (tag_args)
+  }
+  if (tag_args) {
     request.brand_code = tag_args->brand_code;
+  }
 
   base::ThreadPool::PostTaskAndReply(
       FROM_HERE,
@@ -616,10 +610,12 @@
 
   absl::optional<tagging::AppArgs> app_args =
       GetAppArgsForCommandLine(cmd_line, app_id_);
-  if (app_args)
+  if (app_args) {
     request.ap = app_args->ap;
-  if (tag_args)
+  }
+  if (tag_args) {
     request.brand_code = tag_args->brand_code;
+  }
 
   VLOG(1) << __func__ << ": " << installer_path << ": " << install_args << ": "
           << install_data;
diff --git a/chrome/updater/app/app_server.cc b/chrome/updater/app/app_server.cc
index ef28150..c81bad5c 100644
--- a/chrome/updater/app/app_server.cc
+++ b/chrome/updater/app/app_server.cc
@@ -95,8 +95,9 @@
   }
 
   if (this_version > active_version || global_prefs->GetSwapping()) {
-    if (!SwapVersions(global_prefs.get()))
+    if (!SwapVersions(global_prefs.get())) {
       return base::BindOnce(&AppServer::Shutdown, this, kErrorFailedToSwap);
+    }
   }
 
   if (IsInternalService()) {
@@ -113,8 +114,9 @@
 }
 
 void AppServer::Uninitialize() {
-  if (prefs_)
+  if (prefs_) {
     PrefsCommitPendingWrites(prefs_->GetPrefService());
+  }
   if (uninstall_self_) {
     VLOG(1) << "Uninstalling version " << kUpdaterVersion;
     UninstallSelf();
@@ -124,8 +126,9 @@
 }
 
 void AppServer::MaybeUninstall() {
-  if (!prefs_)
+  if (!prefs_) {
     return;
+  }
 
   auto persisted_data = base::MakeRefCounted<PersistedData>(
       updater_scope(), prefs_->GetPrefService());
@@ -161,8 +164,9 @@
 bool AppServer::SwapVersions(GlobalPrefs* global_prefs) {
   global_prefs->SetSwapping(true);
   PrefsCommitPendingWrites(global_prefs->GetPrefService());
-  if (!SwapInNewVersion())
+  if (!SwapInNewVersion()) {
     return false;
+  }
   if (!global_prefs->GetMigratedLegacyUpdaters()) {
     if (!MigrateLegacyUpdaters(base::BindRepeating(
             &PersistedData::RegisterApp,
diff --git a/chrome/updater/app/app_server.h b/chrome/updater/app/app_server.h
index 2020f85..90303666 100644
--- a/chrome/updater/app/app_server.h
+++ b/chrome/updater/app/app_server.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_UPDATER_APP_APP_SERVER_H_
 #define CHROME_UPDATER_APP_APP_SERVER_H_
 
-#include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/updater/app/app.h"
diff --git a/chrome/updater/app/app_server_unittest.cc b/chrome/updater/app/app_server_unittest.cc
index d533d14f0..abc784a 100644
--- a/chrome/updater/app/app_server_unittest.cc
+++ b/chrome/updater/app/app_server_unittest.cc
@@ -10,10 +10,8 @@
 #include "base/files/file_util.h"
 #include "base/functional/callback.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/message_loop/message_pump_type.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
-#include "chrome/updater/constants.h"
 #include "chrome/updater/prefs.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/update_service_internal.h"
diff --git a/chrome/updater/app/app_update.cc b/chrome/updater/app/app_update.cc
index ef63910..daa0a5d 100644
--- a/chrome/updater/app/app_update.cc
+++ b/chrome/updater/app/app_update.cc
@@ -6,7 +6,6 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/task/sequenced_task_runner.h"
 #include "chrome/updater/app/app.h"
 #include "chrome/updater/setup.h"
 
@@ -22,11 +21,9 @@
   void SetupDone(int result);
 };
 
-void AppUpdate::Initialize() {
-}
+void AppUpdate::Initialize() {}
 
-void AppUpdate::Uninitialize() {
-}
+void AppUpdate::Uninitialize() {}
 
 void AppUpdate::FirstTaskRun() {
   InstallCandidate(updater_scope(),
diff --git a/chrome/updater/app/server/posix/mojom/updater_service.mojom b/chrome/updater/app/server/posix/mojom/updater_service.mojom
index f633b157..7320cd6 100644
--- a/chrome/updater/app/server/posix/mojom/updater_service.mojom
+++ b/chrome/updater/app/server/posix/mojom/updater_service.mojom
@@ -247,7 +247,10 @@
     Priority priority,
 
     //  Whether a same-version update is allowed.
-    PolicySameVersionUpdate policy_same_version_update) =>
+    PolicySameVersionUpdate policy_same_version_update,
+
+    // Only checks for updates if `do_update_check_only` is `true`.
+    [MinVersion=1] bool do_update_check_only) =>
     (pending_receiver<StateChangeObserver> observer);
 
   // Registers and installs an application from the network.
diff --git a/chrome/updater/app/server/posix/rpc_unittests.cc b/chrome/updater/app/server/posix/rpc_unittests.cc
index 9c8c098..c795fdc 100644
--- a/chrome/updater/app/server/posix/rpc_unittests.cc
+++ b/chrome/updater/app/server/posix/rpc_unittests.cc
@@ -8,16 +8,13 @@
 #include <utility>
 #include <vector>
 
-#include "base/base_paths.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/path_service.h"
 #include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
@@ -27,20 +24,14 @@
 #include "base/test/test_timeouts.h"
 #include "base/time/time.h"
 #include "base/version.h"
-#include "chrome/updater/app/server/posix/mojom/updater_service.mojom.h"
 #include "chrome/updater/app/server/posix/update_service_internal_stub.h"
 #include "chrome/updater/app/server/posix/update_service_stub.h"
 #include "chrome/updater/ipc/ipc_support.h"
-#include "chrome/updater/ipc/update_service_internal_proxy_posix.h"
-#include "chrome/updater/ipc/update_service_proxy_posix.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/service_proxy_factory.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_scope.h"
 #include "chrome/updater/util/util.h"
-#include "mojo/core/embedder/configuration.h"
-#include "mojo/core/embedder/embedder.h"
-#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
@@ -197,6 +188,7 @@
                  const std::string& install_data_index,
                  Priority priority,
                  PolicySameVersionUpdate policy_same_version_update,
+                 bool do_update_check_only,
                  StateChangeCallback state_update,
                  Callback callback),
                 (override));
@@ -271,6 +263,7 @@
           [](const std::string& app_id, const std::string& install_data_index,
              UpdateService::Priority priority,
              UpdateService::PolicySameVersionUpdate policy_same_version_update,
+             bool do_update_check_only,
              UpdateService::StateChangeCallback state_change_callback,
              UpdateService::Callback callback) {
             EXPECT_EQ(app_id, "ex1");
@@ -411,6 +404,7 @@
     client_proxy->Update("ex1", "install_data_index",
                          UpdateService::Priority::kBackground,
                          UpdateService::PolicySameVersionUpdate::kAllowed,
+                         /*do_update_check_only=*/false,
                          UpdaterIPCTestCase::ExpectUpdateStatesCallback(),
                          UpdaterIPCTestCase::ExpectResultCallback(run_loop));
     run_loop.Run();
diff --git a/chrome/updater/app/server/posix/update_service_internal_stub.cc b/chrome/updater/app/server/posix/update_service_internal_stub.cc
index 84de1c8..997fac8 100644
--- a/chrome/updater/app/server/posix/update_service_internal_stub.cc
+++ b/chrome/updater/app/server/posix/update_service_internal_stub.cc
@@ -7,16 +7,11 @@
 #include <iterator>
 #include <utility>
 
-#include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/process/process_handle.h"
-#include "chrome/updater/app/server/posix/mojom/updater_service_internal.mojom-forward.h"
 #include "chrome/updater/ipc/ipc_names.h"
 #include "chrome/updater/ipc/ipc_security.h"
-#include "chrome/updater/updater_version.h"
 #include "components/named_mojo_ipc_server/connection_info.h"
 #include "components/named_mojo_ipc_server/named_mojo_ipc_server.h"
 
diff --git a/chrome/updater/app/server/posix/update_service_stub.cc b/chrome/updater/app/server/posix/update_service_stub.cc
index 3b2c676..0a4cde8 100644
--- a/chrome/updater/app/server/posix/update_service_stub.cc
+++ b/chrome/updater/app/server/posix/update_service_stub.cc
@@ -15,7 +15,6 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/process/process_handle.h"
 #include "base/ranges/algorithm.h"
 #include "base/sequence_checker.h"
 #include "base/version.h"
@@ -23,7 +22,6 @@
 #include "chrome/updater/ipc/ipc_names.h"
 #include "chrome/updater/ipc/ipc_security.h"
 #include "chrome/updater/registration_data.h"
-#include "chrome/updater/updater_version.h"
 #include "components/named_mojo_ipc_server/connection_info.h"
 #include "components/named_mojo_ipc_server/endpoint_options.h"
 #include "components/named_mojo_ipc_server/named_mojo_ipc_server.h"
@@ -130,10 +128,12 @@
               const std::string& install_data_index,
               UpdateService::Priority priority,
               UpdateService::PolicySameVersionUpdate policy_same_version_update,
+              bool do_update_check_only,
               UpdateCallback callback) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     impl_->Update(app_id, install_data_index, priority,
-                  policy_same_version_update, std::move(callback));
+                  policy_same_version_update, do_update_check_only,
+                  std::move(callback));
   }
 
   // The rest of updater::mojom::UpdateService is rejected.
@@ -296,6 +296,7 @@
     const std::string& install_data_index,
     UpdateService::Priority priority,
     UpdateService::PolicySameVersionUpdate policy_same_version_update,
+    bool do_update_check_only,
     UpdateCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   task_start_listener_.Run();
@@ -308,7 +309,7 @@
                 static_cast<updater::UpdateService::Priority>(priority),
                 static_cast<updater::UpdateService::PolicySameVersionUpdate>(
                     policy_same_version_update),
-                state_change_callback,
+                do_update_check_only, state_change_callback,
                 std::move(on_complete_callback).Then(task_end_listener_));
 }
 
diff --git a/chrome/updater/app/server/posix/update_service_stub.h b/chrome/updater/app/server/posix/update_service_stub.h
index 82ea7c36..e54c7918 100644
--- a/chrome/updater/app/server/posix/update_service_stub.h
+++ b/chrome/updater/app/server/posix/update_service_stub.h
@@ -44,6 +44,7 @@
               const std::string& install_data_index,
               UpdateService::Priority priority,
               UpdateService::PolicySameVersionUpdate policy_same_version_update,
+              bool do_update_check_only,
               UpdateCallback callback) override;
   void Install(mojom::RegistrationRequestPtr registration,
                const std::string& client_install_data,
diff --git a/chrome/updater/app/server/win/com_classes.h b/chrome/updater/app/server/win/com_classes.h
index b15633f..e5d688b 100644
--- a/chrome/updater/app/server/win/com_classes.h
+++ b/chrome/updater/app/server/win/com_classes.h
@@ -13,7 +13,6 @@
 #include "chrome/updater/app/server/win/updater_idl.h"
 #include "chrome/updater/app/server/win/updater_internal_idl.h"
 #include "chrome/updater/update_service.h"
-#include "chrome/updater/updater_scope.h"
 #include "chrome/updater/util/win_util.h"
 
 // Definitions for native COM updater classes.
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index a9819cd..2cef945 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -14,15 +14,11 @@
 
 #include "base/check.h"
 #include "base/check_op.h"
-#include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/path_service.h"
-#include "base/process/launch.h"
 #include "base/process/process.h"
-#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -33,14 +29,10 @@
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "base/types/expected.h"
-#include "base/win/registry.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_handle.h"
-#include "base/win/scoped_process_information.h"
-#include "base/win/win_util.h"
 #include "chrome/updater/app/server/win/server.h"
 #include "chrome/updater/constants.h"
-#include "chrome/updater/external_constants.h"
 #include "chrome/updater/persisted_data.h"
 #include "chrome/updater/policy/manager.h"
 #include "chrome/updater/policy/service.h"
@@ -53,7 +45,6 @@
 #include "chrome/updater/win/app_command_runner.h"
 #include "chrome/updater/win/scoped_handle.h"
 #include "chrome/updater/win/setup/setup_util.h"
-#include "chrome/updater/win/win_constants.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace {
@@ -634,8 +625,9 @@
   IFACEMETHODIMP createInstalledApp(BSTR app_id) override {
     base::AutoLock lock{lock_};
 
-    if (app_web_)
+    if (app_web_) {
       return E_UNEXPECTED;
+    }
 
     return Microsoft::WRL::MakeAndInitialize<AppWebImpl>(&app_web_, app_id);
   }
@@ -662,8 +654,9 @@
   IFACEMETHODIMP get_appWeb(int index, IDispatch** app_web) override {
     base::AutoLock lock{lock_};
 
-    if (index != 0 || !app_web_)
+    if (index != 0 || !app_web_) {
       return E_UNEXPECTED;
+    }
 
     return app_web_.CopyTo(app_web);
   }
@@ -674,8 +667,9 @@
   IFACEMETHODIMP checkForUpdate() override {
     base::AutoLock lock{lock_};
 
-    if (!app_web_)
+    if (!app_web_) {
       return E_UNEXPECTED;
+    }
 
     return app_web_->Update(/*do_update_check_only=*/true);
   }
@@ -862,8 +856,9 @@
         substitution9}) {
     const absl::optional<std::wstring> substitution_string =
         StringFromVariant(substitution);
-    if (!substitution_string)
+    if (!substitution_string) {
       break;
+    }
 
     VLOG(2) << __func__
             << " substitution_string: " << substitution_string.value();
@@ -887,8 +882,9 @@
   DCHECK(minutes);
 
   PolicyStatus<base::TimeDelta> period = policy_service_->GetLastCheckPeriod();
-  if (!period)
+  if (!period) {
     return E_FAIL;
+  }
 
   *minutes = period.policy().InMinutes();
   return S_OK;
@@ -1104,8 +1100,9 @@
                     GetUpdaterScope(),
                     AppServerSingletonInstance()->prefs()->GetPrefService())
                     ->GetLastChecked();
-            if (last_checked_time.is_null())
+            if (last_checked_time.is_null()) {
               return;
+            }
 
             const FILETIME last_checked_filetime =
                 last_checked_time.ToFileTime();
@@ -1164,12 +1161,14 @@
   auto policy_status =
       PolicyStatusResult<UpdatesSuppressedTimes>::Get(base::BindRepeating(
           &PolicyService::GetUpdatesSuppressedTimes, policy_service_));
-  if (!policy_status.has_value())
+  if (!policy_status.has_value()) {
     return E_FAIL;
+  }
   const UpdatesSuppressedTimes updates_suppressed_times =
       policy_status->effective_policy()->policy;
-  if (!updates_suppressed_times.valid())
+  if (!updates_suppressed_times.valid()) {
     return E_FAIL;
+  }
   base::Time::Exploded now;
   base::Time::Now().LocalExplode(&now);
   *are_updates_suppressed =
diff --git a/chrome/updater/app/server/win/com_classes_legacy.h b/chrome/updater/app/server/win/com_classes_legacy.h
index c449478..8e9fa168 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.h
+++ b/chrome/updater/app/server/win/com_classes_legacy.h
@@ -16,7 +16,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/path_service.h"
 #include "base/process/process.h"
-#include "base/synchronization/lock.h"
 #include "base/types/expected.h"
 #include "base/win/win_util.h"
 #include "chrome/updater/app/server/win/updater_legacy_idl.h"
@@ -27,7 +26,6 @@
 #include "chrome/updater/util/win_util.h"
 #include "chrome/updater/win/app_command_runner.h"
 #include "chrome/updater/win/setup/setup_util.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 // Definitions for COM updater classes provided for backward compatibility
 // with Google Update.
@@ -53,8 +51,9 @@
 
   // Overrides for IDispatch.
   IFACEMETHODIMP GetTypeInfoCount(UINT* type_info_count) override {
-    if (FAILED(hr_load_typelib_))
+    if (FAILED(hr_load_typelib_)) {
       return hr_load_typelib_;
+    }
 
     *type_info_count = 1;
     return S_OK;
@@ -63,8 +62,9 @@
   IFACEMETHODIMP GetTypeInfo(UINT type_info_index,
                              LCID locale_id,
                              ITypeInfo** type_info) override {
-    if (FAILED(hr_load_typelib_))
+    if (FAILED(hr_load_typelib_)) {
       return hr_load_typelib_;
+    }
 
     return type_info_index == 0 ? type_info_.CopyTo(type_info) : E_INVALIDARG;
   }
@@ -74,8 +74,9 @@
                                UINT count_of_names_to_be_mapped,
                                LCID locale_id,
                                DISPID* dispatch_ids) override {
-    if (FAILED(hr_load_typelib_))
+    if (FAILED(hr_load_typelib_)) {
       return hr_load_typelib_;
+    }
 
     return type_info_->GetIDsOfNames(names_to_be_mapped,
                                      count_of_names_to_be_mapped, dispatch_ids);
@@ -89,8 +90,9 @@
                         VARIANT* result,
                         EXCEPINFO* exception_info,
                         UINT* arg_error_index) override {
-    if (FAILED(hr_load_typelib_))
+    if (FAILED(hr_load_typelib_)) {
       return hr_load_typelib_;
+    }
 
     HRESULT hr = type_info_->Invoke(Microsoft::WRL::ComPtr<T>(this).Get(),
                                     dispatch_id, flags, dispatch_parameters,
@@ -104,8 +106,9 @@
   // Loads the typelib and typeinfo for interface `T`.
   HRESULT InitializeTypeInfo() {
     base::FilePath typelib_path;
-    if (!base::PathService::Get(base::DIR_EXE, &typelib_path))
+    if (!base::PathService::Get(base::DIR_EXE, &typelib_path)) {
       return E_UNEXPECTED;
+    }
 
     typelib_path = typelib_path.Append(GetExecutableRelativePath())
                        .Append(GetComTypeLibResourceIndex(__uuidof(T)));
diff --git a/chrome/updater/app/server/win/com_classes_legacy_unittest.cc b/chrome/updater/app/server/win/com_classes_legacy_unittest.cc
index cebcd864..2b6b12b 100644
--- a/chrome/updater/app/server/win/com_classes_legacy_unittest.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy_unittest.cc
@@ -13,16 +13,11 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/bind.h"
-#include "base/test/test_timeouts.h"
-#include "base/time/time.h"
-#include "base/win/scoped_handle.h"
 #include "base/win/scoped_variant.h"
 #include "base/win/win_util.h"
 #include "build/branding_buildflags.h"
@@ -31,13 +26,11 @@
 #include "chrome/updater/util/unittest_util.h"
 #include "chrome/updater/util/unittest_util_win.h"
 #include "chrome/updater/util/util.h"
-#include "chrome/updater/util/win_util.h"
 #include "chrome/updater/win/setup/setup_util.h"
 #include "chrome/updater/win/test/test_executables.h"
 #include "chrome/updater/win/test/test_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace updater {
 namespace {
@@ -185,8 +178,9 @@
 }
 
 TEST_F(LegacyAppCommandWebImplTest, CommandRunningStatus) {
-  if (IsSystemInstall(GetTestScope()))
+  if (IsSystemInstall(GetTestScope())) {
     return;
+  }
 
   Microsoft::WRL::ComPtr<LegacyAppCommandWebImpl> app_command_web;
   base::CommandLine command_line =
diff --git a/chrome/updater/app/server/win/server.cc b/chrome/updater/app/server/win/server.cc
index 45672e1..3c6750f 100644
--- a/chrome/updater/app/server/win/server.cc
+++ b/chrome/updater/app/server/win/server.cc
@@ -18,8 +18,6 @@
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
 #include "base/strings/strcat.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -28,8 +26,6 @@
 #include "base/win/registry.h"
 #include "base/win/windows_types.h"
 #include "chrome/installer/util/work_item_list.h"
-#include "chrome/updater/app/server/win/com_classes.h"
-#include "chrome/updater/app/server/win/com_classes_legacy.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/update_service.h"
@@ -70,8 +66,9 @@
   // TODO(crbug.com/1270520) - use a switch that can uninstall immediately if
   // unused, instead of requiring server starts.
   uninstall_if_unused_command.AppendSwitch(kWakeSwitch);
-  if (IsSystemInstall(scope))
+  if (IsSystemInstall(scope)) {
     uninstall_if_unused_command.AppendSwitch(kSystemSwitch);
+  }
   uninstall_if_unused_command.AppendSwitch(kEnableLoggingSwitch);
   uninstall_if_unused_command.AppendSwitchASCII(kLoggingModuleSwitch,
                                                 kLoggingModuleSwitchValue);
@@ -149,8 +146,9 @@
 
   const absl::optional<base::FilePath> target_path =
       GetGoogleUpdateExePath(scope);
-  if (!target_path)
+  if (!target_path) {
     return false;
+  }
   list->AddCopyTreeWorkItem(updater_path, *target_path, temp_path,
                             WorkItem::ALWAYS);
 
@@ -236,8 +234,9 @@
   main_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
   CreateWRLModule();
   HRESULT hr = std::move(register_callback).Run();
-  if (FAILED(hr))
+  if (FAILED(hr)) {
     Shutdown(hr);
+  }
 }
 
 void ComServerApp::UninstallSelf() {
@@ -249,8 +248,9 @@
 
   const absl::optional<base::FilePath> versioned_directory =
       GetVersionedInstallDirectory(updater_scope());
-  if (!versioned_directory)
+  if (!versioned_directory) {
     return false;
+  }
 
   const base::FilePath updater_path =
       versioned_directory->Append(GetExecutableRelativePath());
@@ -260,8 +260,9 @@
   }
 
   absl::optional<base::ScopedTempDir> temp_dir = CreateSecureTempDir();
-  if (!temp_dir)
+  if (!temp_dir) {
     return false;
+  }
 
   if (!SwapGoogleUpdate(updater_scope(), updater_path, temp_dir->GetPath(),
                         UpdaterScopeToHKeyRoot(updater_scope()), list.get())) {
@@ -290,8 +291,9 @@
     const std::wstring app_id = it.Name();
 
     // Skip importing legacy updater.
-    if (base::EqualsCaseInsensitiveASCII(app_id, kLegacyGoogleUpdaterAppID))
+    if (base::EqualsCaseInsensitiveASCII(app_id, kLegacyGoogleUpdaterAppID)) {
       continue;
+    }
 
     base::win::RegKey key;
     if (key.Open(root, GetAppClientsKey(app_id).c_str(), Wow6432(KEY_READ)) !=
@@ -302,20 +304,24 @@
     RegistrationRequest registration;
     registration.app_id = base::SysWideToUTF8(app_id);
     std::wstring pv;
-    if (key.ReadValue(kRegValuePV, &pv) != ERROR_SUCCESS)
+    if (key.ReadValue(kRegValuePV, &pv) != ERROR_SUCCESS) {
       continue;
+    }
 
     registration.version = base::Version(base::SysWideToUTF8(pv));
-    if (!registration.version.IsValid())
+    if (!registration.version.IsValid()) {
       continue;
+    }
 
     std::wstring brand_code;
-    if (key.ReadValue(kRegValueBrandCode, &brand_code) == ERROR_SUCCESS)
+    if (key.ReadValue(kRegValueBrandCode, &brand_code) == ERROR_SUCCESS) {
       registration.brand_code = base::SysWideToUTF8(brand_code);
+    }
 
     std::wstring ap;
-    if (key.ReadValue(kRegValueAP, &ap) == ERROR_SUCCESS)
+    if (key.ReadValue(kRegValueAP, &ap) == ERROR_SUCCESS) {
       registration.ap = base::SysWideToUTF8(ap);
+    }
 
     register_callback.Run(registration);
   }
diff --git a/chrome/updater/app/server/win/server.h b/chrome/updater/app/server/win/server.h
index d931824..76e9fb03 100644
--- a/chrome/updater/app/server/win/server.h
+++ b/chrome/updater/app/server/win/server.h
@@ -11,7 +11,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/task/sequenced_task_runner.h"
-#include "chrome/updater/app/app.h"
 #include "chrome/updater/app/app_server.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/update_service_internal.h"
diff --git a/chrome/updater/app/server/win/service_main.cc b/chrome/updater/app/server/win/service_main.cc
index 765e42e..c3de27d0 100644
--- a/chrome/updater/app/server/win/service_main.cc
+++ b/chrome/updater/app/server/win/service_main.cc
@@ -11,18 +11,14 @@
 #include <type_traits>
 
 #include "base/command_line.h"
-#include "base/cxx17_backports.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/process/launch.h"
 #include "base/task/single_thread_task_executor.h"
 #include "base/win/scoped_com_initializer.h"
-#include "chrome/updater/app/server/win/com_classes.h"
-#include "chrome/updater/app/server/win/com_classes_legacy.h"
 #include "chrome/updater/app/server/win/server.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/util/win_util.h"
-#include "chrome/updater/win/win_constants.h"
 
 namespace updater {
 
@@ -59,8 +55,9 @@
 
 int ServiceMain::RunWindowsService(const base::CommandLine* command_line) {
   ServiceMain* service = ServiceMain::GetInstance();
-  if (!service->InitWithCommandLine(command_line))
+  if (!service->InitWithCommandLine(command_line)) {
     return ERROR_BAD_ARGUMENTS;
+  }
 
   int ret = service->Start();
   DCHECK_NE(ret, int{STILL_ACTIVE});
@@ -80,8 +77,9 @@
   }
 
   // Run interactively if needed.
-  if (command_line->HasSwitch(kConsoleSwitchName))
+  if (command_line->HasSwitch(kConsoleSwitchName)) {
     run_routine_ = &ServiceMain::RunInteractive;
+  }
 
   return true;
 }
@@ -186,8 +184,9 @@
   }
 
   HRESULT hr = InitializeComSecurity();
-  if (FAILED(hr))
+  if (FAILED(hr)) {
     return hr;
+  }
 
   return AppServerSingletonInstance()->Run();
 }
diff --git a/chrome/updater/app/server/win/service_main.h b/chrome/updater/app/server/win/service_main.h
index 41e596f3..8af9e03 100644
--- a/chrome/updater/app/server/win/service_main.h
+++ b/chrome/updater/app/server/win/service_main.h
@@ -8,7 +8,6 @@
 #include <windows.h>
 
 #include "base/no_destructor.h"
-#include "base/synchronization/waitable_event.h"
 #include "base/win/atl.h"
 
 namespace base {
diff --git a/chrome/updater/ipc/update_service_proxy_posix.cc b/chrome/updater/ipc/update_service_proxy_posix.cc
index da3d9fcf..962cf0e1 100644
--- a/chrome/updater/ipc/update_service_proxy_posix.cc
+++ b/chrome/updater/ipc/update_service_proxy_posix.cc
@@ -291,6 +291,7 @@
     const std::string& install_data_index,
     Priority priority,
     PolicySameVersionUpdate policy_same_version_update,
+    bool do_update_check_only,
     StateChangeCallback state_update,
     Callback callback) {
   VLOG(1) << __func__;
@@ -303,6 +304,7 @@
                   static_cast<mojom::UpdateService::Priority>(priority),
                   static_cast<mojom::UpdateService::PolicySameVersionUpdate>(
                       policy_same_version_update),
+                  do_update_check_only,
                   std::move(state_change_observer_callback));
 }
 
diff --git a/chrome/updater/ipc/update_service_proxy_posix.h b/chrome/updater/ipc/update_service_proxy_posix.h
index f7becb9..3cb5e87 100644
--- a/chrome/updater/ipc/update_service_proxy_posix.h
+++ b/chrome/updater/ipc/update_service_proxy_posix.h
@@ -63,6 +63,7 @@
               const std::string& install_data_index,
               Priority priority,
               PolicySameVersionUpdate policy_same_version_update,
+              bool do_update_check_only,
               StateChangeCallback state_update,
               Callback callback) override;
   void Install(const RegistrationRequest& registration,
diff --git a/chrome/updater/mac/keystone/ksadmin.mm b/chrome/updater/mac/keystone/ksadmin.mm
index f5790c9a..e50d474e 100644
--- a/chrome/updater/mac/keystone/ksadmin.mm
+++ b/chrome/updater/mac/keystone/ksadmin.mm
@@ -422,6 +422,7 @@
       HasSwitch(kCommandUserInitiated) ? UpdateService::Priority::kForeground
                                        : UpdateService::Priority::kBackground,
       UpdateService::PolicySameVersionUpdate::kNotAllowed,
+      /*do_update_check_only=*/false,
       base::BindRepeating([](const UpdateService::UpdateState& update_state) {
         if (update_state.state == UpdateService::UpdateState::State::kUpdated) {
           printf("Finished updating (errors=%d reboot=%s)\n", 0, "YES");
diff --git a/chrome/updater/test/integration_test_commands.h b/chrome/updater/test/integration_test_commands.h
index 6d15ee73..7ac38279 100644
--- a/chrome/updater/test/integration_test_commands.h
+++ b/chrome/updater/test/integration_test_commands.h
@@ -77,16 +77,9 @@
   virtual void RunWakeAll() const = 0;
   virtual void RunWakeActive(int exit_code) const = 0;
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   virtual void Update(const std::string& app_id,
                       const std::string& install_data_index,
                       bool do_update_check_only) const = 0;
-#else   // BUILDFLAG(IS_WIN)
-  virtual void Update(const std::string& app_id,
-                      const std::string& install_data_index) const = 0;
-#endif  // BUILDFLAG(IS_WIN)
 
   virtual void UpdateAll() const = 0;
   virtual void DeleteUpdaterDirectory() const = 0;
diff --git a/chrome/updater/test/integration_test_commands_system.cc b/chrome/updater/test/integration_test_commands_system.cc
index 0effb569..704fa5e 100644
--- a/chrome/updater/test/integration_test_commands_system.cc
+++ b/chrome/updater/test/integration_test_commands_system.cc
@@ -197,9 +197,6 @@
                {Param("exit_code", base::NumberToString(expected_exit_code))});
   }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   void Update(const std::string& app_id,
               const std::string& install_data_index,
               bool do_update_check_only) const override {
@@ -208,13 +205,6 @@
                           Param("do_update_check_only",
                                 do_update_check_only ? "true" : "false")});
   }
-#else   // BUILDFLAG(IS_WIN)
-  void Update(const std::string& app_id,
-              const std::string& install_data_index) const override {
-    RunCommand("update", {Param("app_id", app_id),
-                          Param("install_data_index", install_data_index)});
-  }
-#endif  // BUILDFLAG(IS_WIN)
 
   void UpdateAll() const override { RunCommand("update_all", {}); }
 
diff --git a/chrome/updater/test/integration_test_commands_user.cc b/chrome/updater/test/integration_test_commands_user.cc
index 4eb6b96..925e0af3 100644
--- a/chrome/updater/test/integration_test_commands_user.cc
+++ b/chrome/updater/test/integration_test_commands_user.cc
@@ -176,21 +176,12 @@
     updater::test::RunWakeActive(updater_scope_, exit_code);
   }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   void Update(const std::string& app_id,
               const std::string& install_data_index,
               bool do_update_check_only) const override {
     updater::test::Update(updater_scope_, app_id, install_data_index,
                           do_update_check_only);
   }
-#else   // BUILDFLAG(IS_WIN)
-  void Update(const std::string& app_id,
-              const std::string& install_data_index) const override {
-    updater::test::Update(updater_scope_, app_id, install_data_index);
-  }
-#endif  // BUILDFLAG(IS_WIN)
 
   void UpdateAll() const override { updater::test::UpdateAll(updater_scope_); }
 
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 412e81f..ce64bcf3 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -275,20 +275,11 @@
     test_commands_->RunWakeActive(exit_code);
   }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   void Update(const std::string& app_id,
               const std::string& install_data_index,
               bool do_update_check_only) {
     test_commands_->Update(app_id, install_data_index, do_update_check_only);
   }
-#else   // BUILDFLAG(IS_WIN)
-  void Update(const std::string& app_id,
-              const std::string& install_data_index) {
-    test_commands_->Update(app_id, install_data_index);
-  }
-#endif  // BUILDFLAG(IS_WIN)
 
   void UpdateAll() { test_commands_->UpdateAll(); }
 
@@ -566,9 +557,6 @@
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
 TEST_F(IntegrationTest, CheckForUpdate) {
   ScopedServer test_server(test_commands_);
   ASSERT_NO_FATAL_FAILURE(Install());
@@ -581,7 +569,6 @@
 
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
-#endif  // BUILDFLAG(IS_WIN)
 
 TEST_F(IntegrationTest, UpdateApp) {
   ScopedServer test_server(test_commands_);
@@ -598,15 +585,8 @@
   const std::string kInstallDataIndex("test_install_data_index");
   ASSERT_NO_FATAL_FAILURE(
       ExpectUpdateSequence(&test_server, kAppId, kInstallDataIndex, v1, v2));
-
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   ASSERT_NO_FATAL_FAILURE(Update(kAppId, kInstallDataIndex,
                                  /*do_update_check_only=*/false));
-#else   // BUILDFLAG(IS_WIN)
-  ASSERT_NO_FATAL_FAILURE(Update(kAppId, kInstallDataIndex));
-#endif  // BUILDFLAG(IS_WIN)
 
   ASSERT_TRUE(WaitForUpdaterExit());
   ASSERT_NO_FATAL_FAILURE(ExpectAppVersion(kAppId, v2));
diff --git a/chrome/updater/test/integration_tests_helper.cc b/chrome/updater/test/integration_tests_helper.cc
index 0a507621..4e5fcdbe 100644
--- a/chrome/updater/test/integration_tests_helper.cc
+++ b/chrome/updater/test/integration_tests_helper.cc
@@ -286,21 +286,11 @@
     {"run_wake_all", WithSystemScope(Wrap(&RunWakeAll))},
     {"run_wake_active",
      WithSwitch("exit_code", WithSystemScope(Wrap(&RunWakeActive)))},
-
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
     {"update",
      WithSwitch(
          "do_update_check_only",
          WithSwitch("install_data_index",
                     (WithSwitch("app_id", WithSystemScope(Wrap(&Update))))))},
-#else   // BUILDFLAG(IS_WIN)
-    {"update",
-     WithSwitch("install_data_index",
-                (WithSwitch("app_id", WithSystemScope(Wrap(&Update)))))},
-#endif  // BUILDFLAG(IS_WIN)
-
     {"update_all", WithSystemScope(Wrap(&UpdateAll))},
     {"delete_updater_directory",
      WithSystemScope(Wrap(&DeleteUpdaterDirectory))},
diff --git a/chrome/updater/test/integration_tests_impl.cc b/chrome/updater/test/integration_tests_impl.cc
index b239440..6ba6e13 100644
--- a/chrome/updater/test/integration_tests_impl.cc
+++ b/chrome/updater/test/integration_tests_impl.cc
@@ -372,9 +372,6 @@
   RunUpdaterWithSwitch(active_version, scope, kWakeSwitch, expected_exit_code);
 }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
 void Update(UpdaterScope scope,
             const std::string& app_id,
             const std::string& install_data_index,
@@ -389,21 +386,6 @@
           [&loop](UpdateService::Result result_unused) { loop.Quit(); }));
   loop.Run();
 }
-#else   // BUILDFLAG(IS_WIN)
-
-void Update(UpdaterScope scope,
-            const std::string& app_id,
-            const std::string& install_data_index) {
-  scoped_refptr<UpdateService> update_service = CreateUpdateServiceProxy(scope);
-  base::RunLoop loop;
-  update_service->Update(
-      app_id, install_data_index, UpdateService::Priority::kForeground,
-      UpdateService::PolicySameVersionUpdate::kNotAllowed, base::DoNothing(),
-      base::BindLambdaForTesting(
-          [&loop](UpdateService::Result result_unused) { loop.Quit(); }));
-  loop.Run();
-}
-#endif  // BUILDFLAG(IS_WIN)
 
 void UpdateAll(UpdaterScope scope) {
   scoped_refptr<UpdateService> update_service = CreateUpdateServiceProxy(scope);
@@ -707,11 +689,7 @@
   service_proxy->Update(
       app_id, install_data_index, UpdateService::Priority::kForeground,
       policy_same_version_update,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
       /*do_update_check_only=*/false,
-#endif  // BUILDFLAG(IS_WIN)
       base::BindLambdaForTesting([](const UpdateService::UpdateState&) {}),
       base::BindLambdaForTesting([&](UpdateService::Result result) {
         EXPECT_EQ(result, UpdateService::Result::kSuccess);
diff --git a/chrome/updater/test/integration_tests_impl.h b/chrome/updater/test/integration_tests_impl.h
index 1de19adb..da7aca2 100644
--- a/chrome/updater/test/integration_tests_impl.h
+++ b/chrome/updater/test/integration_tests_impl.h
@@ -101,20 +101,11 @@
 void RunWakeActive(UpdaterScope scope, int exit_code);
 
 // Invokes the active instance's UpdateService::Update (via RPC) for an app.
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
 void Update(UpdaterScope scope,
             const std::string& app_id,
             const std::string& install_data_index,
             bool do_update_check_only);
 
-#else   // BUILDFLAG(IS_WIN)
-void Update(UpdaterScope scope,
-            const std::string& app_id,
-            const std::string& install_data_index);
-#endif  // BUILDFLAG(IS_WIN)
-
 // Invokes the active instance's UpdateService::UpdateAll (via RPC).
 void UpdateAll(UpdaterScope scope);
 
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index 240adc86..cc634f4 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -265,6 +265,12 @@
       EXPECT_EQ(is_installed,
                 RegKeyExistsCOM(root, GetComServerAppidRegistryPath(clsid)));
     }
+
+    const std::wstring progid(GetProgIdForClsid(scope, clsid));
+    if (!progid.empty()) {
+      EXPECT_EQ(is_installed,
+                RegKeyExistsCOM(root, GetComProgIdRegistryPath(progid)));
+    }
   }
 
   for (const IID& iid :
@@ -558,6 +564,11 @@
     EXPECT_TRUE(DeleteRegKeyCOM(root, GetComServerClsidRegistryPath(clsid)));
     if (IsSystemInstall(scope))
       EXPECT_TRUE(DeleteRegKeyCOM(root, GetComServerAppidRegistryPath(clsid)));
+
+    const std::wstring progid(GetProgIdForClsid(scope, clsid));
+    if (!progid.empty()) {
+      EXPECT_TRUE(DeleteRegKeyCOM(root, GetComProgIdRegistryPath(progid)));
+    }
   }
 
   for (const IID& iid : JoinVectors(GetSideBySideInterfaces(scope),
@@ -769,6 +780,16 @@
                                                      : __uuidof(IUpdaterUser),
                               IID_PPV_ARGS_Helper(&updater)));
 
+    // Verifies that the progid for the legacy clsid is registered.
+    CLSID expected_clsid = {};
+    EXPECT_HRESULT_SUCCEEDED(::CLSIDFromProgID(
+        IsSystemInstall(scope) ? L"GoogleUpdate.Update3WebMachine"
+                               : L"GoogleUpdate.Update3WebUser",
+        &expected_clsid));
+    EXPECT_EQ(expected_clsid, IsSystemInstall(scope)
+                                  ? __uuidof(GoogleUpdate3WebSystemClass)
+                                  : __uuidof(GoogleUpdate3WebUserClass));
+
     for (const CLSID& clsid : [&scope]() -> std::vector<CLSID> {
            if (IsSystemInstall(scope)) {
              return {__uuidof(GoogleUpdate3WebSystemClass),
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h
index d0a5a3188..95e090a 100644
--- a/chrome/updater/update_service.h
+++ b/chrome/updater/update_service.h
@@ -236,11 +236,7 @@
   //   `install_data_index`: Index of the server install data.
   //   `priority`: Priority for processing this update.
   //   `policy_same_version_update`: Whether a same-version update is allowed.
-  //
-  // TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-  // done in separate CL.
-  //   Windows-only: `do_update_check_only`: Only checks for updates if `true`.
-  //
+  //   `do_update_check_only`: Only checks for updates if `true`.
   //   `state_update`: The callback will be invoked every time the update
   //     changes state when the engine starts. It will be called on the
   //     sequence used by the update service, so this callback must not block.
@@ -257,11 +253,7 @@
                       const std::string& install_data_index,
                       Priority priority,
                       PolicySameVersionUpdate policy_same_version_update,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
                       bool do_update_check_only,
-#endif  // BUILDFLAG(IS_WIN)
                       StateChangeCallback state_update,
                       Callback callback) = 0;
 
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index 095f38e..cf26a88 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -122,9 +122,6 @@
   }
 }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
 update_client::UpdateClient::CrxStateChangeCallback
 MakeUpdateClientCrxStateChangeCallbackForUpdateCheck(
     scoped_refptr<update_client::Configurator> config,
@@ -165,7 +162,6 @@
       },
       config, callback, base::MakeRefCounted<RefCountedState>());
 }
-#endif  // BUILDFLAG(IS_WIN)
 
 update_client::UpdateClient::CrxStateChangeCallback
 MakeUpdateClientCrxStateChangeCallback(
@@ -292,15 +288,6 @@
   if (request.app_id != kUpdaterAppId) {
     persisted_data_->SetHadApps();
   }
-  base::Version current_version =
-      persisted_data_->GetProductVersion(request.app_id);
-  if (current_version.IsValid() &&
-      current_version.CompareTo(request.version) == 1) {
-    main_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(callback), kRegistrationAlreadyRegistered));
-    return;
-  }
   persisted_data_->RegisterApp(request);
   std::move(callback).Run(kRegistrationSuccess);
 }
@@ -479,11 +466,7 @@
     const std::string& install_data_index,
     Priority priority,
     PolicySameVersionUpdate policy_same_version_update,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
     bool do_update_check_only,
-#endif  // BUILDFLAG(IS_WIN)
     StateChangeCallback state_update,
     Callback callback) {
   VLOG(1) << __func__;
@@ -496,9 +479,6 @@
     return;
   }
 
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
   if (do_update_check_only) {
     main_task_runner_->PostTask(
         FROM_HERE,
@@ -517,7 +497,6 @@
             MakeUpdateClientCallback(std::move(callback))));
     return;
   }
-#endif  // BUILDFLAG(IS_WIN)
 
   ShouldBlockUpdateForMeteredNetwork(
       priority,
diff --git a/chrome/updater/update_service_impl.h b/chrome/updater/update_service_impl.h
index 6d47e58f..d709203 100644
--- a/chrome/updater/update_service_impl.h
+++ b/chrome/updater/update_service_impl.h
@@ -56,11 +56,7 @@
               const std::string& install_data_index,
               Priority priority,
               PolicySameVersionUpdate policy_same_version_update,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
               bool do_update_check_only,
-#endif  // BUILDFLAG(IS_WIN)
               StateChangeCallback state_update,
               Callback callback) override;
   void Install(const RegistrationRequest& registration,
diff --git a/chrome/updater/update_service_impl_inactive.cc b/chrome/updater/update_service_impl_inactive.cc
index a12d644..9f6fa40 100644
--- a/chrome/updater/update_service_impl_inactive.cc
+++ b/chrome/updater/update_service_impl_inactive.cc
@@ -68,11 +68,7 @@
               const std::string& /*install_data_index*/,
               Priority /*priority*/,
               PolicySameVersionUpdate /*policy_same_version_update*/,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
               bool /*do_update_check_only*/,
-#endif  // BUILDFLAG(IS_WIN)
               StateChangeCallback /*state_update*/,
               Callback callback) override {
     VLOG(1) << __func__ << " (Inactive)";
diff --git a/chrome/updater/update_service_internal_impl_qualifying.cc b/chrome/updater/update_service_internal_impl_qualifying.cc
index 1a5230b..669e432c 100644
--- a/chrome/updater/update_service_internal_impl_qualifying.cc
+++ b/chrome/updater/update_service_internal_impl_qualifying.cc
@@ -109,12 +109,7 @@
                        kQualificationAppId, "",
                        UpdateService::Priority::kBackground,
                        UpdateService::PolicySameVersionUpdate::kNotAllowed,
-// TODO(crbug.com/1396103): remove this `#if` once mojo interface changes are
-// done in separate CL.
-#if BUILDFLAG(IS_WIN)
-                       /*do_update_check_only=*/false,
-#endif  // BUILDFLAG(IS_WIN)
-                       base::DoNothing()))
+                       /*do_update_check_only=*/false, base::DoNothing()))
         ->Run(base::BindOnce(
             &UpdateServiceInternalQualifyingImpl::UpdateCheckDone, this,
             std::move(callback)));
diff --git a/chrome/updater/win/setup/setup_util.cc b/chrome/updater/win/setup/setup_util.cc
index 083c352a..8f9237f 100644
--- a/chrome/updater/win/setup/setup_util.cc
+++ b/chrome/updater/win/setup/setup_util.cc
@@ -62,6 +62,107 @@
              : std::wstring();
 }
 
+// Adds work items to `list` to install the progid corresponding to `clsid`.
+void AddInstallComProgIdWorkItems(UpdaterScope scope,
+                                  CLSID clsid,
+                                  WorkItemList* list) {
+  const std::wstring progid(GetProgIdForClsid(scope, clsid));
+  if (!progid.empty()) {
+    const HKEY root = UpdaterScopeToHKeyRoot(scope);
+    const std::wstring progid_reg_path(GetComProgIdRegistryPath(progid));
+
+    // Delete any old registrations first.
+    for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY}) {
+      list->AddDeleteRegKeyWorkItem(root, progid_reg_path, key_flag);
+    }
+
+    list->AddCreateRegKeyWorkItem(root, progid_reg_path + L"\\CLSID",
+                                  WorkItem::kWow64Default);
+    list->AddSetRegValueWorkItem(root, progid_reg_path + L"\\CLSID",
+                                 WorkItem::kWow64Default, L"",
+                                 base::win::WStringFromGUID(clsid), true);
+  }
+}
+
+// Adds work items to `list` to install the interface `iid`.
+void AddInstallComInterfaceWorkItems(HKEY root,
+                                     const base::FilePath& typelib_path,
+                                     GUID iid,
+                                     WorkItemList* list) {
+  const std::wstring iid_reg_path = GetComIidRegistryPath(iid);
+  const std::wstring typelib_reg_path = GetComTypeLibRegistryPath(iid);
+
+  // Delete any old registrations first.
+  for (const auto& reg_path : {iid_reg_path, typelib_reg_path}) {
+    for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY}) {
+      list->AddDeleteRegKeyWorkItem(root, reg_path, key_flag);
+    }
+  }
+
+  // Registering the Ole Automation marshaler with the CLSID
+  // {00020424-0000-0000-C000-000000000046} as the proxy/stub for the
+  // interfaces.
+  list->AddCreateRegKeyWorkItem(root, iid_reg_path + L"\\ProxyStubClsid32",
+                                WorkItem::kWow64Default);
+  list->AddSetRegValueWorkItem(root, iid_reg_path + L"\\ProxyStubClsid32",
+                               WorkItem::kWow64Default, L"",
+                               L"{00020424-0000-0000-C000-000000000046}", true);
+  list->AddCreateRegKeyWorkItem(root, iid_reg_path + L"\\TypeLib",
+                                WorkItem::kWow64Default);
+  list->AddSetRegValueWorkItem(root, iid_reg_path + L"\\TypeLib",
+                               WorkItem::kWow64Default, L"",
+                               base::win::WStringFromGUID(iid), true);
+
+  // The TypeLib registration for the Ole Automation marshaler.
+  const base::FilePath qualified_typelib_path =
+      typelib_path.Append(GetComTypeLibResourceIndex(iid));
+  list->AddCreateRegKeyWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win32",
+                                WorkItem::kWow64Default);
+  list->AddSetRegValueWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win32",
+                               WorkItem::kWow64Default, L"",
+                               qualified_typelib_path.value(), true);
+  list->AddCreateRegKeyWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win64",
+                                WorkItem::kWow64Default);
+  list->AddSetRegValueWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win64",
+                               WorkItem::kWow64Default, L"",
+                               qualified_typelib_path.value(), true);
+}
+
+// Adds work items to `list` to install the server `iid`.
+void AddInstallServerWorkItems(HKEY root,
+                               CLSID clsid,
+                               const base::FilePath& com_server_path,
+                               bool internal_service,
+                               WorkItemList* list) {
+  const std::wstring clsid_reg_path = GetComServerClsidRegistryPath(clsid);
+
+  // Delete any old registrations first.
+  for (const auto& reg_path : {clsid_reg_path}) {
+    for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY}) {
+      list->AddDeleteRegKeyWorkItem(root, reg_path, key_flag);
+    }
+  }
+
+  list->AddCreateRegKeyWorkItem(root, clsid_reg_path, WorkItem::kWow64Default);
+  const std::wstring local_server32_reg_path =
+      base::StrCat({clsid_reg_path, L"\\LocalServer32"});
+  list->AddCreateRegKeyWorkItem(root, local_server32_reg_path,
+                                WorkItem::kWow64Default);
+
+  base::CommandLine run_com_server_command(com_server_path);
+  run_com_server_command.AppendSwitch(kServerSwitch);
+  run_com_server_command.AppendSwitchASCII(
+      kServerServiceSwitch, internal_service
+                                ? kServerUpdateServiceInternalSwitchValue
+                                : kServerUpdateServiceSwitchValue);
+  run_com_server_command.AppendSwitch(kEnableLoggingSwitch);
+  run_com_server_command.AppendSwitchASCII(kLoggingModuleSwitch,
+                                           kLoggingModuleSwitchValue);
+  list->AddSetRegValueWorkItem(
+      root, local_server32_reg_path, WorkItem::kWow64Default, L"",
+      run_com_server_command.GetCommandLineString(), true);
+}
+
 }  // namespace
 
 bool RegisterWakeTask(const base::CommandLine& run_command,
@@ -205,81 +306,6 @@
   return is_internal ? GetSideBySideServers(scope) : GetActiveServers(scope);
 }
 
-void AddInstallComInterfaceWorkItems(HKEY root,
-                                     const base::FilePath& typelib_path,
-                                     GUID iid,
-                                     WorkItemList* list) {
-  const std::wstring iid_reg_path = GetComIidRegistryPath(iid);
-  const std::wstring typelib_reg_path = GetComTypeLibRegistryPath(iid);
-
-  // Delete any old registrations first.
-  for (const auto& reg_path : {iid_reg_path, typelib_reg_path}) {
-    for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY})
-      list->AddDeleteRegKeyWorkItem(root, reg_path, key_flag);
-  }
-
-  // Registering the Ole Automation marshaler with the CLSID
-  // {00020424-0000-0000-C000-000000000046} as the proxy/stub for the
-  // interfaces.
-  list->AddCreateRegKeyWorkItem(root, iid_reg_path + L"\\ProxyStubClsid32",
-                                WorkItem::kWow64Default);
-  list->AddSetRegValueWorkItem(root, iid_reg_path + L"\\ProxyStubClsid32",
-                               WorkItem::kWow64Default, L"",
-                               L"{00020424-0000-0000-C000-000000000046}", true);
-  list->AddCreateRegKeyWorkItem(root, iid_reg_path + L"\\TypeLib",
-                                WorkItem::kWow64Default);
-  list->AddSetRegValueWorkItem(root, iid_reg_path + L"\\TypeLib",
-                               WorkItem::kWow64Default, L"",
-                               base::win::WStringFromGUID(iid), true);
-
-  // The TypeLib registration for the Ole Automation marshaler.
-  const base::FilePath qualified_typelib_path =
-      typelib_path.Append(GetComTypeLibResourceIndex(iid));
-  list->AddCreateRegKeyWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win32",
-                                WorkItem::kWow64Default);
-  list->AddSetRegValueWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win32",
-                               WorkItem::kWow64Default, L"",
-                               qualified_typelib_path.value(), true);
-  list->AddCreateRegKeyWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win64",
-                                WorkItem::kWow64Default);
-  list->AddSetRegValueWorkItem(root, typelib_reg_path + L"\\1.0\\0\\win64",
-                               WorkItem::kWow64Default, L"",
-                               qualified_typelib_path.value(), true);
-}
-
-void AddInstallServerWorkItems(HKEY root,
-                               CLSID clsid,
-                               const base::FilePath& com_server_path,
-                               bool internal_service,
-                               WorkItemList* list) {
-  const std::wstring clsid_reg_path = GetComServerClsidRegistryPath(clsid);
-
-  // Delete any old registrations first.
-  for (const auto& reg_path : {clsid_reg_path}) {
-    for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY})
-      list->AddDeleteRegKeyWorkItem(root, reg_path, key_flag);
-  }
-
-  list->AddCreateRegKeyWorkItem(root, clsid_reg_path, WorkItem::kWow64Default);
-  const std::wstring local_server32_reg_path =
-      base::StrCat({clsid_reg_path, L"\\LocalServer32"});
-  list->AddCreateRegKeyWorkItem(root, local_server32_reg_path,
-                                WorkItem::kWow64Default);
-
-  base::CommandLine run_com_server_command(com_server_path);
-  run_com_server_command.AppendSwitch(kServerSwitch);
-  run_com_server_command.AppendSwitchASCII(
-      kServerServiceSwitch, internal_service
-                                ? kServerUpdateServiceInternalSwitchValue
-                                : kServerUpdateServiceSwitchValue);
-  run_com_server_command.AppendSwitch(kEnableLoggingSwitch);
-  run_com_server_command.AppendSwitchASCII(kLoggingModuleSwitch,
-                                           kLoggingModuleSwitchValue);
-  list->AddSetRegValueWorkItem(
-      root, local_server32_reg_path, WorkItem::kWow64Default, L"",
-      run_com_server_command.GetCommandLineString(), true);
-}
-
 void AddComServerWorkItems(const base::FilePath& com_server_path,
                            bool is_internal,
                            WorkItemList* list) {
@@ -292,6 +318,7 @@
   for (const auto& clsid : GetServers(is_internal, UpdaterScope::kUser)) {
     AddInstallServerWorkItems(HKEY_CURRENT_USER, clsid, com_server_path,
                               is_internal, list);
+    AddInstallComProgIdWorkItems(UpdaterScope::kUser, clsid, list);
   }
 
   for (const auto& iid : GetInterfaces(is_internal, UpdaterScope::kUser)) {
@@ -325,11 +352,16 @@
   base::CommandLine com_switch(base::CommandLine::NO_PROGRAM);
   com_switch.AppendSwitch(kComServiceSwitch);
 
+  const std::vector<CLSID> clsids(
+      GetServers(internal_service, UpdaterScope::kSystem));
   list->AddWorkItem(new installer::InstallServiceWorkItem(
       GetServiceName(internal_service).c_str(),
       GetServiceDisplayName(internal_service).c_str(), SERVICE_AUTO_START,
-      com_service_command, com_switch, UPDATER_KEY,
-      GetServers(internal_service, UpdaterScope::kSystem), {}));
+      com_service_command, com_switch, UPDATER_KEY, clsids, {}));
+
+  for (const auto& clsid : clsids) {
+    AddInstallComProgIdWorkItems(UpdaterScope::kSystem, clsid, list);
+  }
 
   for (const auto& iid :
        GetInterfaces(internal_service, UpdaterScope::kSystem)) {
@@ -338,6 +370,23 @@
   }
 }
 
+std::wstring GetProgIdForClsid(UpdaterScope scope, CLSID clsid) {
+  switch (scope) {
+    case UpdaterScope::kUser:
+      return clsid == __uuidof(GoogleUpdate3WebUserClass)
+                 ? L"GoogleUpdate.Update3WebUser"
+                 : L"";
+    case UpdaterScope::kSystem:
+      return clsid == __uuidof(GoogleUpdate3WebSystemClass)
+                 ? L"GoogleUpdate.Update3WebMachine"
+                 : L"";
+  }
+}
+
+std::wstring GetComProgIdRegistryPath(const std::wstring& progid) {
+  return base::StrCat({L"Software\\Classes\\", progid});
+}
+
 std::wstring GetComServerClsidRegistryPath(REFCLSID clsid) {
   return base::StrCat(
       {L"Software\\Classes\\CLSID\\", base::win::WStringFromGUID(clsid)});
diff --git a/chrome/updater/win/setup/setup_util.h b/chrome/updater/win/setup/setup_util.h
index b9de5ac5..cb564c4 100644
--- a/chrome/updater/win/setup/setup_util.h
+++ b/chrome/updater/win/setup/setup_util.h
@@ -38,6 +38,8 @@
 bool RegisterWakeTask(const base::CommandLine& run_command, UpdaterScope scope);
 void UnregisterWakeTask(UpdaterScope scope);
 
+std::wstring GetProgIdForClsid(UpdaterScope scope, CLSID clsid);
+std::wstring GetComProgIdRegistryPath(const std::wstring& progid);
 std::wstring GetComServerClsidRegistryPath(REFCLSID clsid);
 std::wstring GetComServerAppidRegistryPath(REFGUID appid);
 std::wstring GetComIidRegistryPath(REFIID iid);
@@ -88,19 +90,6 @@
   return joined_vector;
 }
 
-// Adds work items to `list` to install the interface `iid`.
-void AddInstallComInterfaceWorkItems(HKEY root,
-                                     const base::FilePath& typelib_path,
-                                     GUID iid,
-                                     WorkItemList* list);
-
-// Adds work items to `list` to install the server `iid`.
-void AddInstallServerWorkItems(HKEY root,
-                               CLSID iid,
-                               const base::FilePath& executable_path,
-                               bool internal_service,
-                               WorkItemList* list);
-
 // Adds work items to register the per-user COM server.
 void AddComServerWorkItems(const base::FilePath& com_server_path,
                            bool is_internal,
diff --git a/chrome/updater/win/setup/uninstall.cc b/chrome/updater/win/setup/uninstall.cc
index b172573..19984fd1 100644
--- a/chrome/updater/win/setup/uninstall.cc
+++ b/chrome/updater/win/setup/uninstall.cc
@@ -45,6 +45,13 @@
     installer::DeleteRegistryKey(UpdaterScopeToHKeyRoot(scope),
                                  GetComServerClsidRegistryPath(clsid),
                                  WorkItem::kWow64Default);
+
+    const std::wstring progid(GetProgIdForClsid(scope, clsid));
+    if (!progid.empty()) {
+      installer::DeleteRegistryKey(UpdaterScopeToHKeyRoot(scope),
+                                   GetComProgIdRegistryPath(progid),
+                                   WorkItem::kWow64Default);
+    }
   }
 }
 
diff --git a/chromeos/ash/components/device_activity/churn_cohort_use_case_impl.cc b/chromeos/ash/components/device_activity/churn_cohort_use_case_impl.cc
index f0d639e6..253fd730 100644
--- a/chromeos/ash/components/device_activity/churn_cohort_use_case_impl.cc
+++ b/chromeos/ash/components/device_activity/churn_cohort_use_case_impl.cc
@@ -41,12 +41,8 @@
 
 absl::optional<FresnelImportDataRequest>
 ChurnCohortUseCaseImpl::GenerateImportRequestBody() {
-  std::string psm_id_str = GetPsmIdentifier().value().sensitive_id();
-  std::string window_id_str = GetWindowIdentifier().value();
-
   // Generate Fresnel PSM import request body.
   FresnelImportDataRequest import_request;
-  import_request.set_window_identifier(window_id_str);
 
   // Create fresh |DeviceMetadata| object.
   // Note every dimension added to this proto must be approved by privacy.
@@ -57,7 +53,14 @@
   device_metadata->set_hardware_id(GetFullHardwareClass());
 
   import_request.set_use_case(GetPsmUseCase());
-  import_request.set_plaintext_identifier(psm_id_str);
+
+  std::string psm_id_str = GetPsmIdentifier().value().sensitive_id();
+  std::string window_id_str = GetWindowIdentifier().value();
+
+  FresnelImportData* import_data = import_request.add_import_data();
+  import_data->set_plaintext_id(psm_id_str);
+  import_data->set_window_identifier(window_id_str);
+  import_data->set_is_pt_window_identifier(true);
 
   return import_request;
 }
diff --git a/chromeos/ash/components/network/portal_detector/network_portal_detector.h b/chromeos/ash/components/network/portal_detector/network_portal_detector.h
index d396d7f..55c7ce3 100644
--- a/chromeos/ash/components/network/portal_detector/network_portal_detector.h
+++ b/chromeos/ash/components/network/portal_detector/network_portal_detector.h
@@ -37,8 +37,12 @@
   // Returns true if portal detection is enabled.
   virtual bool IsEnabled() = 0;
 
-  // Enable portal detection. Once enabled, portal detection for the default
-  // network will be handled any time the default network state changes.
+  // Enable portal detection. This will do nothing if the EULA has not been
+  // accepted (i.e. OOBE has not completed) since we do not want to show a
+  // captive portal signin page until the user accepts the EULA. Once accepted,
+  // Enable() should be called again.
+  // Once enabled, portal detection for the default network will be handled any
+  // time the default network state changes.
   virtual void Enable() = 0;
 
   // Returns non-localized string representation of |status|.
diff --git a/chromeos/crosapi/mojom/ui_constants_mojom_traits.cc b/chromeos/crosapi/mojom/ui_constants_mojom_traits.cc
index ee24a07cd..c181f854 100644
--- a/chromeos/crosapi/mojom/ui_constants_mojom_traits.cc
+++ b/chromeos/crosapi/mojom/ui_constants_mojom_traits.cc
@@ -37,7 +37,7 @@
       *output = ui::ResourceScaleFactor::k100Percent;
       return true;
     case crosapi::mojom::ResourceScaleFactor::k200Percent:
-      *output = ui::ResourceScaleFactor::k100Percent;
+      *output = ui::ResourceScaleFactor::k200Percent;
       return true;
     case crosapi::mojom::ResourceScaleFactor::k300Percent:
       *output = ui::ResourceScaleFactor::k300Percent;
diff --git a/components/autofill/core/browser/metrics/payments/iban_metrics.cc b/components/autofill/core/browser/metrics/payments/iban_metrics.cc
index e430aac7..c3e2fb0 100644
--- a/components/autofill/core/browser/metrics/payments/iban_metrics.cc
+++ b/components/autofill/core/browser/metrics/payments/iban_metrics.cc
@@ -16,8 +16,27 @@
 
 void LogIBANSaveNotOfferedDueToMaxStrikesMetric(
     AutofillMetrics::SaveTypeMetric metric) {
-  UMA_HISTOGRAM_ENUMERATION(
+  base::UmaHistogramEnumeration(
       "Autofill.StrikeDatabase.IbanSaveNotOfferedDueToMaxStrikes", metric);
 }
 
+void LogSaveIbanBubbleOfferMetric(SaveIbanPromptOffer metric, bool is_reshow) {
+  std::string base_histogram_name = "Autofill.SaveIbanPromptOffer.Local";
+  std::string show = is_reshow ? ".Reshows" : ".FirstShow";
+  base::UmaHistogramEnumeration(base_histogram_name + show, metric);
+}
+
+void LogSaveIbanBubbleResultMetric(SaveIbanBubbleResult metric,
+                                   bool is_reshow) {
+  std::string base_histogram_name = "Autofill.SaveIbanPromptResult.Local";
+  std::string show = is_reshow ? ".Reshows" : ".FirstShow";
+  base::UmaHistogramEnumeration(base_histogram_name + show, metric);
+}
+
+void LogSaveIbanBubbleResultSavedWithNicknameMetric(bool save_with_nickname) {
+  base::UmaHistogramBoolean(
+      "Autofill.SaveIbanPromptResult.Local.SavedWithNickname",
+      save_with_nickname);
+}
+
 }  // namespace autofill::autofill_metrics
diff --git a/components/autofill/core/browser/metrics/payments/iban_metrics.h b/components/autofill/core/browser/metrics/payments/iban_metrics.h
index e67d4d7..7cec9b80 100644
--- a/components/autofill/core/browser/metrics/payments/iban_metrics.h
+++ b/components/autofill/core/browser/metrics/payments/iban_metrics.h
@@ -10,6 +10,36 @@
 
 namespace autofill::autofill_metrics {
 
+// This includes all possible results.
+// They will be used in metrics, and should not be renumbered.
+enum class SaveIbanBubbleResult {
+  // The user explicitly accepted the bubble by clicking the ok button.
+  kAccepted = 0,
+  // The user explicitly cancelled the bubble by clicking the cancel button.
+  kCancelled = 1,
+  // The user explicitly closed the bubble with the close button or ESC.
+  kClosed = 2,
+  // The user did not interact with the bubble.
+  kNotInteracted = 3,
+  // The bubble lost focus and was deactivated.
+  kLostFocus = 4,
+  // The reason why the bubble is closed is not clear. Possible reason is the
+  // logging function is invoked before the closed reason is correctly set.
+  kUnknown = 5,
+  kMaxValue = kUnknown,
+};
+
+// Metrics to track event when the IBAN prompt is offered.
+// They will be used in metrics, and should not be renumbered.
+enum class SaveIbanPromptOffer {
+  // The prompt is actually shown.
+  kShown = 0,
+  // The prompt is not shown because the prompt has been declined by the user
+  // too many times.
+  kNotShownMaxStrikesReached = 1,
+  kMaxValue = kNotShownMaxStrikesReached,
+};
+
 // Logs the number of strikes that an IBAN had when save was accepted.
 void LogStrikesPresentWhenIBANSaved(const int num_strikes);
 
@@ -17,6 +47,16 @@
 void LogIBANSaveNotOfferedDueToMaxStrikesMetric(
     AutofillMetrics::SaveTypeMetric metric);
 
+// Logs when IBAN save bubble is offered to users.
+void LogSaveIbanBubbleOfferMetric(SaveIbanPromptOffer metric, bool is_reshow);
+
+// Logs when the user makes a decision on the IBAN save bubble.
+void LogSaveIbanBubbleResultMetric(SaveIbanBubbleResult metric, bool is_reshow);
+
+// Logs when the user accepts the bubble to save an IBAN.
+// `save_with_nickname` donates the user has input a nickname.
+void LogSaveIbanBubbleResultSavedWithNicknameMetric(bool save_with_nickname);
+
 }  // namespace autofill::autofill_metrics
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_IBAN_METRICS_H_
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.cc b/components/autofill/core/browser/payments/credit_card_save_manager.cc
index b8de8fc..a107b75b 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -277,23 +277,6 @@
   show_save_prompt_ = !GetCreditCardSaveStrikeDatabase()->ShouldBlockFeature(
       base::UTF16ToUTF8(upload_request_.card.LastFourDigits()));
 
-#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
-
-  int save_card_ui_experiment_arm =
-      features::kAutofillSaveCardUiExperimentSelectorInNumber.Get();
-
-  // Adding the Save Card UI Experiment to the active experiments in upload
-  // request if the experiment is active. If 3rd save card ui experiment, aka
-  // Current with Avatar and Email, is selected then we would not add
-  // AutofillSaveCardUiExperiment to the active experiments list, as we want the
-  // current footer to be displayed.
-  if (base::FeatureList::IsEnabled(features::kAutofillSaveCardUiExperiment) &&
-      (save_card_ui_experiment_arm == 1 || save_card_ui_experiment_arm == 2)) {
-    upload_request_.active_experiments.push_back(
-        "AutofillSaveCardUiExperiment");
-  }
-#endif
-
   payments_client_->GetUploadDetails(
       country_only_profiles, upload_request_.detected_values,
       upload_request_.active_experiments, app_locale_,
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 88b2019..791fbff 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -1688,102 +1688,6 @@
 }
 #endif
 
-#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
-TEST_F(CreditCardSaveManagerTest,
-       AttemptToOfferCardUploadSave_SaveCardUiExperimentEnabled) {
-  // Setting the flag and params for the save card ui experiment.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kAutofillSaveCardUiExperiment,
-      {{"autofill_save_card_ui_experiment_selector_in_number", "2"}});
-
-  // Set up our credit card form data.
-  FormData credit_card_form;
-  CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
-  FormsSeen(std::vector<FormData>(1, credit_card_form));
-
-  // Edit the data, and submit.
-  credit_card_form.fields[0].value = u"Jane Doe";
-  credit_card_form.fields[1].value = u"4111111111111111";
-  credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
-  credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
-  credit_card_form.fields[4].value = u"123";
-  FormSubmitted(credit_card_form);
-
-  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
-  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
-
-  // Confirm that active experiments vector has the correct value.
-  std::vector<const char*> active_experiments_in_request =
-      payments_client_->active_experiments_in_request();
-  EXPECT_THAT(
-      active_experiments_in_request,
-      testing::Contains(testing::StrEq("AutofillSaveCardUiExperiment")));
-}
-
-TEST_F(CreditCardSaveManagerTest,
-       AttemptToOfferCardUploadSave_SaveCardUiExperimentDisabled) {
-  // Disabling the flag for the save card ui experiment.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      features::kAutofillSaveCardUiExperiment);
-
-  FormData credit_card_form;
-  CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
-  FormsSeen(std::vector<FormData>(1, credit_card_form));
-
-  credit_card_form.fields[0].value = u"Jane Doe";
-  credit_card_form.fields[1].value = u"4111111111111111";
-  credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
-  credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
-  credit_card_form.fields[4].value = u"123";
-  FormSubmitted(credit_card_form);
-
-  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
-  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
-
-  std::vector<const char*> active_experiments_in_request =
-      payments_client_->active_experiments_in_request();
-  EXPECT_THAT(active_experiments_in_request,
-              testing::Not(testing::Contains(
-                  testing::StrEq("AutofillSaveCardUiExperiment"))));
-}
-
-TEST_F(
-    CreditCardSaveManagerTest,
-    AttemptToOfferCardUploadSave_SaveCardUiExperimentEnabledWithoutAddedInOutgoingRequest) {
-  // Setting the flag and params for the save card ui experiment with value 3 as
-  // we are not getting the updated/experimental TOS for that experiment arm.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kAutofillSaveCardUiExperiment,
-      {{"autofill_save_card_ui_experiment_selector_in_number", "3"}});
-
-  // Set up our credit card form data.
-  FormData credit_card_form;
-  CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
-  FormsSeen(std::vector<FormData>(1, credit_card_form));
-
-  // Edit the data, and submit.
-  credit_card_form.fields[0].value = u"Jane Doe";
-  credit_card_form.fields[1].value = u"4111111111111111";
-  credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
-  credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
-  credit_card_form.fields[4].value = u"123";
-  FormSubmitted(credit_card_form);
-
-  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
-  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
-
-  // Confirm that active experiments vector has the correct value.
-  std::vector<const char*> active_experiments_in_request =
-      payments_client_->active_experiments_in_request();
-  EXPECT_THAT(active_experiments_in_request,
-              testing::Not(testing::Contains(
-                  testing::StrEq("AutofillSaveCardUiExperiment"))));
-}
-#endif
-
 // TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
 // permanently if the test doesn't apply to iOS flow.
 #if !BUILDFLAG(IS_IOS)
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc
index d34007b..677b576c 100644
--- a/components/autofill/core/common/autofill_payments_features.cc
+++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -198,18 +198,6 @@
              "AutofillSaveCardInfobarEditSupport",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// When enabled, Chrome will display experimental UI variants to the user
-// during the upload save card process.
-BASE_FEATURE(kAutofillSaveCardUiExperiment,
-             "AutofillSaveCardUiExperiment",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-// This will select one of the options for the save card UI bubble which we
-// want to display to the user. The value will be an integer(number).
-const base::FeatureParam<int> kAutofillSaveCardUiExperimentSelectorInNumber{
-    &kAutofillSaveCardUiExperiment,
-    "autofill_save_card_ui_experiment_selector_in_number", 0};
-
 // When enabled, the entire PAN and the CVC details of the unmasked cached card
 // will be shown in the manual filling view.
 BASE_FEATURE(kAutofillShowUnmaskedCachedCardInManualFillingView,
diff --git a/components/autofill/core/common/autofill_payments_features.h b/components/autofill/core/common/autofill_payments_features.h
index 0c41191..146d19e9 100644
--- a/components/autofill/core/common/autofill_payments_features.h
+++ b/components/autofill/core/common/autofill_payments_features.h
@@ -39,9 +39,6 @@
 BASE_DECLARE_FEATURE(kAutofillParseVcnCardOnFileStandaloneCvcFields);
 BASE_DECLARE_FEATURE(kAutofillRemoveCardExpirationAndTypeTitles);
 BASE_DECLARE_FEATURE(kAutofillSaveCardInfobarEditSupport);
-BASE_DECLARE_FEATURE(kAutofillSaveCardUiExperiment);
-extern const base::FeatureParam<int>
-    kAutofillSaveCardUiExperimentSelectorInNumber;
 BASE_DECLARE_FEATURE(kAutofillShowUnmaskedCachedCardInManualFillingView);
 BASE_DECLARE_FEATURE(kAutofillSuggestServerCardInsteadOfLocalCard);
 BASE_DECLARE_FEATURE(kAutofillUpstream);
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 4e6cdaf2..436bf74 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -457,9 +457,10 @@
 
   const bool request_release_fence =
       !per_commit_explicit_release_callback.is_null();
-  if (per_commit_explicit_release_callback)
+  if (per_commit_explicit_release_callback) {
     pending_explicit_releases_.emplace(
         next_commit_id_, std::move(per_commit_explicit_release_callback));
+  }
 
   resource->id = resource_manager->AllocateResourceId();
   resource->format = viz::SharedImageFormat::SinglePlane(viz::RGBA_8888);
@@ -566,8 +567,12 @@
   return true;
 }
 
+void Buffer::SkipLegacyRelease() {
+  legacy_release_skippable_ = true;
+}
+
 void Buffer::OnAttach() {
-  DLOG_IF(WARNING, attach_count_)
+  DLOG_IF(WARNING, attach_count_ && !legacy_release_skippable_)
       << "Reattaching a buffer that is already attached to another surface.";
   TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id",
                static_cast<const void*>(gfx_buffer()), "count", attach_count_);
@@ -614,8 +619,9 @@
   TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
 
   // Run release callback to notify the client that buffer has been released.
-  if (!release_callback_.is_null())
+  if (!release_callback_.is_null() && !legacy_release_skippable_) {
     release_callback_.Run();
+  }
 }
 
 void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture,
@@ -662,7 +668,11 @@
 
   // We are still required to send these wl_buffer.release events even if
   // the client supports explicit synchronization.
-  if (release_fence.is_null()) {
+  if (!buffer_release_callback) {
+    return;
+  }
+
+  if (release_fence.is_null() || legacy_release_skippable_) {
     std::move(buffer_release_callback).Run();
   } else {
     // Watching the release fence's fd results in a context switch to the I/O
@@ -716,9 +726,10 @@
     gfx::ColorSpace color_space,
     ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
     PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
-  if (per_commit_explicit_release_callback)
+  if (per_commit_explicit_release_callback) {
     std::move(per_commit_explicit_release_callback)
         .Run(/*release_fence=*/gfx::GpuFenceHandle());
+  }
   return false;
 }
 
diff --git a/components/exo/buffer.h b/components/exo/buffer.h
index 1f6430f..5808c00 100644
--- a/components/exo/buffer.h
+++ b/components/exo/buffer.h
@@ -53,6 +53,9 @@
     release_callback_ = release_callback;
   }
 
+  // The client does not need release_callback_ to notify buffer usage.
+  void SkipLegacyRelease();
+
   // Returns if this buffer's contents are vertically inverted.
   bool y_invert() const { return y_invert_; }
 
@@ -212,6 +215,8 @@
   // protocol requires us to send regular buffer release events.
   base::flat_map<uint64_t, BufferRelease> buffer_releases_;
 
+  bool legacy_release_skippable_ = false;
+
 #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
   ProtectedBufferState protected_buffer_state_ = ProtectedBufferState::UNKNOWN;
 #endif  // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 478d70a..4463c7d 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -1302,6 +1302,10 @@
     if (!buffer_color_space.IsValid()) {
       buffer_color_space = gfx::ColorSpace::CreateSRGB();
     }
+    if (legacy_buffer_release_skippable_ &&
+        state_.per_commit_explicit_release_callback_) {
+      state_.buffer->buffer()->SkipLegacyRelease();
+    }
     if (state_.buffer->buffer()->ProduceTransferableResource(
             resource_manager, std::move(state_.acquire_fence),
             state_.basic_state.only_visible_on_secure_output,
diff --git a/components/exo/surface.h b/components/exo/surface.h
index 7ad1fd4..3d25c96 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -107,6 +107,10 @@
     leave_enter_callback_ = callback;
   }
 
+  void set_legacy_buffer_release_skippable(bool skippable) {
+    legacy_buffer_release_skippable_ = skippable;
+  }
+
   // Called when the display the surface is on has changed.
   // Returns true if successful, and false if it fails.
   bool UpdateDisplay(int64_t old_id, int64_t new_id);
@@ -659,6 +663,7 @@
   LeaveEnterCallback leave_enter_callback_;
 
   bool keyboard_shortcuts_inhibited_ = false;
+  bool legacy_buffer_release_skippable_ = false;
 };
 
 class ScopedSurface {
diff --git a/components/exo/wayland/surface_augmenter.cc b/components/exo/wayland/surface_augmenter.cc
index 072cf6e3..13e900e 100644
--- a/components/exo/wayland/surface_augmenter.cc
+++ b/components/exo/wayland/surface_augmenter.cc
@@ -39,6 +39,7 @@
   explicit AugmentedSurface(Surface* surface) : surface_(surface) {
     surface_->AddSurfaceObserver(this);
     surface_->SetProperty(kSurfaceHasAugmentedSurfaceKey, true);
+    surface_->set_legacy_buffer_release_skippable(true);
   }
   AugmentedSurface(const AugmentedSurface&) = delete;
   AugmentedSurface& operator=(const AugmentedSurface&) = delete;
diff --git a/components/media_router/common/providers/cast/channel/cast_channel_metrics.cc b/components/media_router/common/providers/cast/channel/cast_channel_metrics.cc
index 51b3d95..1cf6788 100644
--- a/components/media_router/common/providers/cast/channel/cast_channel_metrics.cc
+++ b/components/media_router/common/providers/cast/channel/cast_channel_metrics.cc
@@ -9,9 +9,6 @@
 
 namespace cast_channel {
 
-constexpr char kLaunchSessionChannelFlagsHistogram[] =
-    "Cast.Channel.LaunchSession.Flags";
-
 void RecordLaunchSessionChannelFlags(CastChannelFlags flags) {
   if (!flags) {
     UMA_HISTOGRAM_ENUMERATION(kLaunchSessionChannelFlagsHistogram,
diff --git a/components/media_router/common/providers/cast/channel/cast_channel_metrics.h b/components/media_router/common/providers/cast/channel/cast_channel_metrics.h
index 724251c3..9d57df90 100644
--- a/components/media_router/common/providers/cast/channel/cast_channel_metrics.h
+++ b/components/media_router/common/providers/cast/channel/cast_channel_metrics.h
@@ -9,6 +9,9 @@
 
 namespace cast_channel {
 
+constexpr char kLaunchSessionChannelFlagsHistogram[] =
+    "Cast.Channel.LaunchSession.Flags";
+
 // Records the flags set on a Cast channel when a Cast LAUNCH message is sent.
 void RecordLaunchSessionChannelFlags(CastChannelFlags flags);
 
diff --git a/components/media_router/common/providers/cast/channel/cast_message_handler_unittest.cc b/components/media_router/common/providers/cast/channel/cast_message_handler_unittest.cc
index cd024b09..50d3f7e 100644
--- a/components/media_router/common/providers/cast/channel/cast_message_handler_unittest.cc
+++ b/components/media_router/common/providers/cast/channel/cast_message_handler_unittest.cc
@@ -12,10 +12,13 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/test/values_test_util.h"
+#include "components/media_router/common/providers/cast/channel/cast_channel_enum.h"
+#include "components/media_router/common/providers/cast/channel/cast_channel_metrics.h"
 #include "components/media_router/common/providers/cast/channel/cast_message_util.h"
 #include "components/media_router/common/providers/cast/channel/cast_test_util.h"
 #include "content/public/test/browser_task_environment.h"
@@ -419,6 +422,10 @@
 }
 
 TEST_F(CastMessageHandlerTest, LaunchSession) {
+  base::HistogramTester histogram_tester;
+  cast_socket_.SetFlags(
+      static_cast<CastChannelFlags>(CastChannelFlag::kSha1DigestAlgorithm) |
+      static_cast<CastChannelFlags>(CastChannelFlag::kCRLMissing));
   ExpectEnsureConnectionThen(CastMessageType::kLaunch);
 
   const absl::optional<base::Value> json = base::JSONReader::Read(kAppParams);
@@ -457,6 +464,13 @@
   OnMessage(response);
   run_loop_->Run();
   EXPECT_EQ(1, session_launch_response_count_);
+  // Flags associated with the CastSocket should be recorded on launch.
+  histogram_tester.ExpectBucketCount(kLaunchSessionChannelFlagsHistogram,
+                                     CastChannelFlag::kFlagsNone, 0);
+  histogram_tester.ExpectBucketCount(kLaunchSessionChannelFlagsHistogram,
+                                     CastChannelFlag::kSha1DigestAlgorithm, 1);
+  histogram_tester.ExpectBucketCount(kLaunchSessionChannelFlagsHistogram,
+                                     CastChannelFlag::kCRLMissing, 1);
 }
 
 TEST_F(CastMessageHandlerTest, LaunchSessionTimedOut) {
diff --git a/components/media_router/common/providers/cast/channel/cast_test_util.h b/components/media_router/common/providers/cast/channel/cast_test_util.h
index f346052..e97e688 100644
--- a/components/media_router/common/providers/cast/channel/cast_test_util.h
+++ b/components/media_router/common/providers/cast/channel/cast_test_util.h
@@ -148,9 +148,8 @@
     error_state_ = error_state;
   }
 
-  CastChannelFlags flags() const override {
-    return static_cast<CastChannelFlags>(CastChannelFlag::kFlagsNone);
-  }
+  CastChannelFlags flags() const override { return flags_; }
+  void SetFlags(CastChannelFlags flags) { flags_ = flags; }
 
   bool keep_alive() const override { return keep_alive_; }
   void SetKeepAlive(bool keep_alive) { keep_alive_ = keep_alive; }
@@ -165,6 +164,8 @@
   net::IPEndPoint ip_endpoint_;
   int channel_id_;
   ChannelError error_state_;
+  CastChannelFlags flags_{
+      static_cast<CastChannelFlags>(CastChannelFlag::kFlagsNone)};
   bool keep_alive_;
   bool audio_only_;
 
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp
index 9b35b99..983ec556 100644
--- a/components/payments_strings.grdp
+++ b/components/payments_strings.grdp
@@ -588,6 +588,9 @@
   <message name="IDS_PAYMENT_HANDLER_SHEET_CLOSED" desc="Accessibility string read when the payment-handler bottom sheet is closed." formatter_data="android_java">
     Payment handler sheet is closed
   </message>
+  <message name="IDS_PAYMENT_HANDLER_ICON" desc="The alt text for the payment handler icon. Used for accessibility.">
+    Payment handler icon
+  </message>
 
   <!-- Secure Payment Confirmation strings -->
   <if expr="not is_win and not is_macosx">
diff --git a/components/payments_strings_grdp/IDS_PAYMENT_HANDLER_ICON.png.sha1 b/components/payments_strings_grdp/IDS_PAYMENT_HANDLER_ICON.png.sha1
new file mode 100644
index 0000000..f7967fa6
--- /dev/null
+++ b/components/payments_strings_grdp/IDS_PAYMENT_HANDLER_ICON.png.sha1
@@ -0,0 +1 @@
+a4914f944acc47c8932fe1646a177f216f3b28cc
\ No newline at end of file
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index d47c9beb..7d9cf91 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -818,6 +818,9 @@
                                    button.control_count);
       button_node->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
                                    button.control_index + 1);
+      button_node->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kCheck);
+    } else {
+      button_node->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kPress);
     }
 
     button_node->relative_bounds.bounds = button.bounds;
@@ -836,6 +839,9 @@
     listbox_option_node->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
                                           choice_field_option.is_selected);
     listbox_option_node->AddState(ax::mojom::State::kFocusable);
+    listbox_option_node->SetDefaultActionVerb(
+        ax::mojom::DefaultActionVerb::kSelect);
+
     return listbox_option_node;
   }
 
@@ -902,6 +908,11 @@
 
     combobox_input_node->AddState(ax::mojom::State::kFocusable);
     combobox_input_node->relative_bounds.bounds = choice_field.bounds;
+    if (input_role == ax::mojom::Role::kComboBoxMenuButton) {
+      combobox_input_node->SetDefaultActionVerb(
+          ax::mojom::DefaultActionVerb::kOpen);
+    }
+
     return combobox_input_node;
   }
 
diff --git a/components/performance_manager/decorators/page_live_state_decorator.cc b/components/performance_manager/decorators/page_live_state_decorator.cc
index 07c8c7b74..5cacfbf 100644
--- a/components/performance_manager/decorators/page_live_state_decorator.cc
+++ b/components/performance_manager/decorators/page_live_state_decorator.cc
@@ -365,11 +365,11 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value PageLiveStateDecorator::DescribePageNodeData(
+base::Value::Dict PageLiveStateDecorator::DescribePageNodeData(
     const PageNode* node) const {
   auto* data = Data::FromPageNode(node);
   if (!data)
-    return base::Value();
+    return base::Value::Dict();
 
   base::Value::Dict ret;
   ret.Set("IsConnectedToUSBDevice", data->IsConnectedToUSBDevice());
@@ -383,7 +383,7 @@
   ret.Set("WasDiscarded", data->WasDiscarded());
   ret.Set("IsActiveTab", data->IsActiveTab());
 
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 void PageLiveStateDecorator::OnMainFrameUrlChanged(const PageNode* page_node) {
diff --git a/components/performance_manager/decorators/page_load_tracker_decorator.cc b/components/performance_manager/decorators/page_load_tracker_decorator.cc
index 9323c673..35cded30f 100644
--- a/components/performance_manager/decorators/page_load_tracker_decorator.cc
+++ b/components/performance_manager/decorators/page_load_tracker_decorator.cc
@@ -102,18 +102,18 @@
   UnregisterObservers(graph);
 }
 
-base::Value PageLoadTrackerDecorator::DescribePageNodeData(
+base::Value::Dict PageLoadTrackerDecorator::DescribePageNodeData(
     const PageNode* page_node) const {
   auto* data = DataImpl::Get(PageNodeImpl::FromNode(page_node));
   if (data == nullptr)
-    return base::Value();
+    return base::Value::Dict();
 
   base::Value::Dict ret;
   ret.Set("load_idle_state", ToString(data->load_idle_state()));
   ret.Set("is_loading", data->is_loading_);
   ret.Set("did_commit", data->did_commit_);
 
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 void PageLoadTrackerDecorator::OnMainThreadTaskLoadIsLow(
diff --git a/components/performance_manager/decorators/page_load_tracker_decorator.h b/components/performance_manager/decorators/page_load_tracker_decorator.h
index bf17c49a..23f1dcad 100644
--- a/components/performance_manager/decorators/page_load_tracker_decorator.h
+++ b/components/performance_manager/decorators/page_load_tracker_decorator.h
@@ -46,7 +46,7 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
 
   // ProcessNodeObserver implementation:
   void OnMainThreadTaskLoadIsLow(const ProcessNode* process_node) override;
diff --git a/components/performance_manager/freezing/freezing_vote_aggregator.cc b/components/performance_manager/freezing/freezing_vote_aggregator.cc
index ac8d3e39..dc9bf11 100644
--- a/components/performance_manager/freezing/freezing_vote_aggregator.cc
+++ b/components/performance_manager/freezing/freezing_vote_aggregator.cc
@@ -116,15 +116,15 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value FreezingVoteAggregator::DescribePageNodeData(
+base::Value::Dict FreezingVoteAggregator::DescribePageNodeData(
     const PageNode* node) const {
   auto votes_for_page = vote_data_map_.find(node);
   if (votes_for_page == vote_data_map_.end())
-    return base::Value();
+    return base::Value::Dict();
 
   base::Value::Dict ret;
   votes_for_page->second.DescribeVotes(ret);
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 FreezingVoteAggregator::FreezingVoteData::FreezingVoteData() = default;
diff --git a/components/performance_manager/freezing/freezing_vote_aggregator.h b/components/performance_manager/freezing/freezing_vote_aggregator.h
index 5820752..49522c80b 100644
--- a/components/performance_manager/freezing/freezing_vote_aggregator.h
+++ b/components/performance_manager/freezing/freezing_vote_aggregator.h
@@ -60,7 +60,7 @@
   void UnregisterNodeDataDescriber(Graph* graph);
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
 
  private:
   friend class performance_manager::FreezingVoteDecorator;
diff --git a/components/performance_manager/graph/frame_node_impl_describer.cc b/components/performance_manager/graph/frame_node_impl_describer.cc
index 44c4376..24c0965 100644
--- a/components/performance_manager/graph/frame_node_impl_describer.cc
+++ b/components/performance_manager/graph/frame_node_impl_describer.cc
@@ -52,7 +52,7 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value FrameNodeImplDescriber::DescribeFrameNodeData(
+base::Value::Dict FrameNodeImplDescriber::DescribeFrameNodeData(
     const FrameNode* node) const {
   const FrameNodeImpl* impl = FrameNodeImpl::FromNode(node);
 
@@ -86,7 +86,7 @@
           ViewportIntersectionToString(impl->viewport_intersection_.value()));
   ret.Set("visibility", FrameNodeVisibilityToString(impl->visibility_.value()));
 
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/frame_node_impl_describer.h b/components/performance_manager/graph/frame_node_impl_describer.h
index 8453e70..78d2a421 100644
--- a/components/performance_manager/graph/frame_node_impl_describer.h
+++ b/components/performance_manager/graph/frame_node_impl_describer.h
@@ -23,7 +23,7 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriberDefaultImpl impl:
-  base::Value DescribeFrameNodeData(const FrameNode* node) const override;
+  base::Value::Dict DescribeFrameNodeData(const FrameNode* node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/graph_impl.cc b/components/performance_manager/graph/graph_impl.cc
index 45170138..a0f555d9 100644
--- a/components/performance_manager/graph/graph_impl.cc
+++ b/components/performance_manager/graph/graph_impl.cc
@@ -65,7 +65,7 @@
   void RegisterDescriber(const NodeDataDescriber* describer,
                          base::StringPiece name) override;
   void UnregisterDescriber(const NodeDataDescriber* describer) override;
-  base::Value DescribeNodeData(const Node* node) const override;
+  base::Value::Dict DescribeNodeData(const Node* node) const override;
 
   size_t size() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -74,8 +74,8 @@
 
  private:
   template <typename NodeType, typename NodeImplType>
-  base::Value DescribeNodeImpl(
-      base::Value (NodeDataDescriber::*DescribeFn)(const NodeType*) const,
+  base::Value::Dict DescribeNodeImpl(
+      base::Value::Dict (NodeDataDescriber::*DescribeFn)(const NodeType*) const,
       const NodeImplType* node) const VALID_CONTEXT_REQUIRED(sequence_checker_);
 
   base::flat_map<const NodeDataDescriber*, std::string> describers_
@@ -84,16 +84,16 @@
 };
 
 template <typename NodeType, typename NodeImplType>
-base::Value NodeDataDescriberRegistryImpl::DescribeNodeImpl(
-    base::Value (NodeDataDescriber::*Describe)(const NodeType*) const,
+base::Value::Dict NodeDataDescriberRegistryImpl::DescribeNodeImpl(
+    base::Value::Dict (NodeDataDescriber::*Describe)(const NodeType*) const,
     const NodeImplType* node) const {
-  base::Value result(base::Value::Type::DICT);
+  base::Value::Dict result;
 
   for (const auto& name_and_describer : describers_) {
-    base::Value description = (name_and_describer.first->*Describe)(node);
-    if (!description.is_none()) {
-      DCHECK_EQ(nullptr, result.FindDictKey(name_and_describer.second));
-      result.SetKey(name_and_describer.second, std::move(description));
+    base::Value::Dict description = (name_and_describer.first->*Describe)(node);
+    if (!description.empty()) {
+      DCHECK_EQ(nullptr, result.FindDict(name_and_describer.second));
+      result.Set(name_and_describer.second, std::move(description));
     }
   }
 
@@ -126,14 +126,14 @@
   DCHECK_EQ(1u, erased);
 }
 
-base::Value NodeDataDescriberRegistryImpl::DescribeNodeData(
+base::Value::Dict NodeDataDescriberRegistryImpl::DescribeNodeData(
     const Node* node) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const NodeBase* node_base = NodeBase::FromNode(node);
   switch (node_base->type()) {
     case NodeTypeEnum::kInvalidType:
       NOTREACHED();
-      return base::Value();
+      return base::Value::Dict();
     case NodeTypeEnum::kFrame:
       return DescribeNodeImpl(&NodeDataDescriber::DescribeFrameNodeData,
                               FrameNodeImpl::FromNodeBase(node_base));
diff --git a/components/performance_manager/graph/graph_impl_unittest.cc b/components/performance_manager/graph/graph_impl_unittest.cc
index 32528d0b..96ae0477 100644
--- a/components/performance_manager/graph/graph_impl_unittest.cc
+++ b/components/performance_manager/graph/graph_impl_unittest.cc
@@ -205,57 +205,59 @@
  public:
   explicit TestNodeDataDescriber(base::StringPiece name) : name_(name) {}
 
-  base::Value DescribeFrameNodeData(const FrameNode* node) const override {
-    base::Value::List list;
-    list.Append(name_);
-    list.Append("FrameNode");
-    return base::Value(std::move(list));
+  base::Value::Dict DescribeFrameNodeData(
+      const FrameNode* node) const override {
+    base::Value::Dict dict;
+    dict.Set("name", name_);
+    dict.Set("type", "FrameNode");
+    return dict;
   }
 
-  base::Value DescribePageNodeData(const PageNode* node) const override {
-    base::Value::List list;
-    list.Append(name_);
-    list.Append("PageNode");
-    return base::Value(std::move(list));
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override {
+    base::Value::Dict dict;
+    dict.Set("name", name_);
+    dict.Set("type", "PageNode");
+    return dict;
   }
 
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override {
-    base::Value::List list;
-    list.Append(name_);
-    list.Append("ProcessNode");
-    return base::Value(std::move(list));
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override {
+    base::Value::Dict dict;
+    dict.Set("name", name_);
+    dict.Set("type", "ProcessNode");
+    return dict;
   }
 
-  base::Value DescribeSystemNodeData(const SystemNode* node) const override {
-    base::Value::List list;
-    list.Append(name_);
-    list.Append("SystemNode");
-    return base::Value(std::move(list));
+  base::Value::Dict DescribeSystemNodeData(
+      const SystemNode* node) const override {
+    base::Value::Dict dict;
+    dict.Set("name", name_);
+    dict.Set("type", "SystemNode");
+    return dict;
   }
 
-  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override {
-    base::Value::List list;
-    list.Append(name_);
-    list.Append("WorkerNode");
-    return base::Value(std::move(list));
+  base::Value::Dict DescribeWorkerNodeData(
+      const WorkerNode* node) const override {
+    base::Value::Dict dict;
+    dict.Set("name", name_);
+    dict.Set("type", "WorkerNode");
+    return dict;
   }
 
  private:
   const std::string name_;
 };
 
-void AssertDictValueContainsListKey(const base::Value& descr,
+void AssertDictValueContainsListKey(const base::Value::Dict& descr,
                                     const char* key,
-                                    const char* s1,
-                                    const char* s2) {
-  ASSERT_TRUE(descr.is_dict());
-  const base::Value* v = descr.FindListKey(key);
-  ASSERT_NE(nullptr, v);
+                                    const std::string s1,
+                                    const std::string s2) {
+  const base::Value::Dict* dict = descr.FindDict(key);
+  ASSERT_NE(nullptr, dict);
 
-  const auto& list = v->GetList();
-  ASSERT_EQ(2u, list.size());
-  ASSERT_EQ(list[0], base::Value(s1));
-  ASSERT_EQ(list[1], base::Value(s2));
+  ASSERT_EQ(2u, dict->size());
+  ASSERT_EQ(*(dict->FindString("name")), s1);
+  ASSERT_EQ(*(dict->FindString("type")), s2);
 }
 
 }  // namespace
@@ -265,8 +267,8 @@
   NodeDataDescriberRegistry* registry = graph()->GetNodeDataDescriberRegistry();
 
   // No describers->no description.
-  base::Value descr = registry->DescribeNodeData(mock_graph.frame.get());
-  EXPECT_EQ(0u, descr.DictSize());
+  base::Value::Dict descr = registry->DescribeNodeData(mock_graph.frame.get());
+  EXPECT_EQ(0u, descr.size());
 
   // Test that the default impl does nothing.
   NodeDataDescriberDefaultImpl default_impl;
@@ -278,25 +280,25 @@
 
   descr = registry->DescribeNodeData(mock_graph.frame.get());
   AssertDictValueContainsListKey(descr, "d1", "d1", "FrameNode");
-  EXPECT_EQ(1u, descr.DictSize());
+  EXPECT_EQ(1u, descr.size());
 
   descr = registry->DescribeNodeData(mock_graph.page.get());
   AssertDictValueContainsListKey(descr, "d1", "d1", "PageNode");
-  EXPECT_EQ(1u, descr.DictSize());
+  EXPECT_EQ(1u, descr.size());
 
   descr = registry->DescribeNodeData(mock_graph.process.get());
   AssertDictValueContainsListKey(descr, "d1", "d1", "ProcessNode");
-  EXPECT_EQ(1u, descr.DictSize());
+  EXPECT_EQ(1u, descr.size());
 
   descr = registry->DescribeNodeData(graph()->GetSystemNode());
   AssertDictValueContainsListKey(descr, "d1", "d1", "SystemNode");
-  EXPECT_EQ(1u, descr.DictSize());
+  EXPECT_EQ(1u, descr.size());
 
   auto worker = CreateNode<WorkerNodeImpl>(WorkerNode::WorkerType::kDedicated,
                                            mock_graph.process.get());
   descr = registry->DescribeNodeData(worker.get());
   AssertDictValueContainsListKey(descr, "d1", "d1", "WorkerNode");
-  EXPECT_EQ(1u, descr.DictSize());
+  EXPECT_EQ(1u, descr.size());
 
   // Unregister the default impl now that it's been verified to say nothing
   // about all node types.
@@ -307,7 +309,7 @@
   registry->RegisterDescriber(&d2, "d2");
 
   descr = registry->DescribeNodeData(mock_graph.frame.get());
-  EXPECT_EQ(2u, descr.DictSize());
+  EXPECT_EQ(2u, descr.size());
   AssertDictValueContainsListKey(descr, "d1", "d1", "FrameNode");
   AssertDictValueContainsListKey(descr, "d2", "d2", "FrameNode");
 
@@ -316,7 +318,7 @@
 
   // No describers after unregistration->no description.
   descr = registry->DescribeNodeData(mock_graph.frame.get());
-  EXPECT_EQ(0u, descr.DictSize());
+  EXPECT_EQ(0u, descr.size());
 }
 
 TEST_F(GraphImplTest, OpenersAndEmbeddersClearedOnTeardown) {
diff --git a/components/performance_manager/graph/node_data_describer.cc b/components/performance_manager/graph/node_data_describer.cc
index 3103611..a167946 100644
--- a/components/performance_manager/graph/node_data_describer.cc
+++ b/components/performance_manager/graph/node_data_describer.cc
@@ -6,29 +6,29 @@
 
 namespace performance_manager {
 
-base::Value NodeDataDescriberDefaultImpl::DescribeFrameNodeData(
+base::Value::Dict NodeDataDescriberDefaultImpl::DescribeFrameNodeData(
     const FrameNode* node) const {
-  return base::Value();
+  return base::Value::Dict();
 }
 
-base::Value NodeDataDescriberDefaultImpl::DescribePageNodeData(
+base::Value::Dict NodeDataDescriberDefaultImpl::DescribePageNodeData(
     const PageNode* node) const {
-  return base::Value();
+  return base::Value::Dict();
 }
 
-base::Value NodeDataDescriberDefaultImpl::DescribeProcessNodeData(
+base::Value::Dict NodeDataDescriberDefaultImpl::DescribeProcessNodeData(
     const ProcessNode* node) const {
-  return base::Value();
+  return base::Value::Dict();
 }
 
-base::Value NodeDataDescriberDefaultImpl::DescribeSystemNodeData(
+base::Value::Dict NodeDataDescriberDefaultImpl::DescribeSystemNodeData(
     const SystemNode* node) const {
-  return base::Value();
+  return base::Value::Dict();
 }
 
-base::Value NodeDataDescriberDefaultImpl::DescribeWorkerNodeData(
+base::Value::Dict NodeDataDescriberDefaultImpl::DescribeWorkerNodeData(
     const WorkerNode* node) const {
-  return base::Value();
+  return base::Value::Dict();
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/page_node_impl_describer.cc b/components/performance_manager/graph/page_node_impl_describer.cc
index 828c676e..ba1593e 100644
--- a/components/performance_manager/graph/page_node_impl_describer.cc
+++ b/components/performance_manager/graph/page_node_impl_describer.cc
@@ -39,7 +39,7 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value PageNodeImplDescriber::DescribePageNodeData(
+base::Value::Dict PageNodeImplDescriber::DescribePageNodeData(
     const PageNode* page_node) const {
   const PageNodeImpl* page_node_impl = PageNodeImpl::FromNode(page_node);
   DCHECK_CALLED_ON_VALID_SEQUENCE(page_node_impl->sequence_checker_);
@@ -86,7 +86,7 @@
   result.Set("freezing_vote",
              FreezingVoteToString(page_node_impl->freezing_vote()));
 
-  return base::Value(std::move(result));
+  return result;
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/page_node_impl_describer.h b/components/performance_manager/graph/page_node_impl_describer.h
index 56bf669d..5bc1d08 100644
--- a/components/performance_manager/graph/page_node_impl_describer.h
+++ b/components/performance_manager/graph/page_node_impl_describer.h
@@ -25,7 +25,8 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* page_node) const override;
+  base::Value::Dict DescribePageNodeData(
+      const PageNode* page_node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/process_node_impl_describer.cc b/components/performance_manager/graph/process_node_impl_describer.cc
index 31cd844..e90a4322 100644
--- a/components/performance_manager/graph/process_node_impl_describer.cc
+++ b/components/performance_manager/graph/process_node_impl_describer.cc
@@ -132,7 +132,7 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value ProcessNodeImplDescriber::DescribeProcessNodeData(
+base::Value::Dict ProcessNodeImplDescriber::DescribeProcessNodeData(
     const ProcessNode* node) const {
   const ProcessNodeImpl* impl = ProcessNodeImpl::FromNode(node);
 
@@ -191,7 +191,7 @@
                 .value());
   }
 
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/process_node_impl_describer.h b/components/performance_manager/graph/process_node_impl_describer.h
index 401214c..e0f1d3f 100644
--- a/components/performance_manager/graph/process_node_impl_describer.h
+++ b/components/performance_manager/graph/process_node_impl_describer.h
@@ -26,7 +26,8 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/worker_node_impl_describer.cc b/components/performance_manager/graph/worker_node_impl_describer.cc
index 72db192b..9ebc9b1 100644
--- a/components/performance_manager/graph/worker_node_impl_describer.cc
+++ b/components/performance_manager/graph/worker_node_impl_describer.cc
@@ -36,11 +36,11 @@
   graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
 }
 
-base::Value WorkerNodeImplDescriber::DescribeWorkerNodeData(
+base::Value::Dict WorkerNodeImplDescriber::DescribeWorkerNodeData(
     const WorkerNode* node) const {
   const WorkerNodeImpl* impl = WorkerNodeImpl::FromNode(node);
   if (!impl)
-    return base::Value();
+    return base::Value::Dict();
 
   base::Value::Dict ret;
   ret.Set("browser_context_id", impl->browser_context_id());
@@ -49,7 +49,7 @@
   ret.Set("worker_type", WorkerTypeToString(impl->worker_type()));
   ret.Set("priority", PriorityAndReasonToValue(impl->priority_and_reason()));
 
-  return base::Value(std::move(ret));
+  return ret;
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/worker_node_impl_describer.h b/components/performance_manager/graph/worker_node_impl_describer.h
index 91504437..2626148 100644
--- a/components/performance_manager/graph/worker_node_impl_describer.h
+++ b/components/performance_manager/graph/worker_node_impl_describer.h
@@ -26,7 +26,8 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override;
+  base::Value::Dict DescribeWorkerNodeData(
+      const WorkerNode* node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/public/decorators/page_live_state_decorator.h b/components/performance_manager/public/decorators/page_live_state_decorator.h
index efc0b54..d4303c9d 100644
--- a/components/performance_manager/public/decorators/page_live_state_decorator.h
+++ b/components/performance_manager/public/decorators/page_live_state_decorator.h
@@ -107,7 +107,7 @@
   void OnTakenFromGraph(Graph* graph) override;
 
   // NodeDataDescriber implementation:
-  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
 
   // PageNode::ObserverDefaultImpl implementation:
   void OnMainFrameUrlChanged(const PageNode* page_node) override;
diff --git a/components/performance_manager/public/graph/node_data_describer.h b/components/performance_manager/public/graph/node_data_describer.h
index 67dbb9e..3d52703 100644
--- a/components/performance_manager/public/graph/node_data_describer.h
+++ b/components/performance_manager/public/graph/node_data_describer.h
@@ -39,23 +39,30 @@
  public:
   virtual ~NodeDataDescriber() = default;
 
-  virtual base::Value DescribeFrameNodeData(const FrameNode* node) const = 0;
-  virtual base::Value DescribePageNodeData(const PageNode* node) const = 0;
-  virtual base::Value DescribeProcessNodeData(
+  virtual base::Value::Dict DescribeFrameNodeData(
+      const FrameNode* node) const = 0;
+  virtual base::Value::Dict DescribePageNodeData(
+      const PageNode* node) const = 0;
+  virtual base::Value::Dict DescribeProcessNodeData(
       const ProcessNode* node) const = 0;
-  virtual base::Value DescribeSystemNodeData(const SystemNode* node) const = 0;
-  virtual base::Value DescribeWorkerNodeData(const WorkerNode* node) const = 0;
+  virtual base::Value::Dict DescribeSystemNodeData(
+      const SystemNode* node) const = 0;
+  virtual base::Value::Dict DescribeWorkerNodeData(
+      const WorkerNode* node) const = 0;
 };
 
 // A convenience do-nothing implementation of the interface above. Returns
 // an is_none() value for all nodes.
 class NodeDataDescriberDefaultImpl : public NodeDataDescriber {
  public:
-  base::Value DescribeFrameNodeData(const FrameNode* node) const override;
-  base::Value DescribePageNodeData(const PageNode* node) const override;
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
-  base::Value DescribeSystemNodeData(const SystemNode* node) const override;
-  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override;
+  base::Value::Dict DescribeFrameNodeData(const FrameNode* node) const override;
+  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
+  base::Value::Dict DescribeSystemNodeData(
+      const SystemNode* node) const override;
+  base::Value::Dict DescribeWorkerNodeData(
+      const WorkerNode* node) const override;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/public/graph/node_data_describer_registry.h b/components/performance_manager/public/graph/node_data_describer_registry.h
index e3e83e6..c75ba8b 100644
--- a/components/performance_manager/public/graph/node_data_describer_registry.h
+++ b/components/performance_manager/public/graph/node_data_describer_registry.h
@@ -28,7 +28,7 @@
 
   // Invoke all registered describers for |node| and return a dictionary from
   // their name to their description - if any.
-  virtual base::Value DescribeNodeData(const Node* node) const = 0;
+  virtual base::Value::Dict DescribeNodeData(const Node* node) const = 0;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/v8_memory/v8_context_tracker.cc b/components/performance_manager/v8_memory/v8_context_tracker.cc
index 69d07b2..f37e75f 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker.cc
+++ b/components/performance_manager/v8_memory/v8_context_tracker.cc
@@ -407,7 +407,7 @@
   graph->RemoveGraphObserver(this);
 }
 
-base::Value V8ContextTracker::DescribeFrameNodeData(
+base::Value::Dict V8ContextTracker::DescribeFrameNodeData(
     const FrameNode* node) const {
   DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
 
@@ -419,10 +419,10 @@
 
   base::Value::Dict dict;
   dict.Set("v8_context_count", static_cast<int>(v8_context_count));
-  return base::Value(std::move(dict));
+  return dict;
 }
 
-base::Value V8ContextTracker::DescribeProcessNodeData(
+base::Value::Dict V8ContextTracker::DescribeProcessNodeData(
     const ProcessNode* node) const {
   DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
 
@@ -447,10 +447,10 @@
            static_cast<int>(execution_context_count));
   dict.Set("destroyed_execution_context_count",
            static_cast<int>(destroyed_execution_context_count));
-  return base::Value(std::move(dict));
+  return dict;
 }
 
-base::Value V8ContextTracker::DescribeWorkerNodeData(
+base::Value::Dict V8ContextTracker::DescribeWorkerNodeData(
     const WorkerNode* node) const {
   DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
   size_t v8_context_count = 0;
@@ -461,7 +461,7 @@
 
   base::Value::Dict dict;
   dict.Set("v8_context_count", static_cast<int>(v8_context_count));
-  return base::Value(std::move(dict));
+  return dict;
 }
 
 void V8ContextTracker::OnBeforeProcessNodeRemoved(const ProcessNode* node) {
diff --git a/components/performance_manager/v8_memory/v8_context_tracker.h b/components/performance_manager/v8_memory/v8_context_tracker.h
index 8c3b677e..af6e69d 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker.h
+++ b/components/performance_manager/v8_memory/v8_context_tracker.h
@@ -218,9 +218,10 @@
 
   // Implementation of NodeDataDescriber. We have things to say about
   // execution contexts (frames and workers), as well as processes.
-  base::Value DescribeFrameNodeData(const FrameNode* node) const final;
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const final;
-  base::Value DescribeWorkerNodeData(const WorkerNode* node) const final;
+  base::Value::Dict DescribeFrameNodeData(const FrameNode* node) const final;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const final;
+  base::Value::Dict DescribeWorkerNodeData(const WorkerNode* node) const final;
 
   // Implementation of ProcessNode::ObserverDefaultImpl.
   void OnBeforeProcessNodeRemoved(const ProcessNode* node) final;
diff --git a/components/performance_manager/v8_memory/v8_detailed_memory_decorator.cc b/components/performance_manager/v8_memory/v8_detailed_memory_decorator.cc
index c811a2d..f74cde8 100644
--- a/components/performance_manager/v8_memory/v8_detailed_memory_decorator.cc
+++ b/components/performance_manager/v8_memory/v8_detailed_memory_decorator.cc
@@ -753,26 +753,26 @@
   process_data->process_measurement_requests().OnOwnerUnregistered();
 }
 
-base::Value V8DetailedMemoryDecorator::DescribeFrameNodeData(
+base::Value::Dict V8DetailedMemoryDecorator::DescribeFrameNodeData(
     const FrameNode* frame_node) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const auto* const frame_data =
       V8DetailedMemoryExecutionContextData::ForFrameNode(frame_node);
   if (!frame_data)
-    return base::Value();
+    return base::Value::Dict();
 
   base::Value::Dict dict;
   dict.Set("v8_bytes_used", static_cast<int>(frame_data->v8_bytes_used()));
-  return base::Value(std::move(dict));
+  return dict;
 }
 
-base::Value V8DetailedMemoryDecorator::DescribeProcessNodeData(
+base::Value::Dict V8DetailedMemoryDecorator::DescribeProcessNodeData(
     const ProcessNode* process_node) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const auto* const process_data =
       V8DetailedMemoryProcessData::ForProcessNode(process_node);
   if (!process_data)
-    return base::Value();
+    return base::Value::Dict();
 
   DCHECK_EQ(content::PROCESS_TYPE_RENDERER, process_node->GetProcessType());
 
@@ -781,7 +781,7 @@
            static_cast<int>(process_data->detached_v8_bytes_used()));
   dict.Set("shared_v8_bytes_used",
            static_cast<int>(process_data->shared_v8_bytes_used()));
-  return base::Value(std::move(dict));
+  return dict;
 }
 
 const V8DetailedMemoryRequest* V8DetailedMemoryDecorator::GetNextRequest()
diff --git a/components/performance_manager/v8_memory/v8_detailed_memory_decorator.h b/components/performance_manager/v8_memory/v8_detailed_memory_decorator.h
index 90f1c6a0..50e96ae4 100644
--- a/components/performance_manager/v8_memory/v8_detailed_memory_decorator.h
+++ b/components/performance_manager/v8_memory/v8_detailed_memory_decorator.h
@@ -53,8 +53,9 @@
   void OnBeforeProcessNodeRemoved(const ProcessNode* process_node) override;
 
   // NodeDataDescriber overrides.
-  base::Value DescribeFrameNodeData(const FrameNode* node) const override;
-  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value::Dict DescribeFrameNodeData(const FrameNode* node) const override;
+  base::Value::Dict DescribeProcessNodeData(
+      const ProcessNode* node) const override;
 
   // Returns the next measurement request that should be scheduled.
   const V8DetailedMemoryRequest* GetNextRequest() const;
diff --git a/components/policy/BUILD.gn b/components/policy/BUILD.gn
index 0dd4bcd..8b478f9 100644
--- a/components/policy/BUILD.gn
+++ b/components/policy/BUILD.gn
@@ -72,30 +72,10 @@
 # and compiled.
 cloud_policy_proto_path = "$target_gen_dir/proto/cloud_policy.proto"
 
-# This file is used by chrome/browser/privacy/traffic_annotation.proto as it
-# needs a version without LITE_RUNTIME optimization.
-cloud_policy_full_runtime_proto_path =
-    "$target_gen_dir/proto/cloud_policy_full_runtime.proto"
-
-# This protobuf contains the common definitions of the shared messages
-# between user and device policies
-policy_common_definitions_proto_abspath =
-    "//components/policy/proto/policy_common_definitions.proto"
-
-# This file is used by chrome/browser/privacy/traffic_annotation.proto as it
-# needs a version without LITE_RUNTIME optimization.
-policy_common_definitions_full_runtime_proto_path =
-    "$target_gen_dir/proto/policy_common_definitions_full_runtime.proto"
-
 # This is the "full" protobuf, which defines one protobuf message per
 # policy. It is also the format currently used by the server.
 chrome_settings_proto_path = "$target_gen_dir/proto/chrome_settings.proto"
 
-# This file is used by chrome/browser/privacy/traffic_annotation.proto as it
-# needs a version without LITE_RUNTIME optimization.
-chrome_settings_full_runtime_proto_path =
-    "$target_gen_dir/proto/chrome_settings_full_runtime.proto"
-
 constants_header_path = "$target_gen_dir/policy_constants.h"
 constants_source_path = "$target_gen_dir/policy_constants.cc"
 app_restrictions_path = "$target_gen_dir/app_restrictions.xml"
@@ -150,43 +130,6 @@
   ]
 }
 
-action("full_runtime_code_generate") {
-  script = "tools/generate_policy_source.py"
-  chrome_version_abspath = "//chrome/VERSION"
-  chrome_version_path = rebase_path(chrome_version_abspath, root_build_dir)
-
-  deps = [ ":generate_policy_templates" ]
-  inputs = [
-    chrome_version_abspath,
-    policy_templates_generated_json_path,
-  ]
-  outputs = [
-    cloud_policy_full_runtime_proto_path,
-    chrome_settings_full_runtime_proto_path,
-    policy_common_definitions_full_runtime_proto_path,
-  ]
-
-  args = [
-    # Input information
-    "--chrome-version-file=" + chrome_version_path,
-    "--target-platform=" + target_os,
-    "--policy-templates-file=" +
-        rebase_path(policy_templates_generated_json_path, root_build_dir),
-    "--target-platform=" + target_os,
-
-    # Output files to be generated
-    "--cloud-policy-full-runtime-protobuf=" +
-        rebase_path(cloud_policy_full_runtime_proto_path, root_build_dir),
-    "--chrome-settings-full-runtime-protobuf=" +
-        rebase_path(chrome_settings_full_runtime_proto_path, root_build_dir),
-    "--policy-common-definitions-protobuf=" +
-        rebase_path(policy_common_definitions_proto_abspath, root_build_dir),
-    "--policy-common-definitions-full-runtime-protobuf=" +
-        rebase_path(policy_common_definitions_full_runtime_proto_path,
-                    root_build_dir),
-  ]
-}
-
 policy_templates_grd_file = "resources/policy_templates.build.grd"
 
 # Generates a single policy_templates.json with a real JSON format.
@@ -385,7 +328,6 @@
   defines = [ "POLICY_COMPONENT_IMPLEMENTATION" ]
   public_deps = [
     ":cloud_policy_proto_generated_compile",
-    ":full_runtime_code_generate",
     ":policy_code_generate",
     "//base",
     "//components/policy/core/common:common_constants",
diff --git a/components/policy/core/common/async_policy_loader.cc b/components/policy/core/common/async_policy_loader.cc
index f4ba4910..f22b9ada 100644
--- a/components/policy/core/common/async_policy_loader.cc
+++ b/components/policy/core/common/async_policy_loader.cc
@@ -34,9 +34,9 @@
 AsyncPolicyLoader::AsyncPolicyLoader(
     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     bool periodic_updates)
-    : task_runner_(task_runner),
-      management_service_(nullptr),
-      periodic_updates_(periodic_updates) {}
+    : AsyncPolicyLoader(task_runner,
+                        /*management_service=*/nullptr,
+                        periodic_updates) {}
 
 AsyncPolicyLoader::AsyncPolicyLoader(
     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
@@ -44,7 +44,8 @@
     bool periodic_updates)
     : task_runner_(task_runner),
       management_service_(management_service),
-      periodic_updates_(periodic_updates) {}
+      periodic_updates_(periodic_updates),
+      reload_interval_(kReloadInterval) {}
 
 AsyncPolicyLoader::~AsyncPolicyLoader() {}
 
@@ -98,7 +99,11 @@
 
   update_callback_.Run(std::move(bundle));
   if (periodic_updates_) {
-    ScheduleNextReload(kReloadInterval);
+    // Note: it is important to schedule the next reload after calling Load()
+    // to make sure that anything done in Load() that may change the state of
+    // the loader  (e.g. changing the `reload_interval_`) is effective before
+    // scheduling the next reload.
+    ScheduleNextReload(get_reload_interval());
   }
 }
 
@@ -158,7 +163,7 @@
 
   // Start periodic refreshes.
   if (periodic_updates_) {
-    ScheduleNextReload(kReloadInterval);
+    ScheduleNextReload(get_reload_interval());
   }
 }
 
diff --git a/components/policy/core/common/async_policy_loader.h b/components/policy/core/common/async_policy_loader.h
index 38a8dfa..7ee411f 100644
--- a/components/policy/core/common/async_policy_loader.h
+++ b/components/policy/core/common/async_policy_loader.h
@@ -91,6 +91,12 @@
 
   const scoped_refptr<SchemaMap>& schema_map() const { return schema_map_; }
 
+  base::TimeDelta get_reload_interval() const { return reload_interval_; }
+
+  void set_reload_interval(base::TimeDelta reload_interval) {
+    reload_interval_ = reload_interval;
+  }
+
  private:
   // Allow AsyncPolicyProvider to call Init().
   friend class AsyncPolicyProvider;
@@ -143,6 +149,10 @@
   // The current policy schemas that this provider should load.
   scoped_refptr<SchemaMap> schema_map_;
 
+  // The interval of time between periodic updates. Only relevant when
+  // `periodic_updates_` is true to enable periodic updates.
+  base::TimeDelta reload_interval_;
+
   // Used to get WeakPtrs for the periodic reload task.
   base::WeakPtrFactory<AsyncPolicyLoader> weak_factory_{this};
 };
diff --git a/components/policy/core/common/policy_loader_ios.mm b/components/policy/core/common/policy_loader_ios.mm
index 71fa0510..8e76f39 100644
--- a/components/policy/core/common/policy_loader_ios.mm
+++ b/components/policy/core/common/policy_loader_ios.mm
@@ -2,34 +2,49 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/policy/core/common/policy_loader_ios.h"
+#import "components/policy/core/common/policy_loader_ios.h"
 
 #import <Foundation/Foundation.h>
-#include <stddef.h>
 #import <UIKit/UIKit.h>
+#import <stddef.h>
 
-#include "base/check.h"
-#include "base/functional/bind.h"
-#include "base/json/json_reader.h"
-#include "base/location.h"
+#import "base/check.h"
+#import "base/functional/bind.h"
+#import "base/json/json_reader.h"
+#import "base/location.h"
 #import "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/sys_string_conversions.h"
+#import "base/metrics/histogram_macros.h"
+#import "base/strings/sys_string_conversions.h"
 #import "base/task/sequenced_task_runner.h"
-#include "base/task/sequenced_task_runner.h"
-#include "components/policy/core/common/mac_util.h"
-#include "components/policy/core/common/policy_bundle.h"
+#import "base/time/time.h"
+#import "components/policy/core/common/mac_util.h"
+#import "components/policy/core/common/policy_bundle.h"
 #import "components/policy/core/common/policy_loader_ios_constants.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/core/common/policy_namespace.h"
-#include "components/policy/core/common/schema.h"
-#include "components/policy/core/common/schema_registry.h"
-#include "components/policy/policy_constants.h"
+#import "components/policy/core/common/policy_map.h"
+#import "components/policy/core/common/policy_namespace.h"
+#import "components/policy/core/common/schema.h"
+#import "components/policy/core/common/schema_registry.h"
+#import "components/policy/policy_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Policy reload interval when the browser has platform policy key.
+constexpr base::TimeDelta kManagedByPlatformReloadInterval = base::Seconds(30);
+
+// Returns YES if the browser has platform policy key by looking at the
+// presence of the App Config key. Even if the value of the key is an empty
+// dictionary, the browser will be considered as managed.
+BOOL HasPlatformPolicyKey() {
+  return [[NSUserDefaults standardUserDefaults]
+             dictionaryForKey:kPolicyLoaderIOSConfigurationKey] != nil;
+}
+
+}  // namespace
+
 namespace policy {
 
 PolicyLoaderIOS::PolicyLoaderIOS(
@@ -57,6 +72,12 @@
   size_t count = bundle.Get(chrome_ns).size();
   UMA_HISTOGRAM_COUNTS_100("Enterprise.IOSPolicies", count);
 
+  if (HasPlatformPolicyKey()) {
+    // Set a shorter reload interval when the browser is managed by the
+    // platform. This is to take the dynamic policy updates quickly.
+    set_reload_interval(kManagedByPlatformReloadInterval);
+  }
+
   return bundle;
 }
 
diff --git a/components/policy/core/common/policy_loader_ios_unittest.mm b/components/policy/core/common/policy_loader_ios_unittest.mm
index a4e87c2..6b94309 100644
--- a/components/policy/core/common/policy_loader_ios_unittest.mm
+++ b/components/policy/core/common/policy_loader_ios_unittest.mm
@@ -16,14 +16,18 @@
 #import "base/task/sequenced_task_runner.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/test_simple_task_runner.h"
+#import "base/time/time.h"
 #include "base/values.h"
 #include "components/policy/core/common/async_policy_provider.h"
 #include "components/policy/core/common/configuration_policy_provider_test.h"
 #include "components/policy/core/common/policy_bundle.h"
 #import "components/policy/core/common/policy_loader_ios_constants.h"
 #include "components/policy/core/common/policy_map.h"
+#import "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_test_utils.h"
 #include "components/policy/core/common/policy_types.h"
+#include "components/policy/core/common/schema.h"
+#include "components/policy/core/common/schema_registry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -202,4 +206,129 @@
                          ConfigurationPolicyProviderTest,
                          testing::Values(TestHarness::CreateWithJSONEncoding));
 
+const char kTestChromeSchema[] =
+    "{"
+    "  \"type\": \"object\","
+    "  \"properties\": {"
+    "    \"StringPolicy\": { \"type\": \"string\" },"
+    "  }"
+    "}";
+
+PolicyNamespace GetPolicyNamespace() {
+  return PolicyNamespace(POLICY_DOMAIN_CHROME, "");
+}
+
+// Tests cases not covered by the test harnest.
+class PolicyLoaderIosTest : public PlatformTest {
+ protected:
+  PolicyLoaderIosTest()
+      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+  void SetUp() override {
+    std::string error = RegisterSchema(GetPolicyNamespace(), kTestChromeSchema);
+    ASSERT_TRUE(error.empty())
+        << "Registration of schema failed with error: " << error;
+  }
+
+  void TearDown() override {
+    task_environment_.RunUntilIdle();
+    provider_->Shutdown();
+    // Clear App Config.
+    [[NSUserDefaults standardUserDefaults]
+        removeObjectForKey:kPolicyLoaderIOSConfigurationKey];
+  }
+
+  void InitProvider() {
+    std::unique_ptr<PolicyLoaderIOS> loader = std::make_unique<PolicyLoaderIOS>(
+        &schema_registry_, task_environment_.GetMainThreadTaskRunner());
+    provider_ = std::make_unique<AsyncPolicyProvider>(&schema_registry_,
+                                                      std::move(loader));
+    provider_->Init(&schema_registry_);
+    task_environment_.RunUntilIdle();
+  }
+
+  base::test::TaskEnvironment task_environment_;
+  SchemaRegistry schema_registry_;
+  std::unique_ptr<AsyncPolicyProvider> provider_;
+
+ private:
+  std::string RegisterSchema(const PolicyNamespace& ns,
+                             const std::string& schema_string) {
+    std::string error;
+    Schema schema = Schema::Parse(schema_string, &error);
+    if (schema.valid()) {
+      schema_registry_.RegisterComponent(ns, schema);
+      return std::string();
+    }
+    return error;
+  }
+};
+
+TEST_F(PolicyLoaderIosTest, ReloadIntervalWhenBrowserManagedPostStartup) {
+  InitProvider();
+
+  // Verify that there are no policies loaded at startup.
+  EXPECT_TRUE(provider_->policies().Equals(PolicyBundle()));
+
+  // Set a policy in the App Config at runtime to replicate the situation where
+  // the browser is put under management after startup.
+  NSDictionary* policies = @{@"StringPolicy" : @"string_value"};
+  [[NSUserDefaults standardUserDefaults]
+      setObject:policies
+         forKey:kPolicyLoaderIOSConfigurationKey];
+
+  // Verify that the new policy changes aren't picked up after 10 minutes
+  // when the browser wasn't managed at startup. This is to make sure that the
+  // first reload was scheduled with an interval of 15 minutes.
+  task_environment_.FastForwardBy(base::Minutes(10));
+  EXPECT_TRUE(provider_->policies().Equals(PolicyBundle()));
+
+  // Verify that the new policy changes are picked up after 15 minutes +
+  // epsilon.
+  task_environment_.FastForwardBy(base::Minutes(5) + base::Seconds(1));
+  ASSERT_TRUE(task_environment_.MainThreadIsIdle());
+  PolicyBundle bundle;
+  bundle.Get(GetPolicyNamespace())
+      .Set("StringPolicy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+           POLICY_SOURCE_PLATFORM, base::Value("string_value"), nullptr);
+  EXPECT_TRUE(provider_->policies().Equals(bundle));
+
+  // Simulate the situation where the App Config is updated with new values
+  // before the next reload.
+  NSDictionary* new_policies = @{@"StringPolicy" : @"string_value_new"};
+  [[NSUserDefaults standardUserDefaults]
+      setObject:new_policies
+         forKey:kPolicyLoaderIOSConfigurationKey];
+
+  // Verify that the interval was adjusted to 30 seconds after first reload.
+  task_environment_.FastForwardBy(base::Seconds(31));
+  ASSERT_TRUE(task_environment_.MainThreadIsIdle());
+  PolicyBundle new_bundle;
+  new_bundle.Get(GetPolicyNamespace())
+      .Set("StringPolicy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+           POLICY_SOURCE_PLATFORM, base::Value("string_value_new"), nullptr);
+  EXPECT_TRUE(provider_->policies().Equals(new_bundle));
+}
+
+TEST_F(PolicyLoaderIosTest, ReloadIntervalWhenManagedByPlatformBeforeStartup) {
+  // Set a policy in the App Config to replicate the situation where the browser
+  // is put under management before startup.
+  NSDictionary* policies = @{@"StringPolicy" : @"string_value"};
+  [[NSUserDefaults standardUserDefaults]
+      setObject:policies
+         forKey:kPolicyLoaderIOSConfigurationKey];
+
+  InitProvider();
+
+  // Verify that the new policy changes are picked up after 30 seconds +
+  // epsilon.
+  task_environment_.FastForwardBy(base::Seconds(31));
+  ASSERT_TRUE(task_environment_.MainThreadIsIdle());
+  PolicyBundle bundle;
+  bundle.Get(GetPolicyNamespace())
+      .Set("StringPolicy", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+           POLICY_SOURCE_PLATFORM, base::Value("string_value"), nullptr);
+  EXPECT_TRUE(provider_->policies().Equals(bundle));
+}
+
 }  // namespace policy
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index 2b0fac5f1..6535cc3 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -261,34 +261,12 @@
       help='generate cloud policy protobuf file',
       metavar='FILE')
   parser.add_argument(
-      '--cpfrp',
-      '--cloud-policy-full-runtime-protobuf',
-      dest='cloud_policy_full_runtime_proto_path',
-      help='generate cloud policy full runtime protobuf',
-      metavar='FILE')
-  parser.add_argument(
       '--csp',
       '--chrome-settings-protobuf',
       dest='chrome_settings_proto_path',
       help='generate chrome settings protobuf file',
       metavar='FILE')
   parser.add_argument(
-      '--policy-common-definitions-protobuf',
-      dest='policy_common_definitions_proto_path',
-      help='policy common definitions protobuf file path',
-      metavar='FILE')
-  parser.add_argument(
-      '--policy-common-definitions-full-runtime-protobuf',
-      dest='policy_common_definitions_full_runtime_proto_path',
-      help='generate policy common definitions full runtime protobuf file',
-      metavar='FILE')
-  parser.add_argument(
-      '--csfrp',
-      '--chrome-settings-full-runtime-protobuf',
-      dest='chrome_settings_full_runtime_proto_path',
-      help='generate chrome settings full runtime protobuf',
-      metavar='FILE')
-  parser.add_argument(
       '--ard',
       '--app-restrictions-definition',
       dest='app_restrictions_path',
@@ -420,20 +398,8 @@
     GenerateFile(args.risk_header_path, _WritePolicyRiskTagHeader)
   if args.cloud_policy_proto_path:
     GenerateFile(args.cloud_policy_proto_path, _WriteCloudPolicyProtobuf)
-  if (args.policy_common_definitions_full_runtime_proto_path and
-      args.policy_common_definitions_proto_path):
-    GenerateFile(
-        args.policy_common_definitions_full_runtime_proto_path,
-        partial(_WritePolicyCommonDefinitionsFullRuntimeProtobuf,
-                args.policy_common_definitions_proto_path))
-  if args.cloud_policy_full_runtime_proto_path:
-    GenerateFile(args.cloud_policy_full_runtime_proto_path,
-                 partial(_WriteCloudPolicyProtobuf, is_full_runtime=True))
   if args.chrome_settings_proto_path:
     GenerateFile(args.chrome_settings_proto_path, _WriteChromeSettingsProtobuf)
-  if args.chrome_settings_full_runtime_proto_path:
-    GenerateFile(args.chrome_settings_full_runtime_proto_path,
-                 partial(_WriteChromeSettingsProtobuf, is_full_runtime=True))
 
   if target_platform == 'android' and args.app_restrictions_path:
     GenerateFile(args.app_restrictions_path, _WriteAppRestrictions, xml=True)
@@ -1515,27 +1481,27 @@
 CHROME_SETTINGS_PROTO_HEAD = '''
 syntax = "proto2";
 
-{full_runtime_comment}option optimize_for = LITE_RUNTIME;
+option optimize_for = LITE_RUNTIME;
 
 package enterprise_management;
 
 option go_package="chromium/policy/enterprise_management_proto";
 
 // For StringList and PolicyOptions.
-import "policy_common_definitions{full_runtime_suffix}.proto";
+import "policy_common_definitions.proto";
 
 '''
 
 CLOUD_POLICY_PROTO_HEAD = '''
 syntax = "proto2";
 
-{full_runtime_comment}option optimize_for = LITE_RUNTIME;
+option optimize_for = LITE_RUNTIME;
 
 package enterprise_management;
 
 option go_package="chromium/policy/enterprise_management_proto";
 
-import "policy_common_definitions{full_runtime_suffix}.proto";
+import "policy_common_definitions.proto";
 
 '''
 
@@ -1598,20 +1564,9 @@
     return (policy_id - _LAST_TOP_LEVEL_POLICY_ID - 1) % _CHUNK_SIZE + 1
 
 
-def _WriteChromeSettingsProtobuf(policies,
-                                 policy_atomic_groups,
-                                 target_platform,
-                                 f,
-                                 risk_tags,
-                                 is_full_runtime=False):
-  # For full runtime, disable LITE_RUNTIME switch and import full runtime
-  # version of policy_common_definitions.proto.
-  full_runtime_comment = '//' if is_full_runtime else ''
-  full_runtime_suffix = '_full_runtime' if is_full_runtime else ''
-  f.write(
-      CHROME_SETTINGS_PROTO_HEAD.format(
-          full_runtime_comment=full_runtime_comment,
-          full_runtime_suffix=full_runtime_suffix))
+def _WriteChromeSettingsProtobuf(policies, policy_atomic_groups,
+                                 target_platform, f, risk_tags):
+  f.write(CHROME_SETTINGS_PROTO_HEAD)
   fields = defaultdict(list)
   f.write('// PBs for individual settings.\n\n')
   for policy in policies:
@@ -1656,19 +1611,9 @@
   f.write('}\n')
 
 
-def _WriteCloudPolicyProtobuf(policies,
-                              policy_atomic_groups,
-                              target_platform,
-                              f,
-                              risk_tags,
-                              is_full_runtime=False):
-  # For full runtime, disable LITE_RUNTIME switch and import full runtime
-  # version of policy_common_definitions.proto.
-  full_runtime_comment = '//' if is_full_runtime else ''
-  full_runtime_suffix = '_full_runtime' if is_full_runtime else ''
-  f.write(
-      CLOUD_POLICY_PROTO_HEAD.format(full_runtime_comment=full_runtime_comment,
-                                     full_runtime_suffix=full_runtime_suffix))
+def _WriteCloudPolicyProtobuf(policies, policy_atomic_groups, target_platform,
+                              f, risk_tags):
+  f.write(CLOUD_POLICY_PROTO_HEAD)
 
   fields = defaultdict(list)
 
@@ -1707,18 +1652,6 @@
   f.write('}\n')
 
 
-def _WritePolicyCommonDefinitionsFullRuntimeProtobuf(
-    policy_common_definitions_proto_path, policies, policy_atomic_groups,
-    target_platform, f, risk_tags):
-  # For full runtime, disable LITE_RUNTIME switch
-  with open(policy_common_definitions_proto_path, 'r') as proto_file:
-    policy_common_definitions_proto_code = proto_file.read()
-  f.write(
-      policy_common_definitions_proto_code.replace(
-          "option optimize_for = LITE_RUNTIME;",
-          "//option optimize_for = LITE_RUNTIME;"))
-
-
 #------------------ Chrome OS policy constants header --------------#
 
 # This code applies to Active Directory management only.
diff --git a/components/policy/tools/generate_policy_source_test.py b/components/policy/tools/generate_policy_source_test.py
index 9d5c1e1..eaf483e 100755
--- a/components/policy/tools/generate_policy_source_test.py
+++ b/components/policy/tools/generate_policy_source_test.py
@@ -304,62 +304,32 @@
     self.assertEqual(expected_output.strip(), actual_output.strip())
 
   def testWriteCloudPolicyProtobuf(self):
-    is_full_runtime_values = [False, True]
     output_path = 'mock_cloud_policy_proto'
 
-    for is_full_runtime in is_full_runtime_values:
-      with patch('codecs.open', mock_open()) as mocked_file:
-        with codecs.open(output_path, 'w', encoding='utf-8') as f:
-          generate_policy_source._WriteCloudPolicyProtobuf(
-              self.policies,
-              self.policy_atomic_groups,
-              self.target_platform,
-              f,
-              self.risk_tags,
-              is_full_runtime=is_full_runtime)
+    with patch('codecs.open', mock_open()) as mocked_file:
+      with codecs.open(output_path, 'w', encoding='utf-8') as f:
+        generate_policy_source._WriteCloudPolicyProtobuf(
+            self.policies, self.policy_atomic_groups, self.target_platform, f,
+            self.risk_tags)
 
-      full_runtime_comment = '//' if is_full_runtime else ''
-      full_runtime_suffix = '_full_runtime' if is_full_runtime else ''
+    mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
 
-      with self.subTest(is_full_runtime=is_full_runtime):
-        mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
-
-        expected_formatted = test_data.EXPECTED_CLOUD_POLICY_PROTOBUF % {
-            "full_runtime_comment": full_runtime_comment,
-            "full_runtime_suffix": full_runtime_suffix,
-        }
-
-        self._assertCallsEqual(expected_formatted,
-                               mocked_file().write.call_args_list)
+    self._assertCallsEqual(test_data.EXPECTED_CLOUD_POLICY_PROTOBUF,
+                           mocked_file().write.call_args_list)
 
   def testWriteChromeSettingsProtobuf(self):
-    is_full_runtime_values = [False, True]
     output_path = 'mock_chrome_settings_proto'
 
-    for is_full_runtime in is_full_runtime_values:
-      with patch('codecs.open', mock_open()) as mocked_file:
-        with codecs.open(output_path, 'w', encoding='utf-8') as f:
-          generate_policy_source._WriteChromeSettingsProtobuf(
-              self.policies,
-              self.policy_atomic_groups,
-              self.target_platform,
-              f,
-              self.risk_tags,
-              is_full_runtime=is_full_runtime)
+    with patch('codecs.open', mock_open()) as mocked_file:
+      with codecs.open(output_path, 'w', encoding='utf-8') as f:
+        generate_policy_source._WriteChromeSettingsProtobuf(
+            self.policies, self.policy_atomic_groups, self.target_platform, f,
+            self.risk_tags)
 
-      full_runtime_comment = '//' if is_full_runtime else ''
-      full_runtime_suffix = '_full_runtime' if is_full_runtime else ''
+      mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
 
-      with self.subTest(is_full_runtime=is_full_runtime):
-        mocked_file.assert_called_once_with(output_path, 'w', encoding='utf-8')
-
-        expected_formatted = test_data.EXPECTED_CHROME_SETTINGS_PROTOBUF % {
-            "full_runtime_comment": full_runtime_comment,
-            "full_runtime_suffix": full_runtime_suffix,
-        }
-
-        self._assertCallsEqual(expected_formatted,
-                               mocked_file().write.call_args_list)
+      self._assertCallsEqual(test_data.EXPECTED_CHROME_SETTINGS_PROTOBUF,
+                             mocked_file().write.call_args_list)
 
   def testWritePolicyProto(self):
     output_path = 'mock_write_policy_proto'
diff --git a/components/policy/tools/generate_policy_source_test_data.py b/components/policy/tools/generate_policy_source_test_data.py
index 4ffb6b5..430dd7e 100644
--- a/components/policy/tools/generate_policy_source_test_data.py
+++ b/components/policy/tools/generate_policy_source_test_data.py
@@ -10,13 +10,13 @@
 EXPECTED_CLOUD_POLICY_PROTOBUF = '''
 syntax = "proto2";
 
-%(full_runtime_comment)soption optimize_for = LITE_RUNTIME;
+option optimize_for = LITE_RUNTIME;
 
 package enterprise_management;
 
 option go_package="chromium/policy/enterprise_management_proto";
 
-import "policy_common_definitions%(full_runtime_suffix)s.proto";
+import "policy_common_definitions.proto";
 
 message CloudPolicySubProto1 {
   optional BooleanPolicyProto ChunkOneFirstFieldBooleanPolicy = 1;
@@ -45,14 +45,14 @@
 EXPECTED_CHROME_SETTINGS_PROTOBUF = """
 syntax = "proto2";
 
-%(full_runtime_comment)soption optimize_for = LITE_RUNTIME;
+option optimize_for = LITE_RUNTIME;
 
 package enterprise_management;
 
 option go_package="chromium/policy/enterprise_management_proto";
 
 // For StringList and PolicyOptions.
-import "policy_common_definitions%(full_runtime_suffix)s.proto";
+import "policy_common_definitions.proto";
 
 // PBs for individual settings.
 
diff --git a/components/viz/common/quads/render_pass_io.cc b/components/viz/common/quads/render_pass_io.cc
index 7ea951a..74d574da 100644
--- a/components/viz/common/quads/render_pass_io.cc
+++ b/components/viz/common/quads/render_pass_io.cc
@@ -496,8 +496,7 @@
 std::string PaintFilterToString(const sk_sp<cc::PaintFilter>& filter) {
   // TODO(zmo): Expand to readable fields. Such recorded data becomes invalid
   // when we update any data structure.
-  std::vector<uint8_t> buffer(cc::PaintOpWriter::HeaderBytes() +
-                              cc::PaintFilter::GetFilterSize(filter.get()));
+  std::vector<uint8_t> buffer(cc::PaintOpWriter::SerializedSize(filter.get()));
   // No need to populate the SerializeOptions here since the security
   // constraints explicitly disable serializing images using the transfer cache
   // and serialization of PaintRecords.
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index ec3cd8a..35de646 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -131,15 +131,20 @@
 
 void FromYUVQuad(const YUVVideoDrawQuad* quad,
                  const gfx::Transform& transform_to_root_target,
-                 DCLayerOverlayCandidate* dc_layer) {
+                 OverlayCandidate* dc_layer) {
   // Direct composition path only supports a single NV12 buffer.
   DCHECK(quad->y_plane_resource_id() && quad->u_plane_resource_id());
   DCHECK_EQ(quad->u_plane_resource_id(), quad->v_plane_resource_id());
   dc_layer->resource_id = quad->y_plane_resource_id();
 
-  dc_layer->z_order = 1;
-  dc_layer->content_rect = gfx::ToNearestRect(quad->ya_tex_coord_rect());
-  dc_layer->quad_rect = quad->rect;
+  dc_layer->plane_z_order = 1;
+  dc_layer->display_rect = gfx::RectF(quad->rect);
+  dc_layer->resource_size_in_pixels = quad->ya_tex_size();
+  dc_layer->uv_rect =
+      gfx::ScaleRect(quad->ya_tex_coord_rect(),
+                     1.f / dc_layer->resource_size_in_pixels.width(),
+                     1.f / dc_layer->resource_size_in_pixels.height());
+
   // Quad rect is in quad content space so both quad to target, and target to
   // root transforms must be applied to it.
   gfx::Transform quad_to_root_transform(
@@ -191,17 +196,20 @@
 
 void FromTextureQuad(const TextureDrawQuad* quad,
                      const gfx::Transform& transform_to_root_target,
-                     DCLayerOverlayCandidate* dc_layer) {
+                     OverlayCandidate* dc_layer) {
   dc_layer->resource_id = quad->resource_id();
-  dc_layer->z_order = 1;
-  dc_layer->content_rect = gfx::Rect(quad->resource_size_in_pixels());
-  dc_layer->quad_rect = quad->rect;
+  dc_layer->plane_z_order = 1;
+  dc_layer->resource_size_in_pixels = quad->resource_size_in_pixels();
+  dc_layer->uv_rect =
+      gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
+  dc_layer->display_rect = gfx::RectF(quad->rect);
   // Quad rect is in quad content space so both quad to target, and target to
   // root transforms must be applied to it.
   gfx::Transform quad_to_root_transform;
   if (quad->y_flipped) {
     quad_to_root_transform.Scale(1.0, -1.0);
-    quad_to_root_transform.PostTranslate(0.0, dc_layer->content_rect.height());
+    quad_to_root_transform.PostTranslate(
+        0.0, dc_layer->resource_size_in_pixels.height());
   }
   quad_to_root_transform.PostConcat(
       quad->shared_quad_state->quad_to_target_transform);
@@ -413,15 +421,14 @@
 }
 
 // This function records the damage rect rect of the current frame.
-void RecordOverlayHistograms(
-    std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
-    bool has_occluding_surface_damage,
-    const gfx::Rect* damage_rect) {
+void RecordOverlayHistograms(OverlayCandidateList* dc_layer_overlays,
+                             bool has_occluding_surface_damage,
+                             const gfx::Rect* damage_rect) {
   // If an underlay is found, we record the damage rect of this frame as an
   // underlay.
   bool is_overlay = true;
   for (const auto& dc_layer : *dc_layer_overlays) {
-    if (dc_layer.z_order != 1) {
+    if (dc_layer.plane_z_order != 1) {
       is_overlay = false;
       break;
     }
@@ -464,13 +471,6 @@
 
 }  // namespace
 
-DCLayerOverlayCandidate::DCLayerOverlayCandidate() = default;
-DCLayerOverlayCandidate::DCLayerOverlayCandidate(
-    const DCLayerOverlayCandidate& other) = default;
-DCLayerOverlayCandidate& DCLayerOverlayCandidate::operator=(
-    const DCLayerOverlayCandidate& other) = default;
-DCLayerOverlayCandidate::~DCLayerOverlayCandidate() = default;
-
 DCLayerOverlayProcessor::DCLayerOverlayProcessor(
     const DebugRendererSettings* debug_settings,
     int allowed_yuv_overlay_count,
@@ -604,7 +604,7 @@
 }
 
 void DCLayerOverlayProcessor::InsertDebugBorderDrawQuad(
-    const std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
+    const OverlayCandidateList* dc_layer_overlays,
     AggregatedRenderPass* render_pass,
     const gfx::RectF& display_rect,
     gfx::Rect* damage_rect) {
@@ -627,13 +627,14 @@
 
   // Add debug borders for overlays/underlays
   for (const auto& dc_layer : *dc_layer_overlays) {
-    gfx::Rect overlay_rect = dc_layer.transform.MapRect(dc_layer.quad_rect);
+    gfx::Rect overlay_rect = gfx::ToEnclosingRect(
+        OverlayCandidate::DisplayRectInTargetSpace(dc_layer));
     if (dc_layer.clip_rect)
       overlay_rect.Intersect(*dc_layer.clip_rect);
 
     // Overlay:red, Underlay:blue.
     SkColor4f border_color =
-        dc_layer.z_order > 0 ? SkColors::kRed : SkColors::kBlue;
+        dc_layer.plane_z_order > 0 ? SkColors::kRed : SkColors::kBlue;
     auto it =
         quad_list.InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>(
             quad_list.begin(), 1u);
@@ -722,7 +723,7 @@
     AggregatedRenderPass* render_pass,
     gfx::Rect* damage_rect,
     SurfaceDamageRectList surface_damage_rect_list,
-    std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
+    OverlayCandidateList* dc_layer_overlays,
     bool is_video_capture_enabled,
     bool is_page_fullscreen_mode) {
   bool this_frame_has_occluding_damage_rect = false;
@@ -1043,12 +1044,12 @@
     QuadList::Iterator* new_it,
     size_t* new_index,
     gfx::Rect* damage_rect,
-    std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
+    OverlayCandidateList* dc_layer_overlays,
     bool is_page_fullscreen_mode) {
   // Record the result first before ProcessForOverlay().
   RecordDCLayerResult(DC_LAYER_SUCCESS, it);
 
-  DCLayerOverlayCandidate dc_layer;
+  OverlayCandidate dc_layer;
   dc_layer.is_video_fullscreen_letterboxing =
       is_page_fullscreen_mode
           ? IsFullScreenLetterboxing(it, render_pass->quad_list.end(),
@@ -1112,11 +1113,11 @@
     const QuadList::Iterator& it,
     size_t processed_overlay_count,
     gfx::Rect* damage_rect,
-    DCLayerOverlayCandidate* dc_layer) {
+    OverlayCandidate* dc_layer) {
   // Assign decreasing z-order so that underlays processed earlier, and hence
   // which are above the subsequent underlays, are placed above in the direct
   // composition visual tree.
-  dc_layer->z_order = -1 - processed_overlay_count;
+  dc_layer->plane_z_order = -1 - processed_overlay_count;
 
   // If the video is translucent and uses SrcOver blend mode, we can achieve the
   // same result as compositing with video on top if we replace video quad with
diff --git a/components/viz/service/display/dc_layer_overlay.h b/components/viz/service/display/dc_layer_overlay.h
index c05e0dd5..5e74d7f 100644
--- a/components/viz/service/display/dc_layer_overlay.h
+++ b/components/viz/service/display/dc_layer_overlay.h
@@ -12,6 +12,7 @@
 #include "base/threading/thread_checker.h"
 #include "components/viz/common/quads/aggregated_render_pass.h"
 #include "components/viz/service/display/aggregated_frame.h"
+#include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/viz_service_export.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -24,54 +25,6 @@
 struct DebugRendererSettings;
 class DisplayResourceProvider;
 
-// TODO(weiliangc): Eventually fold this into OverlayProcessorWin and
-// OverlayCandidate class.
-// Holds all information necessary to construct a direct composition overlay
-// from a DrawQuad.
-class VIZ_SERVICE_EXPORT DCLayerOverlayCandidate {
- public:
-  DCLayerOverlayCandidate();
-  DCLayerOverlayCandidate(const DCLayerOverlayCandidate& other);
-  DCLayerOverlayCandidate& operator=(const DCLayerOverlayCandidate& other);
-  ~DCLayerOverlayCandidate();
-
-  // Resource id for a single NV12 image or a swap chain image. See
-  // DCLayerOverlayImage for details.
-  ResourceId resource_id = kInvalidResourceId;
-
-  // Mailbox corresponding to |resource_id|. This is populated in SkiaRenderer
-  // for accessing the textures on the GPU thread.
-  gpu::Mailbox mailbox;
-
-  // Stacking order relative to backbuffer which has z-order 0.
-  int z_order = 1;
-
-  // What part of the content to display in pixels.
-  gfx::Rect content_rect;
-
-  // Bounds of the overlay in pre-transform space.
-  gfx::Rect quad_rect;
-
-  // 2D flattened transform that maps |quad_rect| to root target space,
-  // after applying the |quad_rect.origin()| as an offset.
-  gfx::Transform transform;
-
-  // If |clip_rect| is present, then clip to it in root target space.
-  absl::optional<gfx::Rect> clip_rect;
-
-  // This is the color-space the texture should be displayed as. If invalid,
-  // then the default for the texture should be used. For YUV textures, that's
-  // normally BT.709.
-  gfx::ColorSpace color_space;
-
-  gfx::ProtectedVideoType protected_video_type =
-      gfx::ProtectedVideoType::kClear;
-
-  gfx::HDRMetadata hdr_metadata;
-
-  bool is_video_fullscreen_letterboxing = false;
-};
-
 class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor final
     : public gl::DirectCompositionOverlayCapsObserver {
  public:
@@ -97,7 +50,7 @@
                        AggregatedRenderPass* render_pass,
                        gfx::Rect* damage_rect,
                        SurfaceDamageRectList surface_damage_rect_list,
-                       std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
+                       OverlayCandidateList* dc_layer_overlays,
                        bool is_video_capture_enabled,
                        bool is_page_fullscreen_mode);
   void ClearOverlayState();
@@ -121,17 +74,16 @@
 
   // UpdateDCLayerOverlays() adds the quad at |it| to the overlay list
   // |dc_layer_overlays|.
-  void UpdateDCLayerOverlays(
-      const gfx::RectF& display_rect,
-      AggregatedRenderPass* render_pass,
-      const QuadList::Iterator& it,
-      const gfx::Rect& quad_rectangle_in_root_space,
-      bool is_overlay,
-      QuadList::Iterator* new_it,
-      size_t* new_index,
-      gfx::Rect* damage_rect,
-      std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
-      bool is_page_fullscreen_mode);
+  void UpdateDCLayerOverlays(const gfx::RectF& display_rect,
+                             AggregatedRenderPass* render_pass,
+                             const QuadList::Iterator& it,
+                             const gfx::Rect& quad_rectangle_in_root_space,
+                             bool is_overlay,
+                             QuadList::Iterator* new_it,
+                             size_t* new_index,
+                             gfx::Rect* damage_rect,
+                             OverlayCandidateList* dc_layer_overlays,
+                             bool is_page_fullscreen_mode);
 
   // Returns an iterator to the element after |it|.
   QuadList::Iterator ProcessForOverlay(const gfx::RectF& display_rect,
@@ -143,18 +95,17 @@
                           const QuadList::Iterator& it,
                           size_t processed_overlay_count,
                           gfx::Rect* damage_rect,
-                          DCLayerOverlayCandidate* dc_layer);
+                          OverlayCandidate* dc_layer);
 
   void UpdateRootDamageRect(const gfx::RectF& display_rect,
                             gfx::Rect* damage_rect);
 
   void RemoveOverlayDamageRect(const QuadList::Iterator& it);
 
-  void InsertDebugBorderDrawQuad(
-      const std::vector<DCLayerOverlayCandidate>* dc_layer_overlays,
-      AggregatedRenderPass* render_pass,
-      const gfx::RectF& display_rect,
-      gfx::Rect* damage_rect);
+  void InsertDebugBorderDrawQuad(const OverlayCandidateList* dc_layer_overlays,
+                                 AggregatedRenderPass* render_pass,
+                                 const gfx::RectF& display_rect,
+                                 gfx::Rect* damage_rect);
   bool IsPreviousFrameUnderlayRect(const gfx::Rect& quad_rectangle,
                                    size_t index);
 
diff --git a/components/viz/service/display/overlay_candidate.h b/components/viz/service/display/overlay_candidate.h
index 8fd734b1..e55a000b 100644
--- a/components/viz/service/display/overlay_candidate.h
+++ b/components/viz/service/display/overlay_candidate.h
@@ -26,6 +26,7 @@
 #include "ui/gfx/hdr_metadata.h"
 #include "ui/gfx/overlay_priority_hint.h"
 #include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/video_types.h"
 
 namespace gfx {
 class Rect;
@@ -131,6 +132,13 @@
   // Mailbox from resource_id. It is used by SkiaRenderer.
   gpu::Mailbox mailbox;
 
+#if BUILDFLAG(IS_WIN)
+  gfx::ProtectedVideoType protected_video_type =
+      gfx::ProtectedVideoType::kClear;
+
+  bool is_video_fullscreen_letterboxing = false;
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
   // For candidates from TextureDrawQuads with is_stream_video set to true, this
   // records whether the quad is marked as being backed by a SurfaceTexture or
diff --git a/components/viz/service/display/overlay_dc_unittest.cc b/components/viz/service/display/overlay_dc_unittest.cc
index a3ff967..994a3a8 100644
--- a/components/viz/service/display/overlay_dc_unittest.cc
+++ b/components/viz/service/display/overlay_dc_unittest.cc
@@ -29,6 +29,7 @@
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/output_surface_client.h"
 #include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/display/overlay_processor_win.h"
 #include "components/viz/test/fake_skia_output_surface.h"
 #include "components/viz/test/test_context_provider.h"
@@ -262,7 +263,7 @@
         video_quad->rect = gfx::Rect(0, 0, 10, 10) + video_rect_offset;
         video_quad->visible_rect = gfx::Rect(0, 0, 10, 10) + video_rect_offset;
 
-        std::vector<DCLayerOverlayCandidate> dc_layer_list;
+        OverlayCandidateList dc_layer_list;
         OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
         OverlayProcessorInterface::FilterOperationsMap
             render_pass_backdrop_filters;
@@ -321,8 +322,7 @@
     auto* first_video_quad = CreateFullscreenCandidateYUVVideoQuad(
         resource_provider_.get(), child_resource_provider_.get(),
         child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
-    // Set the protected video flag will force DCLayerOverlayCandidate to use hw
-    // overlay
+    // Set the protected video flag will force the quad to use hw overlay
     first_video_quad->protected_video_type =
         gfx::ProtectedVideoType::kHardwareProtected;
 
@@ -332,14 +332,13 @@
     auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad(
         resource_provider_.get(), child_resource_provider_.get(),
         child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
-    // Set the protected video flag will force DCLayerOverlayCandidate to use hw
-    // overlay
+    // Set the protected video flag will force the quad to use hw overlay
     second_video_quad->protected_video_type =
         gfx::ProtectedVideoType::kHardwareProtected;
     second_video_quad->rect.set_origin(gfx::Point(2, 2));
     second_video_quad->visible_rect.set_origin(gfx::Point(2, 2));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -355,8 +354,8 @@
         &damage_rect_, &content_bounds_);
 
     EXPECT_EQ(2U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.front().z_order);
-    EXPECT_EQ(-2, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.front().plane_z_order);
+    EXPECT_EQ(-2, dc_layer_list.back().plane_z_order);
     // Entire underlay rect must be redrawn.
     EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
   }
@@ -374,8 +373,7 @@
     auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
         resource_provider_.get(), child_resource_provider_.get(),
         child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
-    // Set the protected video flag will force DCLayerOverlayCandidate to use hw
-    // overlay
+    // Set the protected video flag will force the quad to use hw overlay
     video_quad->protected_video_type =
         gfx::ProtectedVideoType::kHardwareProtected;
 
@@ -390,7 +388,7 @@
     second_video_quad->rect.set_origin(gfx::Point(2, 2));
     second_video_quad->visible_rect.set_origin(gfx::Point(2, 2));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -406,8 +404,8 @@
         &damage_rect_, &content_bounds_);
 
     EXPECT_EQ(2U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.front().z_order);
-    EXPECT_EQ(-2, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.front().plane_z_order);
+    EXPECT_EQ(-2, dc_layer_list.back().plane_z_order);
 
     // The underlay rectangle is the same, so the damage for first video quad is
     // contained within the combined occluding rects for this and the last
@@ -440,7 +438,7 @@
     video_quad->rect = gfx::Rect(0, 0, 200, 200);
     video_quad->visible_rect = video_quad->rect;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     // Damage rect fully outside video quad
@@ -456,7 +454,7 @@
         std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
         &damage_rect_, &content_bounds_);
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
     // All rects must be redrawn at the first frame.
     EXPECT_EQ(gfx::Rect(0, 0, 230, 230), damage_rect_);
   }
@@ -483,7 +481,7 @@
     video_quad->rect = gfx::Rect(0, 0, 200, 200);
     video_quad->visible_rect = video_quad->rect;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     // Damage rect fully outside video quad
@@ -499,7 +497,7 @@
         std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
         &damage_rect_, &content_bounds_);
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
     // Only the non-overlay damaged rect need to be drawn by the gl compositor
     EXPECT_EQ(gfx::Rect(210, 210, 20, 20), damage_rect_);
   }
@@ -514,7 +512,7 @@
         resource_provider_.get(), child_resource_provider_.get(),
         child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -528,7 +526,7 @@
         std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
         &damage_rect_, &content_bounds_);
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(1, dc_layer_list.back().z_order);
+    EXPECT_EQ(1, dc_layer_list.back().plane_z_order);
     // Damage rect should be unchanged on initial frame because of resize, but
     // should be empty on the second frame because everything was put in a
     // layer.
@@ -560,7 +558,7 @@
     // Clipped rect shouldn't be overlapped by clipped opaque quad rect.
     shared_state->clip_rect = gfx::Rect(0, 0, 100, 3);
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     AggregatedRenderPassList pass_list;
@@ -577,7 +575,7 @@
     EXPECT_EQ(1U, dc_layer_list.size());
     // Because of clip rects the overlay isn't occluded and shouldn't be an
     // underlay.
-    EXPECT_EQ(1, dc_layer_list.back().z_order);
+    EXPECT_EQ(1, dc_layer_list.back().plane_z_order);
     EXPECT_EQ(gfx::Rect(0, 0, 100, 3), dc_layer_list.back().clip_rect);
     if (i == 1) {
       // The damage rect should only contain contents that aren't in the
@@ -599,7 +597,7 @@
         child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
     pass->shared_quad_state_list.back()->opacity = 0.5f;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -613,7 +611,7 @@
         std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
         &damage_rect_, &content_bounds_);
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(1, dc_layer_list.back().z_order);
+    EXPECT_EQ(1, dc_layer_list.back().plane_z_order);
     // Quad isn't opaque, so underlying damage must remain the same.
     EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
   }
@@ -633,7 +631,7 @@
         resource_provider_.get(), child_resource_provider_.get(),
         child_provider_.get(), shared_state, pass.get());
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     AggregatedRenderPassList pass_list;
@@ -654,7 +652,7 @@
         std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
         &damage_rect_, &content_bounds_);
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
     // Damage rect should be unchanged on initial frame, but should be reduced
     // to the size of quad on top, and empty on the third frame.
     if (i == 0)
@@ -684,7 +682,7 @@
     pass->shared_quad_state_list.back()->mask_filter_info =
         gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(0.f, 0.f, 20.f, 30.f), 5.f));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 256, 256);
@@ -706,7 +704,7 @@
     // The video should be forced to an underlay mode, even there is nothing on
     // top.
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
 
     // Check whether there is a replaced quad in the quad list.
     EXPECT_EQ(1U, root_pass->quad_list.size());
@@ -742,7 +740,7 @@
     pass->shared_quad_state_list.back()->mask_filter_info =
         gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(0.f, 0.f, 20.f, 30.f), 5.f));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 256, 256);
@@ -763,7 +761,7 @@
 
     // still in an underlay mode.
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
 
     // Check whether the red quad on top and the replacedment of the YUV quad
     // are still in the render pass.
@@ -800,7 +798,7 @@
     pass->shared_quad_state_list.back()->mask_filter_info =
         gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(0.f, 0.f, 20.f, 30.f), 5.f));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 256, 256);
@@ -821,7 +819,7 @@
 
     // still in an underlay mode.
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(-1, dc_layer_list.back().z_order);
+    EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
 
     // Check whether the red quad on top and the replacedment of the YUV quad
     // are still in the render pass.
@@ -867,7 +865,7 @@
     second_video_quad->visible_rect = second_rect;
     pass->shared_quad_state_list.back()->overlay_damage_index = 2;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 220, 220);
@@ -910,7 +908,7 @@
     AggregatedRenderPassList pass_list;
     pass_list.push_back(std::move(pass));
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     SurfaceDamageRectList surface_damage_rect_list;
@@ -933,7 +931,7 @@
         &damage_rect_, &content_bounds_);
 
     EXPECT_EQ(1U, dc_layer_list.size());
-    EXPECT_EQ(1, dc_layer_list.back().z_order);
+    EXPECT_EQ(1, dc_layer_list.back().plane_z_order);
     EXPECT_EQ(damage_rect_, expected_damage);
 
     Mock::VerifyAndClearExpectations(output_surface_.get());
@@ -948,7 +946,7 @@
     quad->SetNew(pass->CreateAndAppendSharedQuadState(), damage_rect_,
                  damage_rect_, SkColors::kRed, false);
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
 
@@ -1029,7 +1027,7 @@
   // 100, 100).
   pass->output_rect = gfx::Rect(0, 0, 512, 512);
 
-  std::vector<DCLayerOverlayCandidate> dc_layer_list;
+  OverlayCandidateList dc_layer_list;
   OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
   OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
   render_pass_filters[filter_render_pass_id] = &blur_filter;
@@ -1050,7 +1048,7 @@
   EXPECT_EQ(1U, dc_layer_list.size());
   // Make sure the video is in an underlay mode if the overlay quad intersects
   // with (rpdq->rect + MaximumPixelMovement()).
-  EXPECT_EQ(-1, dc_layer_list.back().z_order);
+  EXPECT_EQ(-1, dc_layer_list.back().plane_z_order);
   EXPECT_EQ(gfx::Rect(0, 0, 360, 360), damage_rect_);
 }
 
@@ -1099,7 +1097,7 @@
   // 100, 100).
   pass->output_rect = gfx::Rect(0, 0, 512, 512);
 
-  std::vector<DCLayerOverlayCandidate> dc_layer_list;
+  OverlayCandidateList dc_layer_list;
   OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
   OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
   render_pass_backdrop_filters[backdrop_filter_render_pass_id] =
@@ -1145,7 +1143,7 @@
     video_quad->visible_rect = rect;
     pass->shared_quad_state_list.back()->overlay_damage_index = 1;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 256, 256);
@@ -1183,7 +1181,7 @@
     video_quad->visible_rect = rect;
     pass->shared_quad_state_list.back()->overlay_damage_index = 0;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    OverlayCandidateList dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     damage_rect_ = gfx::Rect(0, 0, 256, 256);
@@ -1252,7 +1250,7 @@
     video_quad->rect = gfx::Rect(kVideoRect);
     video_quad->visible_rect = video_quad->rect;
 
-    std::vector<DCLayerOverlayCandidate> dc_layer_list;
+    std::vector<OverlayCandidate> dc_layer_list;
     OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
     OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
     AggregatedRenderPassList pass_list;
@@ -1268,11 +1266,14 @@
     LOG(INFO) << damage_rect_.ToString();
 
     EXPECT_EQ(dc_layer_list.size(), 1u);
-    EXPECT_EQ(dc_layer_list[0].transform, kRenderPassToRootTransform);
+    EXPECT_TRUE(
+        absl::holds_alternative<gfx::Transform>(dc_layer_list[0].transform));
+    EXPECT_EQ(absl::get<gfx::Transform>(dc_layer_list[0].transform),
+              kRenderPassToRootTransform);
     if (is_overlay) {
-      EXPECT_GT(dc_layer_list[0].z_order, 0);
+      EXPECT_GT(dc_layer_list[0].plane_z_order, 0);
     } else {
-      EXPECT_LT(dc_layer_list[0].z_order, 0);
+      EXPECT_LT(dc_layer_list[0].plane_z_order, 0);
     }
 
     if (frame == 0) {
diff --git a/components/viz/service/display/overlay_processor_interface.h b/components/viz/service/display/overlay_processor_interface.h
index 41ccab8..0c5b20a7 100644
--- a/components/viz/service/display/overlay_processor_interface.h
+++ b/components/viz/service/display/overlay_processor_interface.h
@@ -52,9 +52,6 @@
 #if BUILDFLAG(IS_APPLE)
   using PlatformOverlayCandidate = CALayerOverlay;
   using CandidateList = CALayerOverlayList;
-#elif BUILDFLAG(IS_WIN)
-  using PlatformOverlayCandidate = DCLayerOverlayCandidate;
-  using CandidateList = std::vector<DCLayerOverlayCandidate>;
 #else
   // Default.
   using PlatformOverlayCandidate = OverlayCandidate;
@@ -66,8 +63,7 @@
 
   virtual bool DisableSplittingQuads() const;
 
-  // Used by Window's DCLayerOverlayCandidate system and
-  // OverlayProcessorUsingStrategy.
+  // Used by DCLayerOverlayProcessor and OverlayProcessorUsingStrategy.
   static void RecordOverlayDamageRectHistograms(
       bool is_overlay,
       bool has_occluding_surface_damage,
diff --git a/components/viz/service/display/overlay_processor_on_gpu.h b/components/viz/service/display/overlay_processor_on_gpu.h
index 3be8131..2dd7527 100644
--- a/components/viz/service/display/overlay_processor_on_gpu.h
+++ b/components/viz/service/display/overlay_processor_on_gpu.h
@@ -34,8 +34,6 @@
  public:
 #if BUILDFLAG(IS_APPLE)
   using CandidateList = CALayerOverlayList;
-#elif BUILDFLAG(IS_WIN)
-  using CandidateList = std::vector<DCLayerOverlayCandidate>;
 #else
   // Default.
   using CandidateList = OverlayCandidateList;
diff --git a/components/viz/service/display/overlay_processor_win.h b/components/viz/service/display/overlay_processor_win.h
index bf6c971..65f4fd2 100644
--- a/components/viz/service/display/overlay_processor_win.h
+++ b/components/viz/service/display/overlay_processor_win.h
@@ -26,8 +26,6 @@
 class VIZ_SERVICE_EXPORT OverlayProcessorWin
     : public OverlayProcessorInterface {
  public:
-  using CandidateList = std::vector<DCLayerOverlayCandidate>;
-
   OverlayProcessorWin(
       OutputSurface* output_surface,
       std::unique_ptr<DCLayerOverlayProcessor> dc_layer_overlay_processor);
@@ -65,7 +63,7 @@
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
       OutputSurfaceOverlayPlane* output_surface_plane,
-      CandidateList* overlay_candidates,
+      OverlayCandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) override;
 
diff --git a/components/viz/service/display/skia_output_surface.h b/components/viz/service/display/skia_output_surface.h
index 880530a..a29f5710a 100644
--- a/components/viz/service/display/skia_output_surface.h
+++ b/components/viz/service/display/skia_output_surface.h
@@ -55,8 +55,6 @@
   using OverlayList = std::vector<OverlayCandidate>;
 #elif BUILDFLAG(IS_APPLE)
   using OverlayList = CALayerOverlayList;
-#elif BUILDFLAG(IS_WIN)
-  using OverlayList = std::vector<DCLayerOverlayCandidate>;
 #elif BUILDFLAG(IS_OZONE)
   using OverlayList = std::vector<OverlayCandidate>;
 #else
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 3e954bc..875f183 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -2662,11 +2662,8 @@
   DCHECK(output_surface_->capabilities().supports_surfaceless);
 #endif
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
-  // CrOS and Android SurfaceControl use this code path. Android classic has
-  // switched over to OverlayProcessor.
-  // TODO(weiliangc): Remove this when CrOS and Android SurfaceControl switch
-  // to OverlayProcessor as well.
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
+  // CrOS, Android SurfaceControl, and Windows use this code path.
   for (auto& overlay : current_frame()->overlay_list) {
     if (overlay.is_root_render_pass) {
       continue;
@@ -2683,26 +2680,6 @@
     overlay.mailbox = lock.mailbox();
     DCHECK(!overlay.mailbox.IsZero());
   }
-#elif BUILDFLAG(IS_WIN)
-  for (auto& dc_layer_overlay : current_frame()->overlay_list) {
-    ResourceId resource_id = dc_layer_overlay.resource_id;
-    if (resource_id == kInvalidResourceId) {
-      continue;
-    }
-
-    // Resources will be unlocked after the next SwapBuffers() is completed.
-    locks.emplace_back(resource_provider(), resource_id);
-    auto& lock = locks.back();
-
-    // Sync tokens ensure the texture to be overlaid is available before
-    // scheduling it for display.
-    if (lock.sync_token().HasData()) {
-      sync_tokens.push_back(lock.sync_token());
-    }
-
-    dc_layer_overlay.mailbox = lock.mailbox();
-    DCHECK(!dc_layer_overlay.mailbox.IsZero());
-  }
 #elif BUILDFLAG(IS_APPLE)
   for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
     if (ca_layer_overlay.rpdq) {
@@ -2767,12 +2744,12 @@
     overlay.mailbox = lock.mailbox();
     DCHECK(!overlay.mailbox.IsZero());
   }
-#else   // BUILDFLAG(IS_ANDROID)
+#else
   // For platforms that don't support overlays, the
   // current_frame()->overlay_list should be empty, and this code should not be
   // reached.
   NOTREACHED();
-#endif  // BUILDFLAG(IS_ANDROID)
+#endif
 
   DCHECK(!current_gpu_commands_completed_fence_->was_set());
   DCHECK(!current_release_fence_->was_set());
diff --git a/components/viz/service/display_embedder/output_presenter.h b/components/viz/service/display_embedder/output_presenter.h
index 2191e3c..a19ec5e 100644
--- a/components/viz/service/display_embedder/output_presenter.h
+++ b/components/viz/service/display_embedder/output_presenter.h
@@ -130,12 +130,8 @@
       const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
       Image* image,
       bool is_submitted) = 0;
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_OZONE)
-  using OverlayPlaneCandidate = OverlayCandidate;
-#elif BUILDFLAG(IS_APPLE)
+#if BUILDFLAG(IS_APPLE)
   using OverlayPlaneCandidate = CALayerOverlay;
-#elif BUILDFLAG(IS_WIN)
-  using OverlayPlaneCandidate = DCLayerOverlayCandidate;
 #else
   // Default.
   using OverlayPlaneCandidate = OverlayCandidate;
diff --git a/components/viz/service/display_embedder/output_presenter_gl.cc b/components/viz/service/display_embedder/output_presenter_gl.cc
index 786ed061..e7c37b93 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -312,8 +312,8 @@
     ScopedOverlayAccess* access,
     std::unique_ptr<gfx::GpuFence> acquire_fence) {
   // Note that |overlay_plane_candidate| has different types on different
-  // platforms. On Android and Ozone it is an OverlayCandidate, on Windows it is
-  // a DCLayerOverlayCandidate, and on macOS it is a CALayeroverlay.
+  // platforms. On Android, Ozone, and Windows, it is an OverlayCandidate and on
+  // macOS it is a CALayeroverlay.
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_OZONE)
 #if BUILDFLAG(IS_OZONE)
   // TODO(crbug.com/1366808): Add ScopedOverlayAccess::GetOverlayImage() that
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index 444fed75..80407fbe 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -35,6 +35,7 @@
 #include "third_party/skia/include/gpu/GrDirectContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
 #include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gl/dc_layer_overlay_params.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -214,15 +215,22 @@
 
     auto params = std::make_unique<gl::DCLayerOverlayParams>();
     params->overlay_image = std::move(overlay_image);
-    params->z_order = dc_layer.z_order;
-    params->content_rect = dc_layer.content_rect;
-    params->quad_rect = dc_layer.quad_rect;
-    DCHECK(dc_layer.transform.IsFlat());
-    params->transform = dc_layer.transform;
+    params->z_order = dc_layer.plane_z_order;
+
+    // SwapChainPresenter uses the size of the overlay's resource in pixels to
+    // calculate its swap chain size. `uv_rect` maps the portion of
+    // `resource_size_in_pixels` that will be displayed.
+    params->content_rect = gfx::ToNearestRect(gfx::ScaleRect(
+        dc_layer.uv_rect, dc_layer.resource_size_in_pixels.width(),
+        dc_layer.resource_size_in_pixels.height()));
+
+    params->quad_rect = gfx::ToEnclosingRect(dc_layer.display_rect);
+    DCHECK(absl::holds_alternative<gfx::Transform>(dc_layer.transform));
+    params->transform = absl::get<gfx::Transform>(dc_layer.transform);
     params->clip_rect = dc_layer.clip_rect;
     params->protected_video_type = dc_layer.protected_video_type;
     params->color_space = dc_layer.color_space;
-    params->hdr_metadata = dc_layer.hdr_metadata;
+    params->hdr_metadata = dc_layer.hdr_metadata.value_or(gfx::HDRMetadata());
     params->is_video_fullscreen_letterboxing =
         dc_layer.is_video_fullscreen_letterboxing;
 
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index ee13869..b2f0884cf 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -16,6 +16,7 @@
 #include "base/notreached.h"
 #include "base/task/bind_post_task.h"
 #include "base/threading/thread_checker.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/blit_request.h"
@@ -54,10 +55,12 @@
 #include "skia/ext/rgba_to_yuva.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/libyuv/include/libyuv/planar_functions.h"
+#include "third_party/skia/include/core/SkAlphaType.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkColorType.h"
 #include "third_party/skia/include/core/SkDeferredDisplayList.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkPromiseImageTexture.h"
@@ -1140,25 +1143,19 @@
   }
 
   // Create a destination for the scaled & clipped result:
-  auto intermediate_representation = CreateSharedImageRepresentationSkia(
-      ResourceFormat::RGBA_8888, intermediate_dst_size, color_space);
-  if (!intermediate_representation) {
-    DVLOG(1) << "failed to create shared image representation for the "
-                "intermediate surface";
+  auto intermediate_surface = SkSurface::MakeRenderTarget(
+      gr_context(), skgpu::Budgeted::kYes,
+      SkImageInfo::Make(gfx::SizeToSkISize(intermediate_dst_size),
+                        SkColorType::kRGBA_8888_SkColorType,
+                        SkAlphaType::kPremul_SkAlphaType,
+                        color_space.ToSkColorSpace()));
+
+  if (!intermediate_surface) {
+    DVLOG(1) << "failed to create surface for the intermediate texture";
     // Send empty result.
     return;
   }
 
-  SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
-  std::vector<GrBackendSemaphore> begin_semaphores;
-  std::vector<GrBackendSemaphore> end_semaphores;
-
-  auto intermediate_scoped_write =
-      intermediate_representation->BeginScopedWriteAccess(
-          /*final_msaa_count=*/1, surface_props, &begin_semaphores,
-          &end_semaphores,
-          gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
-
   absl::optional<SkVector> scaling;
   if (request->is_scaled()) {
     scaling = SkVector::Make(static_cast<SkScalar>(request->scale_to().x()) /
@@ -1167,20 +1164,18 @@
                                  request->scale_from().y());
   }
 
-  intermediate_scoped_write->surface()->wait(begin_semaphores.size(),
-                                             begin_semaphores.data());
-
   RenderSurface(surface, src_rect, scaling,
                 is_downscale_or_identity_in_both_dimensions,
-                intermediate_scoped_write->surface());
+                intermediate_surface.get());
 
   if (request->has_blit_request()) {
-    BlendBitmapOverlays(intermediate_scoped_write->surface()->getCanvas(),
+    BlendBitmapOverlays(intermediate_surface->getCanvas(),
                         request->blit_request());
   }
 
-  auto intermediate_image =
-      intermediate_scoped_write->surface()->makeImageSnapshot();
+  intermediate_surface->flush();
+
+  auto intermediate_image = intermediate_surface->makeImageSnapshot();
   if (!intermediate_image) {
     DLOG(ERROR) << "failed to retrieve `intermediate_image`.";
     return;
@@ -1281,16 +1276,6 @@
     }
   }
 
-  should_submit |= !end_semaphores.empty();
-
-  intermediate_representation->SetCleared();
-  if (!FlushSurface(intermediate_scoped_write->surface(), end_semaphores,
-                    intermediate_scoped_write->TakeEndState())) {
-    // TODO(penghuang): handle vulkan device lost.
-    FailedSkiaFlush("CopyOutputNV12 dest_surface->flush()");
-    return;
-  }
-
   if (should_submit && !gr_context()->submit()) {
     DLOG(ERROR) << "CopyOutputNV12 gr_context->submit() failed";
     return;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 8f589a8..2300a4e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -16,6 +16,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/threading/thread_checker.h"
+#include "base/time/time.h"
 #include "base/types/pass_key.h"
 #include "build/build_config.h"
 #include "components/viz/common/display/renderer_settings.h"
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index 42846c3f..168ad44 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -672,10 +672,13 @@
 // static
 UiaRaiseActiveTextPositionChangedEventFunction
 BrowserAccessibilityManagerWin::GetUiaActiveTextPositionChangedEventFunction() {
-  // This API is only supported from Win8.1 onwards. On older platforms (such as
-  // Windows 7), we will return nullptr for the querying result for the address
-  // of the method "UiaRaiseActiveTextPositionChangedEvent" in
-  // uiautomationcore.dll.
+  // MSDN
+  // (https://learn.microsoft.com/en-us/windows/win32/api/uiautomationcoreapi/nf-uiautomationcoreapi-uiaraiseactivetextpositionchangedevent)
+  // claims this API is fully supported from Win8.1 ownwards, but older
+  // versions of this dll on Win10 (e.g., Windows-10-15063 aka. version 1703)
+  // don't seem to have the API, which makes chrome.dll fail to load, if
+  // ::UiaRaiseActiveTextPositionChangedEvent is called directly. On these older
+  // versions of Win10, we will return nullptr.
   return reinterpret_cast<UiaRaiseActiveTextPositionChangedEventFunction>(
       ::GetProcAddress(::GetModuleHandle(L"uiautomationcore.dll"),
                        "UiaRaiseActiveTextPositionChangedEvent"));
diff --git a/content/browser/attribution_reporting/PRESUBMIT.py b/content/browser/attribution_reporting/PRESUBMIT.py
deleted file mode 100644
index ff205c0..0000000
--- a/content/browser/attribution_reporting/PRESUBMIT.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2020 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Presubmit script for the content/browser/attribution_reporting directory.
-
-See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-USE_PYTHON3 = True
-
-def CheckAttributionStorageSchemaModification(input_api, output_api):
-  """ Checks the kCurrentVersionNumber is modified when necessary.
-
-  Whenever any of the following files is changed:
-    - attribution_storage_sql.cc
-    - attribution_storage_sql_migrations.cc
-    - rate_limit_table.cc
-  and kCurrentVersionNumber stays intact, this check returns a
-  presubmit warning to make sure the value is updated if necessary.
-  """
-
-  database_files_changed = False
-  database_version_changed = False
-
-  for affected_file in input_api.AffectedFiles():
-    basename = input_api.basename(affected_file.LocalPath())
-
-    if (basename == 'attribution_storage_sql_migrations.cc' or
-        basename == 'attribution_storage_sql.cc' or
-        basename == 'rate_limit_table.cc'):
-      database_files_changed = True
-
-    if basename == 'attribution_storage_sql.cc':
-      for (_, line) in affected_file.ChangedContents():
-        if 'const int AttributionStorageSql::kCurrentVersionNumber' in line:
-          database_version_changed = True
-          break
-
-  out = []
-  if database_files_changed and not database_version_changed:
-    out.append(output_api.PresubmitPromptWarning(
-        'Please make sure that the conversions database is properly versioned '
-        'and migrated when making changes to schema or table contents. '
-        'kCurrentVersionNumber in attribution_storage_sql.cc '
-        'must be updated when doing a migration.'))
-  return out
-
-def CheckChangeOnUpload(input_api, output_api):
-  return CheckAttributionStorageSchemaModification(input_api, output_api)
diff --git a/content/browser/attribution_reporting/attribution_interop_parser.cc b/content/browser/attribution_reporting/attribution_interop_parser.cc
index 59fed289..4d06351 100644
--- a/content/browser/attribution_reporting/attribution_interop_parser.cc
+++ b/content/browser/attribution_reporting/attribution_interop_parser.cc
@@ -34,10 +34,6 @@
   base::expected<base::Value::Dict, std::string> SimulatorInputFromInteropInput(
       base::Value::Dict) &&;
 
-  // Converts simulator output to interop test output format.
-  base::expected<base::Value::Dict, std::string>
-  InteropOutputFromSimulatorOutput(base::Value::Dict) &&;
-
   [[nodiscard]] std::string ParseConfig(const base::Value::Dict&,
                                         AttributionConfig&,
                                         bool required) &&;
@@ -76,12 +72,6 @@
 
   base::Value::List ParseEvents(base::Value::Dict& dict, base::StringPiece key);
 
-  base::Value::List ParseEventLevelReports(base::Value::Dict& output);
-
-  base::Value::List ParseAggregatableReports(base::Value::Dict& output);
-
-  base::Value::List ParseVerboseDebugReports(base::Value::Dict& output);
-
   // Returns true if `key` is present in `dict` and the integer is parsed
   // successfully.
   template <typename T>
@@ -381,159 +371,6 @@
   return result;
 }
 
-base::Value::List AttributionInteropParser::ParseEventLevelReports(
-    base::Value::Dict& output) {
-  static constexpr char kKey[] = "event_level_reports";
-
-  base::Value::List event_level_results;
-
-  base::Value* value = output.Find(kKey);
-  if (!value) {
-    return event_level_results;
-  }
-
-  auto context = PushContext(kKey);
-  ParseList(output.Find(kKey), [&](base::Value value) {
-    if (!EnsureDictionary(&value)) {
-      return;
-    }
-
-    base::Value::Dict result;
-
-    base::Value::Dict& value_dict = value.GetDict();
-    MoveValue(value_dict, "report", result, "payload");
-    MoveValue(value_dict, "report_url", result);
-    MoveValue(value_dict, "intended_report_time", result, "report_time");
-
-    if (has_error()) {
-      return;
-    }
-
-    event_level_results.Append(std::move(result));
-  });
-
-  return event_level_results;
-}
-
-base::Value::List AttributionInteropParser::ParseAggregatableReports(
-    base::Value::Dict& output) {
-  static constexpr char kKey[] = "aggregatable_reports";
-
-  base::Value::List aggregatable_results;
-
-  base::Value* value = output.Find(kKey);
-  if (!value) {
-    return aggregatable_results;
-  }
-
-  auto context = PushContext(kKey);
-  ParseList(output.Find(kKey), [&](base::Value value) {
-    if (!EnsureDictionary(&value)) {
-      return;
-    }
-
-    base::Value::Dict result;
-
-    base::Value::Dict& value_dict = value.GetDict();
-    MoveValue(value_dict, "report_url", result);
-    MoveValue(value_dict, "intended_report_time", result, "report_time");
-
-    static constexpr char kKeyTestInfo[] = "test_info";
-    base::Value* test_info;
-    {
-      auto test_info_context = PushContext(kKeyTestInfo);
-      test_info = value_dict.Find(kKeyTestInfo);
-      if (!EnsureDictionary(test_info)) {
-        return;
-      }
-    }
-
-    static constexpr char kKeyReport[] = "report";
-    {
-      auto report_context = PushContext(kKeyReport);
-      base::Value* report = value_dict.Find(kKeyReport);
-      if (!EnsureDictionary(report)) {
-        return;
-      }
-
-      MoveDictValues(test_info->GetDict(), report->GetDict());
-    }
-
-    MoveValue(value_dict, "report", result, "payload");
-
-    if (has_error()) {
-      return;
-    }
-
-    aggregatable_results.Append(std::move(result));
-  });
-
-  return aggregatable_results;
-}
-
-base::Value::List AttributionInteropParser::ParseVerboseDebugReports(
-    base::Value::Dict& output) {
-  static constexpr char kKey[] = "verbose_debug_reports";
-
-  base::Value::List reports;
-
-  base::Value* value = output.Find(kKey);
-  if (!value) {
-    return reports;
-  }
-
-  auto context = PushContext(kKey);
-  ParseList(output.Find(kKey), [&](base::Value value) {
-    if (!EnsureDictionary(&value)) {
-      return;
-    }
-
-    base::Value::Dict report;
-
-    base::Value::Dict& value_dict = value.GetDict();
-    MoveValue(value_dict, "report", report, "payload");
-    MoveValue(value_dict, "report_url", report);
-    MoveValue(value_dict, "report_time", report);
-
-    if (has_error()) {
-      return;
-    }
-
-    reports.Append(std::move(report));
-  });
-
-  return reports;
-}
-
-base::expected<base::Value::Dict, std::string>
-AttributionInteropParser::InteropOutputFromSimulatorOutput(
-    base::Value::Dict output) && {
-  base::Value::List event_level_results = ParseEventLevelReports(output);
-
-  base::Value::List aggregatable_results = ParseAggregatableReports(output);
-
-  base::Value::List verbose_debug_reports = ParseVerboseDebugReports(output);
-
-  if (has_error()) {
-    return base::unexpected(std::move(error_manager_).TakeError());
-  }
-
-  base::Value::Dict dict;
-  if (!event_level_results.empty()) {
-    dict.Set("event_level_results", std::move(event_level_results));
-  }
-
-  if (!aggregatable_results.empty()) {
-    dict.Set("aggregatable_results", std::move(aggregatable_results));
-  }
-
-  if (!verbose_debug_reports.empty()) {
-    dict.Set("verbose_debug_reports", std::move(verbose_debug_reports));
-  }
-
-  return dict;
-}
-
 void AttributionInteropParser::ParseRandomizedResponseRate(
     const base::Value::Dict& dict,
     base::StringPiece key,
@@ -645,12 +482,6 @@
       std::move(input));
 }
 
-base::expected<base::Value::Dict, std::string>
-AttributionInteropOutputFromSimulatorOutput(base::Value::Dict output) {
-  return AttributionInteropParser().InteropOutputFromSimulatorOutput(
-      std::move(output));
-}
-
 base::expected<AttributionConfig, std::string> ParseAttributionConfig(
     const base::Value::Dict& dict) {
   AttributionConfig config;
diff --git a/content/browser/attribution_reporting/attribution_interop_parser.h b/content/browser/attribution_reporting/attribution_interop_parser.h
index c8dfe98..0315751 100644
--- a/content/browser/attribution_reporting/attribution_interop_parser.h
+++ b/content/browser/attribution_reporting/attribution_interop_parser.h
@@ -21,9 +21,6 @@
 base::expected<base::Value::Dict, std::string>
     AttributionSimulatorInputFromInteropInput(base::Value::Dict);
 
-base::expected<base::Value::Dict, std::string>
-    AttributionInteropOutputFromSimulatorOutput(base::Value::Dict);
-
 base::expected<AttributionConfig, std::string> ParseAttributionConfig(
     const base::Value::Dict&);
 
diff --git a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
index 583a0cb..34f356f 100644
--- a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
@@ -128,93 +128,6 @@
   EXPECT_THAT(*result, base::test::IsJson(base::test::ParseJson(kOutputJson)));
 }
 
-TEST(AttributionInteropParserTest, ValidOutput) {
-  constexpr char kInputJson[] = R"json({
-      "event_level_reports": [{
-        "intended_report_time": "1643235573120",
-        "report_time": "1643235573123",
-        "report_url": "https://r.example/path",
-        "report": {
-          "attribution_destination": "https://d.test",
-          "randomized_trigger_rate": 0.0024,
-          "source_event_id": "123",
-          "source_type": "navigation",
-          "trigger_data": "7"
-        }
-      }],
-      "aggregatable_reports": [{
-        "intended_report_time": "1643235573120",
-        "report_time": "1643235573123",
-        "report_url": "https://r.example/path",
-        "report": {
-          "attribution_destination": "https://d.test",
-        },
-        "test_info": {
-          "histograms": [{
-            "key": "key",
-            "value": "0x159"
-          }]
-        }
-      }],
-      "verbose_debug_reports": [{
-        "report": [{
-          "body": {
-            "attribution_destination": "https://destination2.test",
-            "limit": "1",
-            "source_event_id": "222",
-            "source_site": "https://source1.test"
-           },
-           "type": "source-destination-limit"
-        }],
-        "report_time": "1643235575000",
-        "report_url": "https://reporter1.test/.well-known/attribution-reporting/debug/verbose"
-      }]
-    })json";
-
-  constexpr char kOutputJson[] = R"json({
-      "event_level_results": [{
-        "report_time": "1643235573120",
-        "report_url": "https://r.example/path",
-        "payload": {
-          "attribution_destination": "https://d.test",
-          "randomized_trigger_rate": 0.0024,
-          "source_event_id": "123",
-          "source_type": "navigation",
-          "trigger_data": "7"
-        }
-      }],
-      "aggregatable_results": [{
-        "report_time": "1643235573120",
-        "report_url": "https://r.example/path",
-        "payload": {
-          "attribution_destination": "https://d.test",
-          "histograms": [{
-            "key": "key",
-            "value": "0x159"
-          }]
-        }
-      }],
-      "verbose_debug_reports": [{
-        "payload": [{
-          "body": {
-            "attribution_destination": "https://destination2.test",
-            "limit": "1",
-            "source_event_id": "222",
-            "source_site": "https://source1.test"
-           },
-           "type": "source-destination-limit"
-        }],
-        "report_time": "1643235575000",
-        "report_url": "https://reporter1.test/.well-known/attribution-reporting/debug/verbose"
-      }]
-    })json";
-
-  auto result = AttributionInteropOutputFromSimulatorOutput(
-      base::test::ParseJsonDict(kInputJson));
-  ASSERT_TRUE(result.has_value()) << result.error();
-  EXPECT_THAT(*result, base::test::IsJson(base::test::ParseJson(kOutputJson)));
-}
-
 TEST(AttributionInteropParserTest, ValidConfig) {
   const struct {
     const char* json;
@@ -733,160 +646,5 @@
                          AttributionInteropParseInputErrorTest,
                          ::testing::ValuesIn(kParseInputErrorTestCases));
 
-class AttributionInteropParseOutputErrorTest
-    : public testing::TestWithParam<ParseErrorTestCase> {};
-
-TEST_P(AttributionInteropParseOutputErrorTest, InvalidOutputFails) {
-  const ParseErrorTestCase& test_case = GetParam();
-
-  auto result = AttributionInteropOutputFromSimulatorOutput(
-      base::test::ParseJsonDict(test_case.json));
-  ASSERT_FALSE(result.has_value());
-  EXPECT_THAT(result.error(), HasSubstr(test_case.expected_failure_substr));
-}
-
-const ParseErrorTestCase kParseOutputErrorTestCases[] = {
-    {
-        R"(["event_level_reports"]: must be a list)",
-        R"json({
-          "event_level_reports": ""
-        })json",
-    },
-    {
-        R"(["event_level_reports"][0]: must be a dictionary)",
-        R"json({
-          "event_level_reports": [""]
-        })json",
-    },
-    {
-        R"(["event_level_reports"][0]["report"]: must be present)",
-        R"json({
-          "event_level_reports": [{}]
-        })json",
-    },
-    {
-        R"(["event_level_reports"][0]["report_url"]: must be present)",
-        R"json({
-          "event_level_reports": [{}]
-        })json",
-    },
-    {
-        R"(["event_level_reports"][0]["intended_report_time"]: must be present)",
-        R"json({
-          "event_level_reports": [{}]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"]: must be a list)",
-        R"json({
-          "aggregatable_reports": ""
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]: must be a dictionary)",
-        R"json({
-          "aggregatable_reports": [""]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["report_url"]: must be present)",
-        R"json({
-          "aggregatable_reports": [{}]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["intended_report_time"]: must be present)",
-        R"json({
-          "aggregatable_reports": [{}]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["test_info"]: must be present)",
-        R"json({
-          "aggregatable_reports": [{}]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["test_info"]: must be a dictionary)",
-        R"json({
-          "aggregatable_reports": [{
-            "test_info": ""
-          }]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["report"]: must be present)",
-        R"json({
-          "aggregatable_reports": [{
-            "test_info": {}
-          }]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["report"]: must be a dictionary)",
-        R"json({
-          "aggregatable_reports": [{
-            "test_info": {},
-            "report": ""
-          }]
-        })json",
-    },
-    {
-        R"(["aggregatable_reports"][0]["report"]["histograms"]: must not be present)",
-        R"json({
-          "aggregatable_reports": [{
-            "report": {
-              "histograms": ""
-            },
-            "test_info": {
-              "histograms": []
-            }
-          }]
-        })json",
-    },
-    {
-        R"(["verbose_debug_reports"]: must be a list)",
-        R"json({
-          "verbose_debug_reports": {}
-        })json",
-    },
-    {
-        R"(["verbose_debug_reports"][0]: must be a dictionary)",
-        R"json({
-          "verbose_debug_reports": [""]
-        })json",
-    },
-    {
-        R"(["verbose_debug_reports"][0]["report"]: must be present)",
-        R"json({
-          "verbose_debug_reports": [{
-            "report_time": "",
-            "report_url": ""
-          }]
-        })json",
-    },
-    {
-        R"(["verbose_debug_reports"][0]["report_time"]: must be present)",
-        R"json({
-          "verbose_debug_reports": [{
-            "report": [],
-            "report_url": ""
-          }]
-        })json",
-    },
-    {
-        R"(["verbose_debug_reports"][0]["report_url"]: must be present)",
-        R"json({
-          "verbose_debug_reports": [{
-            "report": [],
-            "report_time": ""
-          }]
-        })json",
-    }};
-
-INSTANTIATE_TEST_SUITE_P(AttributionInteropParserInvalidOutputs,
-                         AttributionInteropParseOutputErrorTest,
-                         ::testing::ValuesIn(kParseOutputErrorTestCases));
-
 }  // namespace
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_interop_unittest.cc b/content/browser/attribution_reporting/attribution_interop_unittest.cc
index 8c82b1c..6e27c4f 100644
--- a/content/browser/attribution_reporting/attribution_interop_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_interop_unittest.cc
@@ -96,12 +96,9 @@
   auto input = AttributionSimulatorInputFromInteropInput(std::move(dict));
   ASSERT_TRUE(input.has_value()) << input.error();
 
-  auto simulator_output = RunAttributionSimulation(std::move(*input), config);
-  ASSERT_TRUE(simulator_output.has_value()) << simulator_output.error();
-
-  auto actual_output =
-      AttributionInteropOutputFromSimulatorOutput(std::move(*simulator_output));
+  auto actual_output = RunAttributionSimulation(std::move(*input), config);
   ASSERT_TRUE(actual_output.has_value()) << actual_output.error();
+
   EXPECT_THAT(*actual_output, base::test::IsJson(*expected_output));
 }
 
diff --git a/content/browser/attribution_reporting/attribution_simulator.cc b/content/browser/attribution_reporting/attribution_simulator.cc
index c8f7ca06..7feb1e0 100644
--- a/content/browser/attribution_reporting/attribution_simulator.cc
+++ b/content/browser/attribution_reporting/attribution_simulator.cc
@@ -108,6 +108,21 @@
         report_body.Remove("aggregation_service_payloads");
         report_body.Remove("source_registration_time");
 
+        const auto& aggregatable_data =
+            absl::get<AttributionReport::AggregatableAttributionData>(
+                report.data());
+
+        base::Value::List list;
+        for (const auto& contribution : aggregatable_data.contributions) {
+          base::Value::Dict dict;
+          dict.Set("key", attribution_reporting::HexEncodeAggregationKey(
+                              contribution.key()));
+          dict.Set("value", base::checked_cast<int>(contribution.value()));
+
+          list.Append(std::move(dict));
+        }
+        report_body.Set("histograms", std::move(list));
+
         break;
       }
       case AttributionReport::Type::kEventLevel:
@@ -118,30 +133,13 @@
     }
 
     base::Value::Dict value;
-    value.Set("report", std::move(report_body));
+    value.Set("payload", std::move(report_body));
     value.Set("report_url", report.ReportURL(is_debug_report).spec());
 
-    value.Set("intended_report_time",
+    value.Set("report_time",
               FormatTime(is_debug_report ? report.attribution_info().time
                                          : report.report_time()));
 
-    if (const auto* aggregatable_data =
-            absl::get_if<AttributionReport::AggregatableAttributionData>(
-                &report.data())) {
-      base::Value::List list;
-      for (const auto& contribution : aggregatable_data->contributions) {
-        base::Value::Dict dict;
-        dict.Set("key", attribution_reporting::HexEncodeAggregationKey(
-                            contribution.key()));
-        dict.Set("value", base::checked_cast<int>(contribution.value()));
-
-        list.Append(std::move(dict));
-      }
-      base::Value::Dict test_info;
-      test_info.Set("histograms", std::move(list));
-      value.Set("test_info", std::move(test_info));
-    }
-
     return value;
   }
 
@@ -163,7 +161,7 @@
     }
 
     base::Value::Dict value;
-    value.Set("report", std::move(report_body));
+    value.Set("payload", std::move(report_body));
     value.Set("report_url", report.ReportURL().spec());
     value.Set("report_time", FormatTime(time));
     return value;
@@ -282,22 +280,22 @@
     base::Value::Dict output;
 
     if (!event_level_reports_.empty()) {
-      output.Set("event_level_reports",
+      output.Set("event_level_results",
                  std::exchange(event_level_reports_, {}));
     }
 
     if (!debug_event_level_reports_.empty()) {
-      output.Set("debug_event_level_reports",
+      output.Set("debug_event_level_results",
                  std::exchange(debug_event_level_reports_, {}));
     }
 
     if (!aggregatable_reports_.empty()) {
-      output.Set("aggregatable_reports",
+      output.Set("aggregatable_results",
                  std::exchange(aggregatable_reports_, {}));
     }
 
     if (!debug_aggregatable_reports_.empty()) {
-      output.Set("debug_aggregatable_reports",
+      output.Set("debug_aggregatable_results",
                  std::exchange(debug_aggregatable_reports_, {}));
     }
 
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc
index 4b5045e..1c6129e 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql.cc
+++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -66,22 +66,6 @@
 
 namespace content {
 
-// Version number of the database.
-// TODO: remove the active_unattributed_sources_by_site_reporting_origin index
-// during the next DB migration.
-const int AttributionStorageSql::kCurrentVersionNumber = 46;
-
-// Earliest version which can use a |kCurrentVersionNumber| database
-// without failing.
-const int AttributionStorageSql::kCompatibleVersionNumber = 46;
-
-// Latest version of the database that cannot be upgraded to
-// |kCurrentVersionNumber| without razing the database.
-//
-// Note that all versions >=15 were introduced during the transitional state of
-// the Attribution Reporting API and can be removed when done.
-const int AttributionStorageSql::kDeprecatedVersionNumber = 34;
-
 namespace {
 
 using AggregatableResult = ::content::AttributionTrigger::AggregatableResult;
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.h b/content/browser/attribution_reporting/attribution_storage_sql.h
index d6eeccea..f93e09e8 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql.h
+++ b/content/browser/attribution_reporting/attribution_storage_sql.h
@@ -50,10 +50,24 @@
 // destroyed on the same sequence. The sequence must outlive |this|.
 class CONTENT_EXPORT AttributionStorageSql : public AttributionStorage {
  public:
-  // Exposed for testing.
-  static const int kCurrentVersionNumber;
-  static const int kCompatibleVersionNumber;
-  static const int kDeprecatedVersionNumber;
+  // Version number of the database.
+  // TODO: remove the active_unattributed_sources_by_site_reporting_origin index
+  // during the next DB migration.
+  static constexpr int kCurrentVersionNumber = 46;
+
+  // Earliest version which can use a `kCurrentVersionNumber` database
+  // without failing.
+  static constexpr int kCompatibleVersionNumber = 46;
+
+  // Latest version of the database that cannot be upgraded to
+  // `kCurrentVersionNumber` without razing the database.
+  //
+  // Note that all versions >=15 were introduced during the transitional state
+  // of the Attribution Reporting API and can be removed when done.
+  static constexpr int kDeprecatedVersionNumber = 34;
+
+  static_assert(kCompatibleVersionNumber <= kCurrentVersionNumber);
+  static_assert(kDeprecatedVersionNumber < kCompatibleVersionNumber);
 
   [[nodiscard]] static bool DeleteStorageForTesting(
       const base::FilePath& user_data_directory);
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
index c7f1a757..548a484 100644
--- a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
+++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
@@ -5,10 +5,12 @@
 #include "content/browser/attribution_reporting/attribution_storage_sql_migrations.h"
 
 #include "base/check.h"
+#include "base/functional/function_ref.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/time/time.h"
 #include "components/aggregation_service/aggregation_service.mojom.h"
 #include "content/browser/attribution_reporting/attribution_report.h"
+#include "content/browser/attribution_reporting/attribution_storage_sql.h"
 #include "content/browser/attribution_reporting/common_source_info.h"
 #include "content/browser/attribution_reporting/rate_limit_table.h"
 #include "sql/database.h"
@@ -35,12 +37,27 @@
 // transactions make it more likely that we'll make forward progress each time
 // Chrome stops.
 
-bool MigrateToVersion36(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
+[[nodiscard]] bool MaybeMigrate(
+    sql::Database* db,
+    sql::MetaTable* meta_table,
+    int old_version,
+    base::FunctionRef<bool(sql::Database*)> migrate) {
+  DCHECK(db);
+  DCHECK(meta_table);
+
+  if (meta_table->GetVersionNumber() != old_version) {
+    return true;
   }
 
+  sql::Transaction transaction(db);
+
+  return transaction.Begin() &&                             //
+         migrate(db) &&                                     //
+         SetVersionNumbers(meta_table, old_version + 1) &&  //
+         transaction.Commit();
+}
+
+bool To36(sql::Database* db) {
   static constexpr char kDropOldIndexSql[] = "DROP INDEX sources_by_origin";
   if (!db->Execute(kDropOldIndexSql)) {
     return false;
@@ -54,15 +71,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 36) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion37(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To37(sql::Database* db) {
   static constexpr char kNewDedupKeyTableSql[] =
       "CREATE TABLE new_dedup_keys("
       "source_id INTEGER NOT NULL,"
@@ -98,15 +110,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 37) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion38(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To38(sql::Database* db) {
   static constexpr char kNewSourceTableSql[] =
       "CREATE TABLE new_sources("
       "source_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
@@ -195,15 +202,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 38) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion39(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To39(sql::Database* db) {
   // Create the new aggregatable_report_metadata table with
   // aggregation_coordinator. This follows the steps documented at
   // https://sqlite.org/lang_altertable.html#otheralter. Other approaches, like
@@ -279,15 +281,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 39) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion40(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To40(sql::Database* db) {
   // Create the new aggregatable_contributions table with desired primary-key
   // structure.
   static constexpr char kCreateNewTableSql[] =
@@ -325,15 +322,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 40) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion41(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To41(sql::Database* db) {
   static constexpr char kAddAttestationHeaderColumnSql[] =
       "ALTER TABLE aggregatable_report_metadata "
       "ADD COLUMN attestation_token TEXT";
@@ -341,15 +333,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 41) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion42(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To42(sql::Database* db) {
   static constexpr char kRenameDestinationOriginSql[] =
       "ALTER TABLE rate_limits "
       "RENAME COLUMN destination_origin TO context_origin";
@@ -371,15 +358,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 42) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion43(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To43(sql::Database* db) {
   static constexpr char kRenameExpiryTimeSql[] =
       "ALTER TABLE rate_limits "
       "RENAME COLUMN expiry_time TO source_expiry_or_attribution_time";
@@ -396,15 +378,10 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 43) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion44(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To44(sql::Database* db) {
   {
     static constexpr char kConversionTableSql[] =
         "CREATE TABLE new_event_level_reports("
@@ -526,15 +503,10 @@
     }
   }
 
-  return SetVersionNumbers(meta_table, 44) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion45(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To45(sql::Database* db) {
   static constexpr char kRenameSql[] =
       "ALTER TABLE event_level_reports "
       "RENAME COLUMN destination_origin TO context_origin";
@@ -542,20 +514,15 @@
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 45) && transaction.Commit();
+  return true;
 }
 
-bool MigrateToVersion46(sql::Database* db, sql::MetaTable* meta_table) {
-  sql::Transaction transaction(db);
-  if (!transaction.Begin()) {
-    return false;
-  }
-
+bool To46(sql::Database* db) {
   if (!db->Execute("ALTER TABLE sources DROP COLUMN destination_origin")) {
     return false;
   }
 
-  return SetVersionNumbers(meta_table, 46) && transaction.Commit();
+  return true;
 }
 
 }  // namespace
@@ -570,62 +537,26 @@
     start_timestamp = base::ThreadTicks::Now();
   }
 
-  if (meta_table->GetVersionNumber() == 35) {
-    if (!MigrateToVersion36(db, meta_table)) {
-      return false;
-    }
+  static_assert(AttributionStorageSql::kDeprecatedVersionNumber + 1 == 35,
+                "Remove migration(s) below.");
+
+  bool ok = MaybeMigrate(db, meta_table, 35, &To36) &&
+            MaybeMigrate(db, meta_table, 36, &To37) &&
+            MaybeMigrate(db, meta_table, 37, &To38) &&
+            MaybeMigrate(db, meta_table, 38, &To39) &&
+            MaybeMigrate(db, meta_table, 39, &To40) &&
+            MaybeMigrate(db, meta_table, 40, &To41) &&
+            MaybeMigrate(db, meta_table, 41, &To42) &&
+            MaybeMigrate(db, meta_table, 42, &To43) &&
+            MaybeMigrate(db, meta_table, 43, &To44) &&
+            MaybeMigrate(db, meta_table, 44, &To45) &&
+            MaybeMigrate(db, meta_table, 45, &To46);
+  if (!ok) {
+    return false;
   }
-  if (meta_table->GetVersionNumber() == 36) {
-    if (!MigrateToVersion37(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 37) {
-    if (!MigrateToVersion38(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 38) {
-    if (!MigrateToVersion39(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 39) {
-    if (!MigrateToVersion40(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 40) {
-    if (!MigrateToVersion41(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 41) {
-    if (!MigrateToVersion42(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 42) {
-    if (!MigrateToVersion43(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 43) {
-    if (!MigrateToVersion44(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 44) {
-    if (!MigrateToVersion45(db, meta_table)) {
-      return false;
-    }
-  }
-  if (meta_table->GetVersionNumber() == 45) {
-    if (!MigrateToVersion46(db, meta_table)) {
-      return false;
-    }
-  }
-  // Add similar if () blocks for new versions here.
+
+  static_assert(AttributionStorageSql::kCurrentVersionNumber == 46,
+                "Add migration(s) above.");
 
   if (base::ThreadTicks::IsSupported()) {
     base::UmaHistogramMediumTimes("Conversions.Storage.MigrationTime",
diff --git a/content/browser/file_system_access/file_system_access_file_handle_move_browsertest.cc b/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc
similarity index 66%
rename from content/browser/file_system_access/file_system_access_file_handle_move_browsertest.cc
rename to content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc
index cb4aca10..e60be1a 100644
--- a/content/browser/file_system_access/file_system_access_file_handle_move_browsertest.cc
+++ b/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc
@@ -12,11 +12,11 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
 
-// TODO(crbug.com/1408211): Make this a WPT once crbug.com/1114920 is fixed.
-class FileSystemAccessFileHandleMoveBrowserTest : public ContentBrowserTest {
+class FileSystemAccessFileHandleImplBrowserTest : public ContentBrowserTest {
  public:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -76,7 +76,8 @@
   GURL test_url_;
 };
 
-IN_PROC_BROWSER_TEST_F(FileSystemAccessFileHandleMoveBrowserTest,
+// TODO(crbug.com/1408211): Make this a WPT once crbug.com/1114920 is fixed.
+IN_PROC_BROWSER_TEST_F(FileSystemAccessFileHandleImplBrowserTest,
                        MoveLocalToSandboxed) {
   std::string file_contents = "move me to a sandboxed file system";
   CreateTestFileInDirectory(temp_dir_.GetPath(), file_contents);
@@ -91,7 +92,8 @@
       << result.error;
 }
 
-IN_PROC_BROWSER_TEST_F(FileSystemAccessFileHandleMoveBrowserTest,
+// TODO(crbug.com/1408211): Make this a WPT once crbug.com/1114920 is fixed.
+IN_PROC_BROWSER_TEST_F(FileSystemAccessFileHandleImplBrowserTest,
                        MoveSandboxedToLocal) {
   CreateTestDirectoryInDirectory(temp_dir_.GetPath());
 
@@ -111,15 +113,13 @@
 }
 
 class FileSystemAccessFileHandleMoveLocalBrowserTest
-    : public FileSystemAccessFileHandleMoveBrowserTest {
+    : public FileSystemAccessFileHandleImplBrowserTest {
  public:
   FileSystemAccessFileHandleMoveLocalBrowserTest() {
     scoped_feature_list_.InitAndDisableFeature(
         features::kFileSystemAccessMoveLocalFiles);
   }
 
-  void SetUp() override { FileSystemAccessFileHandleMoveBrowserTest::SetUp(); }
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -136,4 +136,58 @@
       << result.error;
 }
 
+class FileSystemAccessFileHandleGetUniqueIdBrowserTest
+    : public FileSystemAccessFileHandleImplBrowserTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    FileSystemAccessFileHandleImplBrowserTest::SetUpCommandLine(command_line);
+    // Enable File System Access experimental features, which includes the
+    // getUniqueId() method.
+    command_line->AppendSwitch(
+        "--enable-blink-features=FileSystemAccessAPIExperimental");
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(FileSystemAccessFileHandleGetUniqueIdBrowserTest,
+                       SameFileFromDifferentPickerInvocations) {
+  base::FilePath file_path;
+  std::string file_contents = "I am unique";
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_TRUE(
+        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
+    EXPECT_TRUE(base::WriteFile(file_path, file_contents));
+  }
+
+  ui::SelectFileDialog::SetFactory(
+      new FakeSelectFileDialogFactory({file_path}));
+  EXPECT_TRUE(NavigateToURL(shell(), test_url_));
+  EXPECT_EQ(file_path.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let [e] = await self.showOpenFilePicker();"
+                   "  self.file1 = e;"
+                   "  return e.name; })()"));
+  EXPECT_EQ(file_path.BaseName().AsUTF8Unsafe(),
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  let [e] = await self.showOpenFilePicker();"
+                   "  self.file2 = e;"
+                   "  return e.name; })()"));
+
+  EXPECT_TRUE(EvalJs(shell(),
+                     "(async () => {"
+                     "return await self.file2.isSameEntry(self.file1); })()")
+                  .ExtractBool());
+  auto uniqueId1 = EvalJs(shell(),
+                          "(async () => {"
+                          "return await self.file1.getUniqueId(); })()")
+                       .ExtractString();
+  auto uniqueId2 = EvalJs(shell(),
+                          "(async () => {"
+                          "return await self.file2.getUniqueId(); })()")
+                       .ExtractString();
+  EXPECT_EQ(uniqueId1, uniqueId2);
+}
+
 }  // namespace content
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9f1efcd..28c9933 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -446,17 +446,6 @@
     // Block this DLL even if it is not loaded by the browser process.
     config->AddDllToUnload(L"cmsetac.dll");
 
-    if (cmd_line_.HasSwitch(switches::kEnableLogging)) {
-      std::wstring log_file_path = logging::GetLogFileFullPath();
-      if (!log_file_path.empty()) {
-        sandbox::ResultCode result = config->AddRule(
-            sandbox::SubSystem::kFiles, sandbox::Semantics::kFilesAllowAny,
-            log_file_path.c_str());
-        if (result != sandbox::SBOX_ALL_OK)
-          return false;
-      }
-    }
-
     return true;
   }
 
diff --git a/content/browser/renderer_host/input/touch_emulator.cc b/content/browser/renderer_host/input/touch_emulator.cc
index 2b45a83..2c52f2bd 100644
--- a/content/browser/renderer_host/input/touch_emulator.cc
+++ b/content/browser/renderer_host/input/touch_emulator.cc
@@ -5,6 +5,7 @@
 #include "content/browser/renderer_host/input/touch_emulator.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/containers/queue.h"
 #include "base/time/time.h"
@@ -24,6 +25,8 @@
 #include "ui/events/base_event_utils.h"
 #include "ui/events/blink/blink_event_util.h"
 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/skia_conversions.h"
 #include "ui/gfx/image/image.h"
 
 using blink::WebGestureEvent;
@@ -72,7 +75,6 @@
       gesture_provider_config_type_(
           ui::GestureProviderConfigType::CURRENT_PLATFORM),
       double_tap_enabled_(true),
-      use_2x_cursors_(false),
       pinch_gesture_mode_for_testing_(false),
       emulated_stream_active_sequence_count_(0),
       native_stream_active_sequence_count_(0),
@@ -80,7 +82,7 @@
       pending_taps_count_(0) {
   DCHECK(client_);
   ResetState();
-  InitCursors(device_scale_factor, true);
+  SetDeviceScaleFactor(device_scale_factor);
 }
 
 TouchEmulator::~TouchEmulator() {
@@ -102,7 +104,7 @@
 void TouchEmulator::Enable(Mode mode,
                            ui::GestureProviderConfigType config_type) {
   if (gesture_provider_ && mode_ != mode)
-    client_->SetCursor(pointer_cursor_);
+    client_->SetCursor(ui::mojom::CursorType::kPointer);
 
   if (!gesture_provider_ || gesture_provider_config_type_ != config_type ||
       mode_ != mode) {
@@ -128,13 +130,20 @@
   gesture_provider_.reset();
   base::queue<base::OnceClosure> empty;
   injected_touch_completion_callbacks_.swap(empty);
-  client_->SetCursor(pointer_cursor_);
+  client_->SetCursor(ui::mojom::CursorType::kPointer);
   ResetState();
 }
 
 void TouchEmulator::SetDeviceScaleFactor(float device_scale_factor) {
-  if (!InitCursors(device_scale_factor, false))
+  // Make sure the scale factor corresponds to the one of the available cursor
+  // images.
+  const float cursor_scale_factor = device_scale_factor < 1.5f ? 1.0f : 2.0f;
+  if (cursor_scale_factor == cursor_scale_factor_) {
     return;
+  }
+
+  cursor_scale_factor_ = cursor_scale_factor;
+  InitCursors();
   if (enabled())
     UpdateCursor();
 }
@@ -145,38 +154,31 @@
     gesture_provider_->SetDoubleTapSupportForPageEnabled(enabled);
 }
 
-bool TouchEmulator::InitCursors(float device_scale_factor, bool force) {
-  bool use_2x = device_scale_factor > 1.5f;
-  if (use_2x == use_2x_cursors_ && !force)
-    return false;
-  use_2x_cursors_ = use_2x;
-  float cursor_scale_factor = use_2x ? 2.f : 1.f;
-  cursor_size_ = InitCursorFromResource(&touch_cursor_,
-      cursor_scale_factor,
-      use_2x ? IDR_DEVTOOLS_TOUCH_CURSOR_ICON_2X :
-          IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
-  InitCursorFromResource(&pinch_cursor_,
-      cursor_scale_factor,
-      use_2x ? IDR_DEVTOOLS_PINCH_CURSOR_ICON_2X :
-          IDR_DEVTOOLS_PINCH_CURSOR_ICON);
-
-  pointer_cursor_ = ui::Cursor(ui::mojom::CursorType::kPointer);
-  return true;
+void TouchEmulator::InitCursors() {
+  touch_cursor_ = InitCursorFromResource(
+      cursor_scale_factor_ == 1.0f ? IDR_DEVTOOLS_TOUCH_CURSOR_ICON
+                                   : IDR_DEVTOOLS_TOUCH_CURSOR_ICON_2X);
+  pinch_cursor_ = InitCursorFromResource(
+      cursor_scale_factor_ == 1.0f ? IDR_DEVTOOLS_PINCH_CURSOR_ICON
+                                   : IDR_DEVTOOLS_PINCH_CURSOR_ICON_2X);
+  // The touch cursor is bigger. Use its size in DIPs for both cursors.
+  cursor_size_ = gfx::ScaleSize(
+      gfx::SizeF(
+          gfx::SkISizeToSize(touch_cursor_.custom_bitmap().dimensions())),
+      1 / cursor_scale_factor_);
 }
 
-gfx::SizeF TouchEmulator::InitCursorFromResource(ui::Cursor* cursor,
-                                                 float scale,
-                                                 int resource_id) {
-  gfx::Image& cursor_image =
+ui::Cursor TouchEmulator::InitCursorFromResource(int resource_id) {
+  const gfx::Image& cursor_image =
       content::GetContentClient()->GetNativeImageNamed(resource_id);
-  ui::Cursor cursor_info(ui::mojom::CursorType::kCustom);
-  cursor_info.set_image_scale_factor(scale);
-  cursor_info.set_custom_bitmap(cursor_image.AsBitmap());
-  cursor_info.set_custom_hotspot(
-      gfx::Point(cursor_image.Width() / 2, cursor_image.Height() / 2));
+  SkBitmap bitmap = cursor_image.AsBitmap();
+  gfx::Point hotspot(bitmap.width() / 2, bitmap.height() / 2);
 
-  *cursor = cursor_info;
-  return gfx::ScaleSize(gfx::SizeF(cursor_image.Size()), 1.f / scale);
+  ui::Cursor cursor(ui::mojom::CursorType::kCustom);
+  cursor.set_custom_bitmap(std::move(bitmap));
+  cursor.set_custom_hotspot(std::move(hotspot));
+  cursor.set_image_scale_factor(cursor_scale_factor_);
+  return cursor;
 }
 
 bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event,
diff --git a/content/browser/renderer_host/input/touch_emulator.h b/content/browser/renderer_host/input/touch_emulator.h
index 267238c7..0cc3e13 100644
--- a/content/browser/renderer_host/input/touch_emulator.h
+++ b/content/browser/renderer_host/input/touch_emulator.h
@@ -104,11 +104,8 @@
   void OnGestureEvent(const ui::GestureEventData& gesture) override;
   bool RequiresDoubleTapGestureEvents() const override;
 
-  // Returns cursor size in DIP.
-  gfx::SizeF InitCursorFromResource(ui::Cursor* cursor,
-                                    float scale,
-                                    int resource_id);
-  bool InitCursors(float device_scale_factor, bool force);
+  ui::Cursor InitCursorFromResource(int resource_id);
+  void InitCursors();
   void ResetState();
   void UpdateCursor();
   bool UpdateShiftPressed(bool shift_pressed);
@@ -147,14 +144,14 @@
   Mode mode_;
   bool double_tap_enabled_;
 
-  bool use_2x_cursors_;
   // While emulation is on, default cursor is touch. Pressing shift changes
   // cursor to the pinch one.
-  ui::Cursor pointer_cursor_;
   ui::Cursor touch_cursor_;
   ui::Cursor pinch_cursor_;
   gfx::SizeF cursor_size_;
 
+  float cursor_scale_factor_ = 0;
+
   // These are used to drop extra mouse move events coming too quickly, so
   // we don't handle too much touches in gesture provider.
   bool last_mouse_event_was_move_;
diff --git a/content/browser/renderer_host/input/touch_emulator_unittest.cc b/content/browser/renderer_host/input/touch_emulator_unittest.cc
index 2d364c9..1a3fdf96 100644
--- a/content/browser/renderer_host/input/touch_emulator_unittest.cc
+++ b/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -251,6 +251,8 @@
 
   void DisableSynchronousTouchAck() { ack_touches_synchronously_ = false; }
 
+  const ui::Cursor& GetCursor() { return cursor_; }
+
   float GetCursorScaleFactor() { return cursor_.image_scale_factor(); }
 
  private:
@@ -595,9 +597,9 @@
   emulator()->SetDeviceScaleFactor(1.33f);
   EXPECT_EQ(1.0f, GetCursorScaleFactor());
   emulator()->Disable();
-  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  EXPECT_EQ(ui::mojom::CursorType::kPointer, GetCursor().type());
   emulator()->SetDeviceScaleFactor(3.0f);
-  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  EXPECT_EQ(ui::mojom::CursorType::kPointer, GetCursor().type());
   emulator()->Enable(TouchEmulator::Mode::kEmulatingTouchFromMouse,
                      ui::GestureProviderConfigType::GENERIC_MOBILE);
   EXPECT_EQ(2.0f, GetCursorScaleFactor());
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index d66761d..b346c1c 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -2501,11 +2501,7 @@
           /*is_renderer_initiated_check=*/false));
     }
 
-    // No throttles will actually run, but `CommitNavigation()` expects to be
-    // called only once the request has reached `WILL_PROCESS_RESPONSE`.
-    SetState(WILL_PROCESS_RESPONSE);
-
-    CommitNavigation();
+    WillCommitWithoutUrlLoader();
     return;
   }
 
@@ -3251,8 +3247,9 @@
 }
 
 void NavigationRequest::DetermineOriginAgentClusterEndResult() {
-  DCHECK(state_ == WILL_PROCESS_RESPONSE || state_ == WILL_FAIL_REQUEST ||
-         state_ == CANCELING);
+  DCHECK(state_ == WILL_PROCESS_RESPONSE ||
+         state_ == WILL_COMMIT_WITHOUT_URL_LOADER ||
+         state_ == WILL_FAIL_REQUEST || state_ == CANCELING);
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
   url::Origin origin = GetOriginToCommit().value();
   const IsolationContext& isolation_context =
@@ -5068,6 +5065,23 @@
   // NavigationRequest.
 }
 
+void NavigationRequest::OnWillCommitWithoutUrlLoaderChecksComplete(
+    NavigationThrottle::ThrottleCheckResult result) {
+  DCHECK(result.action() == NavigationThrottle::CANCEL_AND_IGNORE ||
+         result.action() == NavigationThrottle::PROCEED);
+  if (result.action() == NavigationThrottle::CANCEL_AND_IGNORE) {
+    OnRequestFailedInternal(
+        network::URLLoaderCompletionStatus(result.net_error_code()),
+        /*skip_throttles=*/true, result.error_page_content(),
+        /*collapse_frame=*/false);
+
+    // DO NOT ADD CODE after this. The previous call to OnRequestFailedInternal
+    // has destroyed the NavigationRequest.
+    return;
+  }
+  CommitNavigation();
+}
+
 void NavigationRequest::RunCommitDeferringConditions() {
   // TODO(nhiroki): Make RegisterDeferringConditions() private and have
   // ProcessChecks() call it for code cleanup.
@@ -6193,6 +6207,9 @@
     case NavigationThrottleRunner::Event::WillProcessResponse:
       OnWillProcessResponseProcessed(result);
       return;
+    case NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader:
+      OnWillCommitWithoutUrlLoaderProcessed(result);
+      return;
     default:
       NOTREACHED();
   }
@@ -6291,6 +6308,24 @@
   // deleted by the previous calls.
 }
 
+void NavigationRequest::OnWillCommitWithoutUrlLoaderProcessed(
+    NavigationThrottle::ThrottleCheckResult result) {
+  DCHECK_EQ(WILL_COMMIT_WITHOUT_URL_LOADER, state_);
+  DCHECK(result.action() == NavigationThrottle::CANCEL_AND_IGNORE ||
+         result.action() == NavigationThrottle::PROCEED);
+  DCHECK(processing_navigation_throttle_);
+  processing_navigation_throttle_ = false;
+  if (complete_callback_for_testing_ &&
+      std::move(complete_callback_for_testing_).Run(result)) {
+    return;
+  }
+
+  OnWillCommitWithoutUrlLoaderChecksComplete(result);
+
+  // DO NOT ADD CODE AFTER THIS, as the NavigationRequest might have been
+  // deleted by the previous calls.
+}
+
 NavigatorDelegate* NavigationRequest::GetDelegate() const {
   return frame_tree_node()->navigator().GetDelegate();
 }
@@ -6369,6 +6404,9 @@
     case WILL_PROCESS_RESPONSE:
       OnWillProcessResponseChecksComplete(result);
       return;
+    case WILL_COMMIT_WITHOUT_URL_LOADER:
+      OnWillCommitWithoutUrlLoaderChecksComplete(result);
+      return;
     default:
       NOTREACHED();
   }
@@ -6471,6 +6509,22 @@
   // by the previous call.
 }
 
+void NavigationRequest::WillCommitWithoutUrlLoader() {
+  EnterChildTraceEvent("WillCommitWithoutUrlLoader", this);
+
+  throttle_runner_->RegisterNavigationThrottlesForCommitWithoutUrlLoader();
+
+  // `CommitNavigation()` expects to be called once the request has reached
+  // at least `WILL_PROCESS_REPSONSE`. `WILL_COMMIT_WITHOUT_URL_LOADER` meets
+  // that requirement, and is useful to clarify which throttles we are waiting
+  // for.
+  SetState(WILL_COMMIT_WITHOUT_URL_LOADER);
+  processing_navigation_throttle_ = true;
+
+  throttle_runner_->ProcessNavigationEvent(
+      NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader);
+}
+
 bool NavigationRequest::IsSelfReferentialURL() {
   // about: URLs should be exempted since they are reserved for other purposes
   // and cannot be the source of infinite recursion.
@@ -8187,6 +8241,7 @@
           {WILL_START_REQUEST, {
               WILL_REDIRECT_REQUEST,
               WILL_PROCESS_RESPONSE,
+              WILL_COMMIT_WITHOUT_URL_LOADER,
               READY_TO_COMMIT,
               DID_COMMIT,
               CANCELING,
@@ -8204,6 +8259,11 @@
               CANCELING,
               WILL_FAIL_REQUEST,
           }},
+          {WILL_COMMIT_WITHOUT_URL_LOADER, {
+              READY_TO_COMMIT,
+              CANCELING,
+              WILL_FAIL_REQUEST,
+          }},
           {READY_TO_COMMIT, {
               NOT_STARTED,
               DID_COMMIT,
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 64dc22d..d457923d 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -159,6 +159,11 @@
     // asynchronous.
     WILL_PROCESS_RESPONSE,
 
+    // The navigation does not require a request/response. Wait only for
+    // NavigationThrottles to finish before calling CommitNavigation(). This
+    // will only be asynchronous if a throttle defers the navigation.
+    WILL_COMMIT_WITHOUT_URL_LOADER,
+
     // The browser process has asked the renderer to commit the response
     // and is waiting for acknowledgement that it has been committed.
     READY_TO_COMMIT,
@@ -899,8 +904,9 @@
   // Note #2: Even though "javascript:" URL and RendererDebugURL fit very well
   // in this category, they don't use the NavigationRequest.
   //
-  // Note #3: Navigations that do not use a URL loader also bypass
-  //          NavigationThrottle.
+  // Note #3: Navigations that do not use a URL loader do not send the usual
+  // set of callbacks to NavigationThrottle. Instead, they send a single
+  // separate callback, WillCommitWithoutUrlLoader().
   bool NeedsUrlLoader();
 
   network::mojom::PrivateNetworkRequestPolicy private_network_request_policy()
@@ -1234,6 +1240,8 @@
   void OnFailureChecksComplete(NavigationThrottle::ThrottleCheckResult result);
   void OnWillProcessResponseChecksComplete(
       NavigationThrottle::ThrottleCheckResult result);
+  void OnWillCommitWithoutUrlLoaderChecksComplete(
+      NavigationThrottle::ThrottleCheckResult result);
 
   // Runs CommitDeferringConditions.
   //
@@ -1424,6 +1432,8 @@
       NavigationThrottle::ThrottleCheckResult result);
   void OnWillProcessResponseProcessed(
       NavigationThrottle::ThrottleCheckResult result);
+  void OnWillCommitWithoutUrlLoaderProcessed(
+      NavigationThrottle::ThrottleCheckResult result);
 
   void CancelDeferredNavigationInternal(
       NavigationThrottle::ThrottleCheckResult result);
@@ -1455,6 +1465,10 @@
   // just before calling |callback|.
   void WillProcessResponse();
 
+  // Called when no URLRequest will be needed to perform this navigation, just
+  // before commit.
+  void WillCommitWithoutUrlLoader();
+
   // Checks for attempts to navigate to a page that is already referenced more
   // than once in the frame's ancestors.  This is a helper function used by
   // WillStartRequest and WillRedirectRequest to prevent the navigation.
diff --git a/content/browser/renderer_host/navigation_request_browsertest.cc b/content/browser/renderer_host/navigation_request_browsertest.cc
index d76ff817..931a901 100644
--- a/content/browser/renderer_host/navigation_request_browsertest.cc
+++ b/content/browser/renderer_host/navigation_request_browsertest.cc
@@ -87,19 +87,26 @@
       NavigationThrottle::ThrottleCheckResult will_redirect_result,
       NavigationThrottle::ThrottleCheckResult will_fail_result,
       NavigationThrottle::ThrottleCheckResult will_process_result,
+      NavigationThrottle::ThrottleCheckResult
+          will_commit_without_url_loader_result,
       base::OnceClosure did_call_will_start,
       base::OnceClosure did_call_will_redirect,
       base::OnceClosure did_call_will_fail,
-      base::OnceClosure did_call_will_process)
+      base::OnceClosure did_call_will_process,
+      base::OnceClosure did_call_will_commit_without_url_loader)
       : NavigationThrottle(handle),
         will_start_result_(will_start_result),
         will_redirect_result_(will_redirect_result),
         will_fail_result_(will_fail_result),
         will_process_result_(will_process_result),
+        will_commit_without_url_loader_result_(
+            will_commit_without_url_loader_result),
         did_call_will_start_(std::move(did_call_will_start)),
         did_call_will_redirect_(std::move(did_call_will_redirect)),
         did_call_will_fail_(std::move(did_call_will_fail)),
-        did_call_will_process_(std::move(did_call_will_process)) {}
+        did_call_will_process_(std::move(did_call_will_process)),
+        did_call_will_commit_without_url_loader_(
+            std::move(did_call_will_commit_without_url_loader)) {}
   ~TestNavigationThrottle() override = default;
 
   const char* GetNameForLogging() override { return "TestNavigationThrottle"; }
@@ -159,14 +166,30 @@
     return will_process_result_;
   }
 
+  NavigationThrottle::ThrottleCheckResult WillCommitWithoutUrlLoader()
+      override {
+    NavigationRequest* navigation_request =
+        NavigationRequest::From(navigation_handle());
+    CHECK_NE(blink::mojom::RequestContextType::UNSPECIFIED,
+             navigation_request->request_context_type());
+    request_context_type_ = navigation_request->request_context_type();
+
+    GetUIThreadTaskRunner({})->PostTask(
+        FROM_HERE, std::move(did_call_will_commit_without_url_loader_));
+    return will_commit_without_url_loader_result_;
+  }
+
   NavigationThrottle::ThrottleCheckResult will_start_result_;
   NavigationThrottle::ThrottleCheckResult will_redirect_result_;
   NavigationThrottle::ThrottleCheckResult will_fail_result_;
   NavigationThrottle::ThrottleCheckResult will_process_result_;
+  NavigationThrottle::ThrottleCheckResult
+      will_commit_without_url_loader_result_;
   base::OnceClosure did_call_will_start_;
   base::OnceClosure did_call_will_redirect_;
   base::OnceClosure did_call_will_fail_;
   base::OnceClosure did_call_will_process_;
+  base::OnceClosure did_call_will_commit_without_url_loader_;
   blink::mojom::RequestContextType request_context_type_ =
       blink::mojom::RequestContextType::UNSPECIFIED;
 };
@@ -182,6 +205,7 @@
     WILL_REDIRECT_REQUEST,
     WILL_FAIL_REQUEST,
     WILL_PROCESS_RESPONSE,
+    WILL_COMMIT_WITHOUT_URL_LOADER,
   };
 
   TestNavigationThrottleInstaller(
@@ -190,12 +214,16 @@
       NavigationThrottle::ThrottleCheckResult will_redirect_result,
       NavigationThrottle::ThrottleCheckResult will_fail_result,
       NavigationThrottle::ThrottleCheckResult will_process_result,
+      NavigationThrottle::ThrottleCheckResult
+          will_commit_without_url_loader_result,
       const GURL& expected_start_url = GURL())
       : WebContentsObserver(web_contents),
         will_start_result_(will_start_result),
         will_redirect_result_(will_redirect_result),
         will_fail_result_(will_fail_result),
         will_process_result_(will_process_result),
+        will_commit_without_url_loader_result_(
+            will_commit_without_url_loader_result),
         expected_start_url_(expected_start_url) {}
   ~TestNavigationThrottleInstaller() override = default;
 
@@ -210,6 +238,7 @@
     auto will_redirect_result = will_start_result;
     auto will_fail_result = will_start_result;
     auto will_process_result = will_start_result;
+    auto will_commit_without_url_loader_result = will_start_result;
 
     switch (method) {
       case WILL_START_REQUEST:
@@ -224,11 +253,14 @@
       case WILL_PROCESS_RESPONSE:
         will_process_result = result;
         break;
+      case WILL_COMMIT_WITHOUT_URL_LOADER:
+        will_commit_without_url_loader_result = result;
+        break;
     }
 
     return std::make_unique<TestNavigationThrottleInstaller>(
         web_contents, will_start_result, will_redirect_result, will_fail_result,
-        will_process_result);
+        will_process_result, will_commit_without_url_loader_result);
   }
 
   TestNavigationThrottle* navigation_throttle() { return navigation_throttle_; }
@@ -265,6 +297,15 @@
     will_process_loop_runner_ = nullptr;
   }
 
+  void WaitForThrottleWillCommitWithoutUrlLoader() {
+    if (will_commit_without_url_loader_called_) {
+      return;
+    }
+    will_commit_without_url_loader_loop_runner_ = new MessageLoopRunner();
+    will_commit_without_url_loader_loop_runner_->Run();
+    will_commit_without_url_loader_loop_runner_ = nullptr;
+  }
+
   void Continue(NavigationThrottle::ThrottleCheckResult result) {
     ASSERT_NE(NavigationThrottle::DEFER, result.action());
     if (result.action() == NavigationThrottle::PROCEED)
@@ -277,6 +318,9 @@
   int will_redirect_called() { return will_redirect_called_; }
   int will_fail_called() { return will_fail_called_; }
   int will_process_called() { return will_process_called_; }
+  int will_commit_without_url_loader_called() {
+    return will_commit_without_url_loader_called_;
+  }
 
   int install_count() { return install_count_; }
 
@@ -305,6 +349,13 @@
       will_process_loop_runner_->Quit();
   }
 
+  virtual void DidCallWillCommitWithoutUrlLoader() {
+    will_commit_without_url_loader_called_++;
+    if (will_commit_without_url_loader_loop_runner_) {
+      will_commit_without_url_loader_loop_runner_->Quit();
+    }
+  }
+
  private:
   void DidStartNavigation(NavigationHandle* handle) override {
     if (!expected_start_url_.is_empty() &&
@@ -313,7 +364,7 @@
 
     std::unique_ptr<NavigationThrottle> throttle(new TestNavigationThrottle(
         handle, will_start_result_, will_redirect_result_, will_fail_result_,
-        will_process_result_,
+        will_process_result_, will_commit_without_url_loader_result_,
         base::BindOnce(
             &TestNavigationThrottleInstaller::DidCallWillStartRequest,
             weak_factory_.GetWeakPtr()),
@@ -324,6 +375,9 @@
                        weak_factory_.GetWeakPtr()),
         base::BindOnce(
             &TestNavigationThrottleInstaller::DidCallWillProcessResponse,
+            weak_factory_.GetWeakPtr()),
+        base::BindOnce(
+            &TestNavigationThrottleInstaller::DidCallWillCommitWithoutUrlLoader,
             weak_factory_.GetWeakPtr())));
     navigation_throttle_ = static_cast<TestNavigationThrottle*>(throttle.get());
     handle->RegisterThrottleForTesting(std::move(throttle));
@@ -342,16 +396,20 @@
   NavigationThrottle::ThrottleCheckResult will_redirect_result_;
   NavigationThrottle::ThrottleCheckResult will_fail_result_;
   NavigationThrottle::ThrottleCheckResult will_process_result_;
+  NavigationThrottle::ThrottleCheckResult
+      will_commit_without_url_loader_result_;
   int will_start_called_ = 0;
   int will_redirect_called_ = 0;
   int will_fail_called_ = 0;
   int will_process_called_ = 0;
+  int will_commit_without_url_loader_called_ = 0;
   raw_ptr<TestNavigationThrottle> navigation_throttle_ = nullptr;
   int install_count_ = 0;
   scoped_refptr<MessageLoopRunner> will_start_loop_runner_;
   scoped_refptr<MessageLoopRunner> will_redirect_loop_runner_;
   scoped_refptr<MessageLoopRunner> will_fail_loop_runner_;
   scoped_refptr<MessageLoopRunner> will_process_loop_runner_;
+  scoped_refptr<MessageLoopRunner> will_commit_without_url_loader_loop_runner_;
   GURL expected_start_url_;
 
   // The throttle installer can be deleted before all tasks posted by its
@@ -371,17 +429,22 @@
       NavigationThrottle::ThrottleCheckResult will_redirect_result,
       NavigationThrottle::ThrottleCheckResult will_fail_result,
       NavigationThrottle::ThrottleCheckResult will_process_result,
+      NavigationThrottle::ThrottleCheckResult
+          will_commit_without_url_loader_result,
       GURL expected_start_url = GURL())
       : TestNavigationThrottleInstaller(web_contents,
                                         NavigationThrottle::DEFER,
                                         NavigationThrottle::DEFER,
                                         NavigationThrottle::DEFER,
                                         NavigationThrottle::DEFER,
+                                        NavigationThrottle::DEFER,
                                         expected_start_url),
         will_start_deferred_result_(will_start_result),
         will_redirect_deferred_result_(will_redirect_result),
         will_fail_deferred_result_(will_fail_result),
-        will_process_deferred_result_(will_process_result) {}
+        will_process_deferred_result_(will_process_result),
+        will_commit_without_url_loader_result_(
+            will_commit_without_url_loader_result) {}
 
  protected:
   void DidCallWillStartRequest() override {
@@ -404,11 +467,18 @@
     Continue(will_process_deferred_result_);
   }
 
+  void DidCallWillCommitWithoutUrlLoader() override {
+    TestNavigationThrottleInstaller::DidCallWillCommitWithoutUrlLoader();
+    Continue(will_commit_without_url_loader_result_);
+  }
+
  private:
   NavigationThrottle::ThrottleCheckResult will_start_deferred_result_;
   NavigationThrottle::ThrottleCheckResult will_redirect_deferred_result_;
   NavigationThrottle::ThrottleCheckResult will_fail_deferred_result_;
   NavigationThrottle::ThrottleCheckResult will_process_deferred_result_;
+  NavigationThrottle::ThrottleCheckResult
+      will_commit_without_url_loader_result_;
 };
 
 // Records all navigation start URLs from the WebContents.
@@ -937,7 +1007,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::CANCEL,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
 
@@ -963,7 +1033,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::CANCEL, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
 
@@ -980,7 +1050,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::CANCEL, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     EXPECT_TRUE(NavigateToURL(shell(), no_redirect_url));
 
@@ -1005,7 +1075,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::CANCEL,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     NavigationHandleObserver observer(shell()->web_contents(), url);
 
@@ -1028,7 +1098,7 @@
         NavigationThrottle::PROCEED,
         NavigationThrottle::ThrottleCheckResult(NavigationThrottle::CANCEL,
                                                 net::ERR_CERT_DATE_INVALID),
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     NavigationHandleObserver observer(shell()->web_contents(), url);
 
@@ -1052,7 +1122,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::CANCEL,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     EXPECT_TRUE(NavigateToURL(shell(), url));
 
@@ -1073,7 +1143,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::CANCEL);
+      NavigationThrottle::CANCEL, NavigationThrottle::PROCEED);
 
   EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
 
@@ -1085,6 +1155,28 @@
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url);
 }
 
+// Ensure that a NavigationThrottle can cancel the navigation when committing
+// without a URLLoader.
+IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
+                       ThrottleCancelCommitWithoutUrlLoader) {
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  GURL about_blank_url(url::kAboutBlankURL);
+  NavigationHandleObserver observer(shell()->web_contents(), about_blank_url);
+  TestNavigationThrottleInstaller installer(
+      shell()->web_contents(), NavigationThrottle::PROCEED,
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+      NavigationThrottle::PROCEED, NavigationThrottle::CANCEL_AND_IGNORE);
+
+  EXPECT_FALSE(NavigateToURL(shell(), about_blank_url));
+
+  EXPECT_FALSE(observer.has_committed());
+  EXPECT_TRUE(observer.is_error());
+  EXPECT_FALSE(observer.was_redirected());
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), start_url);
+}
+
 // Ensure that a NavigationThrottle can defer and resume the navigation at
 // navigation start, navigation redirect and response received.
 IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest, ThrottleDefer) {
@@ -1098,7 +1190,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::DEFER,
       NavigationThrottle::DEFER, NavigationThrottle::DEFER,
-      NavigationThrottle::DEFER);
+      NavigationThrottle::DEFER, NavigationThrottle::DEFER);
 
   shell()->LoadURL(redirect_url);
 
@@ -1108,6 +1200,7 @@
   EXPECT_EQ(0, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_fail_called());
   EXPECT_EQ(0, installer.will_process_called());
+  EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
   installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for WillRedirectRequest.
@@ -1116,6 +1209,7 @@
   EXPECT_EQ(1, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_fail_called());
   EXPECT_EQ(0, installer.will_process_called());
+  EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
   installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for WillProcessResponse.
@@ -1124,6 +1218,7 @@
   EXPECT_EQ(1, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_fail_called());
   EXPECT_EQ(1, installer.will_process_called());
+  EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
   installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for the end of the navigation.
@@ -1149,7 +1244,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::DEFER,
       NavigationThrottle::DEFER, NavigationThrottle::DEFER,
-      NavigationThrottle::DEFER);
+      NavigationThrottle::DEFER, NavigationThrottle::DEFER);
 
   shell()->LoadURL(failure_url);
 
@@ -1159,6 +1254,7 @@
   EXPECT_EQ(0, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_fail_called());
   EXPECT_EQ(0, installer.will_process_called());
+  EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
   installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for WillFailRequest.
@@ -1167,6 +1263,7 @@
   EXPECT_EQ(0, installer.will_redirect_called());
   EXPECT_EQ(1, installer.will_fail_called());
   EXPECT_EQ(0, installer.will_process_called());
+  EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
   installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for the end of the navigation.
@@ -1177,6 +1274,180 @@
   EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, observer.net_error_code());
 }
 
+// Ensure that a NavigationThrottle can defer and resume the navigation when
+// navigating without a URLLoader. This test covers multiple types of
+// navigations that do not require a URLLoader (same-document navigations and
+// about:blank).
+IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
+                       ThrottleDeferCommitWithoutUrlLoader) {
+  GURL url(embedded_test_server()->GetURL("/title1.html"));
+  GURL url_fragment(embedded_test_server()->GetURL("/title1.html#id_1"));
+  GURL about_blank_url(url::kAboutBlankURL);
+
+  // Perform a new-document navigation (setup).
+  {
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::PROCEED,
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
+    NavigationHandleObserver observer(shell()->web_contents(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
+    EXPECT_EQ(1, installer.will_start_called());
+    EXPECT_EQ(1, installer.will_process_called());
+    EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
+    EXPECT_FALSE(observer.is_same_document());
+  }
+
+  // Same-document navigation
+  {
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    NavigationHandleObserver observer(shell()->web_contents(), url_fragment);
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER);
+
+    shell()->LoadURL(url_fragment);
+
+    // Wait for WillCommitWithoutUrlLoader.
+    installer.WaitForThrottleWillCommitWithoutUrlLoader();
+    EXPECT_EQ(0, installer.will_start_called());
+    EXPECT_EQ(0, installer.will_redirect_called());
+    EXPECT_EQ(0, installer.will_fail_called());
+    EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
+    installer.navigation_throttle()->ResumeNavigation();
+
+    // Wait for the end of the navigation.
+    navigation_observer.Wait();
+
+    EXPECT_TRUE(observer.is_same_document());
+    EXPECT_TRUE(observer.has_committed());
+    EXPECT_FALSE(observer.was_redirected());
+    EXPECT_FALSE(observer.is_error());
+    EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url_fragment);
+  }
+
+  // about:blank
+  {
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    NavigationHandleObserver observer(shell()->web_contents(), about_blank_url);
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER);
+
+    shell()->LoadURL(about_blank_url);
+
+    // Wait for WillCommitWithoutUrlLoader.
+    installer.WaitForThrottleWillCommitWithoutUrlLoader();
+    EXPECT_EQ(0, installer.will_start_called());
+    EXPECT_EQ(0, installer.will_redirect_called());
+    EXPECT_EQ(0, installer.will_fail_called());
+    EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
+    installer.navigation_throttle()->ResumeNavigation();
+
+    // Wait for the end of the navigation.
+    navigation_observer.Wait();
+
+    EXPECT_FALSE(observer.is_same_document());
+    EXPECT_TRUE(observer.has_committed());
+    EXPECT_FALSE(observer.was_redirected());
+    EXPECT_FALSE(observer.is_error());
+    EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), about_blank_url);
+  }
+}
+
+// Ensure that a NavigationThrottle can defer and cancel the navigation when
+// navigating without a URLLoader. This test covers multiple types of
+// navigations that do not require a URLLoader (same-document navigations and
+// about:blank).
+IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
+                       ThrottleDeferAndCancelCommitWithoutUrlLoader) {
+  GURL url(embedded_test_server()->GetURL("/title1.html"));
+  GURL url_fragment(embedded_test_server()->GetURL("/title1.html#id_1"));
+  GURL about_blank_url(url::kAboutBlankURL);
+
+  // Perform a new-document navigation (setup).
+  {
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::PROCEED,
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
+    NavigationHandleObserver observer(shell()->web_contents(), url);
+    EXPECT_TRUE(NavigateToURL(shell(), url));
+    EXPECT_EQ(1, installer.will_start_called());
+    EXPECT_EQ(1, installer.will_process_called());
+    EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
+    EXPECT_FALSE(observer.is_same_document());
+  }
+
+  // Same-document navigation
+  {
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    NavigationHandleObserver observer(shell()->web_contents(), url_fragment);
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER);
+
+    shell()->LoadURL(url_fragment);
+
+    // Wait for WillCommitWithoutUrlLoader.
+    installer.WaitForThrottleWillCommitWithoutUrlLoader();
+    EXPECT_EQ(0, installer.will_start_called());
+    EXPECT_EQ(0, installer.will_redirect_called());
+    EXPECT_EQ(0, installer.will_fail_called());
+    EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
+
+    // Cancel the deferred navigation.
+    installer.navigation_throttle()->CancelNavigation(
+        NavigationThrottle::CANCEL_AND_IGNORE);
+
+    // Wait for the end of the navigation.
+    navigation_observer.Wait();
+
+    EXPECT_TRUE(observer.is_same_document());
+    EXPECT_FALSE(observer.has_committed());
+    EXPECT_FALSE(observer.was_redirected());
+    EXPECT_TRUE(observer.is_error());
+  }
+
+  // about:blank
+  {
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    NavigationHandleObserver observer(shell()->web_contents(), about_blank_url);
+    TestNavigationThrottleInstaller installer(
+        shell()->web_contents(), NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER,
+        NavigationThrottle::DEFER, NavigationThrottle::DEFER);
+
+    shell()->LoadURL(about_blank_url);
+
+    // Wait for WillCommitWithoutUrlLoader.
+    installer.WaitForThrottleWillCommitWithoutUrlLoader();
+    EXPECT_EQ(0, installer.will_start_called());
+    EXPECT_EQ(0, installer.will_redirect_called());
+    EXPECT_EQ(0, installer.will_fail_called());
+    EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
+
+    // Cancel the deferred navigation.
+    installer.navigation_throttle()->CancelNavigation(
+        NavigationThrottle::CANCEL_AND_IGNORE);
+
+    // Wait for the end of the navigation.
+    navigation_observer.Wait();
+
+    EXPECT_FALSE(observer.is_same_document());
+    EXPECT_FALSE(observer.has_committed());
+    EXPECT_FALSE(observer.was_redirected());
+    EXPECT_TRUE(observer.is_error());
+  }
+}
+
 // Ensure that a NavigationThrottle can block the navigation and collapse the
 // frame owner both on request start as well as after a redirect. Plus, ensure
 // that the frame is restored on the subsequent non-error-page navigation.
@@ -1220,13 +1491,15 @@
           std::make_unique<TestDeferringNavigationThrottleInstaller>(
               shell()->web_contents(), test_case.will_start_result,
               test_case.will_redirect_result, NavigationThrottle::PROCEED,
-              NavigationThrottle::PROCEED, blocked_subframe_url);
+              NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+              blocked_subframe_url);
     } else {
       subframe_throttle_installer =
           std::make_unique<TestNavigationThrottleInstaller>(
               shell()->web_contents(), test_case.will_start_result,
               test_case.will_redirect_result, NavigationThrottle::PROCEED,
-              NavigationThrottle::PROCEED, blocked_subframe_url);
+              NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+              blocked_subframe_url);
     }
 
     {
@@ -1289,7 +1562,8 @@
   TestNavigationThrottleInstaller subframe_throttle_installer(
       shell()->web_contents(), NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED, blocked_subframe_url);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+      blocked_subframe_url);
 
   {
     SCOPED_TRACE("Initial navigation blocked on main frame load.");
@@ -1333,7 +1607,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   TestNavigationManager main_manager(shell()->web_contents(), main_url);
   TestNavigationManager b_manager(shell()->web_contents(), b_url);
   TestNavigationManager c_manager(shell()->web_contents(), c_url);
@@ -1385,7 +1659,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   TestNavigationManager link_manager(shell()->web_contents(), link_url);
   NavigationStartUrlRecorder url_recorder(shell()->web_contents());
 
@@ -1418,7 +1692,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   TestNavigationManager post_manager(shell()->web_contents(), post_url);
   NavigationStartUrlRecorder url_recorder(shell()->web_contents());
 
@@ -1456,7 +1730,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::CANCEL_AND_IGNORE,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), kUrl);
 
     // Try to navigate to the url. The navigation should be canceled and the
@@ -1471,7 +1745,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::CANCEL_AND_IGNORE, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), kRedirectingUrl);
 
     // Try to navigate to the url. The navigation should be canceled and the
@@ -1486,7 +1760,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::CANCEL_AND_IGNORE);
+        NavigationThrottle::CANCEL_AND_IGNORE, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), kUrl);
 
     // Try to navigate to the url. The navigation should be canceled and the
@@ -1501,7 +1775,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::BLOCK_REQUEST,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), kUrl);
 
     // Try to navigate to the url. The navigation should be canceled and the
@@ -1515,7 +1789,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::BLOCK_REQUEST, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   NavigationHandleObserver observer(shell()->web_contents(), kRedirectingUrl);
 
   // Try to navigate to the url. The navigation should be canceled and the
@@ -1545,7 +1819,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::CANCEL_AND_IGNORE,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   EXPECT_FALSE(NavigateToURL(shell(), kUrl2));
 }
@@ -1646,7 +1920,7 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     TestNavigationManager navigation_manager(shell()->web_contents(),
                                              iframe_secure_url);
 
@@ -1757,6 +2031,9 @@
 
 // Ensure that browser-initiated same-document navigations are detected and
 // don't issue network requests.  See crbug.com/663777.
+// Browser-initiated same-document navigations should trigger a
+// WillCommitWithoutUrlLoader() callback, instead of the WillStartRequest()
+// and WillProcessResponse() callbacks used when there is a network request.
 IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
                        SameDocumentBrowserInitiatedNoReload) {
   GURL url(embedded_test_server()->GetURL("/title1.html"));
@@ -1768,11 +2045,12 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), url);
     EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(1, installer.will_start_called());
     EXPECT_EQ(1, installer.will_process_called());
+    EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
     EXPECT_FALSE(observer.is_same_document());
   }
 
@@ -1781,11 +2059,12 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), url_fragment_1);
     EXPECT_TRUE(NavigateToURL(shell(), url_fragment_1));
     EXPECT_EQ(0, installer.will_start_called());
     EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
     EXPECT_TRUE(observer.is_same_document());
   }
 
@@ -1794,11 +2073,12 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), url_fragment_2);
     EXPECT_TRUE(NavigateToURL(shell(), url_fragment_2));
     EXPECT_EQ(0, installer.will_start_called());
     EXPECT_EQ(0, installer.will_process_called());
+    EXPECT_EQ(1, installer.will_commit_without_url_loader_called());
     EXPECT_TRUE(observer.is_same_document());
   }
 
@@ -1807,11 +2087,12 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), url_fragment_2);
     EXPECT_TRUE(NavigateToURL(shell(), url_fragment_2));
     EXPECT_EQ(1, installer.will_start_called());
     EXPECT_EQ(1, installer.will_process_called());
+    EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
     EXPECT_FALSE(observer.is_same_document());
   }
 
@@ -1820,11 +2101,12 @@
     TestNavigationThrottleInstaller installer(
         shell()->web_contents(), NavigationThrottle::PROCEED,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
     NavigationHandleObserver observer(shell()->web_contents(), url);
     EXPECT_TRUE(NavigateToURL(shell(), url));
     EXPECT_EQ(1, installer.will_start_called());
     EXPECT_EQ(1, installer.will_process_called());
+    EXPECT_EQ(0, installer.will_commit_without_url_loader_called());
     EXPECT_FALSE(observer.is_same_document());
   }
 }
@@ -1900,7 +2182,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::BLOCK_REQUEST, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   NavigationHandleObserver observer(shell()->web_contents(), kRedirectingUrl);
   NavigationLogger logger(shell()->web_contents());
 
@@ -1970,7 +2252,7 @@
   auto installer = std::make_unique<TestNavigationThrottleInstaller>(
       shell()->web_contents(), NavigationThrottle::BLOCK_REQUEST,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   {
     // A blocked, renderer-initiated navigation in the main frame should commit
@@ -2053,7 +2335,7 @@
   installer = std::make_unique<TestNavigationThrottleInstaller>(
       shell()->web_contents(), NavigationThrottle::BLOCK_REQUEST,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   {
     // A blocked, browser-initiated navigation should commit an error page in a
@@ -2094,7 +2376,7 @@
     installer = std::make_unique<TestNavigationThrottleInstaller>(
         shell()->web_contents(), NavigationThrottle::BLOCK_REQUEST,
         NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-        NavigationThrottle::PROCEED);
+        NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
     content::RenderFrameHost* rfh =
         shell()->web_contents()->GetPrimaryMainFrame();
@@ -2312,8 +2594,9 @@
                 new TestNavigationThrottle(
                     handle, NavigationThrottle::DEFER,
                     NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-                    NavigationThrottle::PROCEED, base::DoNothing(),
-                    base::DoNothing(), base::DoNothing(), base::DoNothing()));
+                    NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+                    base::DoNothing(), base::DoNothing(), base::DoNothing(),
+                    base::DoNothing(), base::DoNothing()));
             client_throttle = throttle.get();
             throttles.push_back(std::move(throttle));
             return throttles;
@@ -2324,7 +2607,8 @@
   // before browser client throttles are registered.
   TestNavigationThrottleInstaller test_throttle_installer(
       web_contents, NavigationThrottle::DEFER, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
+      NavigationThrottle::PROCEED);
 
   // Start navigating.
   TestNavigationManager manager(shell()->web_contents(), simple_url);
@@ -2374,7 +2658,7 @@
   TestNavigationThrottleInstaller installer(
       web_contents, NavigationThrottle::BLOCK_REQUEST,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
   NavigationHandleObserver commit_observer(web_contents, blocked_url);
   EXPECT_FALSE(NavigateToURL(shell(), blocked_url));
   NavigationEntry* last_committed =
@@ -2513,7 +2797,7 @@
       TestNavigationThrottleInstaller installer(
           shell()->web_contents(), NavigationThrottle::PROCEED,
           NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-          NavigationThrottle::PROCEED);
+          NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
       NavigateIframeToURL(shell()->web_contents(), "child0", iframe_url);
 
@@ -2809,7 +3093,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::CANCEL,
       NavigationThrottle::PROCEED, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(), url));
   EXPECT_FALSE(observer.has_committed());
@@ -2836,7 +3120,7 @@
   TestNavigationThrottleInstaller installer(
       shell()->web_contents(), NavigationThrottle::PROCEED,
       NavigationThrottle::CANCEL, NavigationThrottle::PROCEED,
-      NavigationThrottle::PROCEED);
+      NavigationThrottle::PROCEED, NavigationThrottle::PROCEED);
 
   EXPECT_FALSE(NavigateToURL(shell(), redirect_url));
 
@@ -3555,7 +3839,8 @@
       NavigationThrottle::PROCEED /* will_start_result */,
       NavigationThrottle::PROCEED /* will_redirect_result */,
       NavigationThrottle::DEFER /* will_fail_result */,
-      NavigationThrottle::PROCEED /* will_process_result */);
+      NavigationThrottle::PROCEED /* will_process_result */,
+      NavigationThrottle::PROCEED /* will_commit_without_url_loader_result */);
 
   // Start a navigation to foo.com that will result in an error.
   shell()->web_contents()->GetController().LoadURL(
diff --git a/content/browser/renderer_host/navigation_request_unittest.cc b/content/browser/renderer_host/navigation_request_unittest.cc
index 379157f..01116fa 100644
--- a/content/browser/renderer_host/navigation_request_unittest.cc
+++ b/content/browser/renderer_host/navigation_request_unittest.cc
@@ -144,6 +144,22 @@
     GetNavigationRequest()->WillFailRequest();
   }
 
+  // Helper function to call WillCommitWithoutUrlLoader on |handle|. If this
+  // function returns DEFER, |callback_result_| will be set to the actual result
+  // of the throttle checks when they are finished.
+  void SimulateWillCommitWithoutUrlLoader() {
+    was_callback_called_ = false;
+    callback_result_ = NavigationThrottle::DEFER;
+
+    // It's safe to use base::Unretained since the NavigationRequest is owned by
+    // the NavigationRequestTest.
+    GetNavigationRequest()->set_complete_callback_for_testing(
+        base::BindOnce(&NavigationRequestTest::UpdateThrottleCheckResult,
+                       base::Unretained(this)));
+
+    GetNavigationRequest()->WillCommitWithoutUrlLoader();
+  }
+
   // Whether the callback was called.
   bool was_callback_called() const { return was_callback_called_; }
 
@@ -160,7 +176,8 @@
                          int start,
                          int redirect,
                          int failure,
-                         int process) {
+                         int process,
+                         int withoutUrlLoader) {
     return start == throttle->GetCallCount(
                         TestNavigationThrottle::WILL_START_REQUEST) &&
            redirect == throttle->GetCallCount(
@@ -168,7 +185,10 @@
            failure == throttle->GetCallCount(
                           TestNavigationThrottle::WILL_FAIL_REQUEST) &&
            process == throttle->GetCallCount(
-                          TestNavigationThrottle::WILL_PROCESS_RESPONSE);
+                          TestNavigationThrottle::WILL_PROCESS_RESPONSE) &&
+           withoutUrlLoader ==
+               throttle->GetCallCount(
+                   TestNavigationThrottle::WILL_COMMIT_WITHOUT_URL_LOADER);
   }
 
   // Creates, register and returns a TestNavigationThrottle that will
@@ -332,21 +352,21 @@
   TestNavigationThrottle* test_throttle =
       CreateTestNavigationThrottle(NavigationThrottle::DEFER);
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
 
   // Simulate WillStartRequest. The request should be deferred. The callback
   // should not have been called.
   SimulateWillStartRequest();
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
   EXPECT_FALSE(was_callback_called());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 
   // Cancel the request. The callback should have been called.
   CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
   EXPECT_EQ(NavigationRequest::CANCELING, state());
   EXPECT_TRUE(was_callback_called());
   EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 }
 
 // Checks that a navigation deferred during WillRedirectRequest can be properly
@@ -355,21 +375,21 @@
   TestNavigationThrottle* test_throttle =
       CreateTestNavigationThrottle(NavigationThrottle::DEFER);
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
 
   // Simulate WillRedirectRequest. The request should be deferred. The callback
   // should not have been called.
   SimulateWillRedirectRequest();
   EXPECT_EQ(NavigationRequest::WILL_REDIRECT_REQUEST, state());
   EXPECT_FALSE(was_callback_called());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0, 0));
 
   // Cancel the request. The callback should have been called.
   CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
   EXPECT_EQ(NavigationRequest::CANCELING, state());
   EXPECT_TRUE(was_callback_called());
   EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 1, 0, 0, 0));
 }
 
 // Checks that a navigation deferred during WillFailRequest can be properly
@@ -378,25 +398,25 @@
   TestNavigationThrottle* test_throttle = CreateTestNavigationThrottle(
       TestNavigationThrottle::WILL_FAIL_REQUEST, NavigationThrottle::DEFER);
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
 
   // Simulate WillStartRequest.
   SimulateWillStartRequest();
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 
   // Simulate WillFailRequest. The request should be deferred. The callback
   // should not have been called.
   SimulateWillFailRequest(net::ERR_CERT_DATE_INVALID);
   EXPECT_EQ(NavigationRequest::WILL_FAIL_REQUEST, state());
   EXPECT_FALSE(was_callback_called());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
 
   // Cancel the request. The callback should have been called.
   CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
   EXPECT_EQ(NavigationRequest::CANCELING, state());
   EXPECT_TRUE(was_callback_called());
   EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
 }
 
 // Checks that a navigation deferred can be canceled and not ignored.
@@ -404,13 +424,13 @@
   TestNavigationThrottle* test_throttle =
       CreateTestNavigationThrottle(NavigationThrottle::DEFER);
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
 
   // Simulate WillStartRequest. The request should be deferred. The callback
   // should not have been called.
   SimulateWillStartRequest();
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 
   // Cancel the request. The callback should have been called with CANCEL, and
   // not CANCEL_AND_IGNORE.
@@ -418,7 +438,7 @@
   EXPECT_EQ(NavigationRequest::CANCELING, state());
   EXPECT_TRUE(was_callback_called());
   EXPECT_EQ(NavigationThrottle::CANCEL, callback_result());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 }
 
 // Checks that a navigation deferred by WillFailRequest can be canceled and not
@@ -427,18 +447,18 @@
   TestNavigationThrottle* test_throttle = CreateTestNavigationThrottle(
       TestNavigationThrottle::WILL_FAIL_REQUEST, NavigationThrottle::DEFER);
   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
-  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
 
   // Simulate WillStartRequest.
   SimulateWillStartRequest();
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 0, 0, 0));
 
   // Simulate WillFailRequest. The request should be deferred. The callback
   // should not have been called.
   SimulateWillFailRequest(net::ERR_CERT_DATE_INVALID);
   EXPECT_EQ(NavigationRequest::WILL_FAIL_REQUEST, state());
   EXPECT_FALSE(was_callback_called());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
 
   // Cancel the request. The callback should have been called with CANCEL, and
   // not CANCEL_AND_IGNORE.
@@ -446,7 +466,30 @@
   EXPECT_EQ(NavigationRequest::CANCELING, state());
   EXPECT_TRUE(was_callback_called());
   EXPECT_EQ(NavigationThrottle::CANCEL, callback_result());
-  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0));
+  EXPECT_TRUE(call_counts_match(test_throttle, 1, 0, 1, 0, 0));
+}
+
+// Checks that a navigation deferred during WillCommitWithoutUrlLoader can be
+// properly cancelled.
+TEST_F(NavigationRequestTest, CancelDeferredWillCommitWithoutUrlLoader) {
+  TestNavigationThrottle* test_throttle =
+      CreateTestNavigationThrottle(NavigationThrottle::DEFER);
+  EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, state());
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 0));
+
+  // Simulate WillCommitWithoutUrlLoader. The request should be deferred. The
+  // callback should not have been called.
+  SimulateWillCommitWithoutUrlLoader();
+  EXPECT_EQ(NavigationRequest::WILL_COMMIT_WITHOUT_URL_LOADER, state());
+  EXPECT_FALSE(was_callback_called());
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 1));
+
+  // Cancel the request. The callback should have been called.
+  CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
+  EXPECT_EQ(NavigationRequest::CANCELING, state());
+  EXPECT_TRUE(was_callback_called());
+  EXPECT_EQ(NavigationThrottle::CANCEL_AND_IGNORE, callback_result());
+  EXPECT_TRUE(call_counts_match(test_throttle, 0, 0, 0, 0, 1));
 }
 
 // Checks that data from the SSLInfo passed into SimulateWillStartRequest() is
diff --git a/content/browser/renderer_host/navigation_throttle_runner.cc b/content/browser/renderer_host/navigation_throttle_runner.cc
index c93cbc9..bf471013 100644
--- a/content/browser/renderer_host/navigation_throttle_runner.cc
+++ b/content/browser/renderer_host/navigation_throttle_runner.cc
@@ -39,6 +39,8 @@
       return throttle->WillFailRequest();
     case NavigationThrottleRunner::Event::WillProcessResponse:
       return throttle->WillProcessResponse();
+    case NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader:
+      return throttle->WillCommitWithoutUrlLoader();
     default:
       NOTREACHED();
   }
@@ -56,6 +58,8 @@
       return "NavigationThrottle::WillFailRequest";
     case NavigationThrottleRunner::Event::WillProcessResponse:
       return "NavigationThrottle::WillProcessResponse";
+    case NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader:
+      return "NavigationThrottle::WillCommitWithoutUrlLoader";
     default:
       NOTREACHED();
   }
@@ -72,6 +76,8 @@
       return "WillFailRequest";
     case NavigationThrottleRunner::Event::WillProcessResponse:
       return "WillProcessResponse";
+    case NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader:
+      return "WillCommitWithoutUrlLoader";
     default:
       NOTREACHED();
   }
@@ -197,6 +203,33 @@
                     std::make_move_iterator(testing_throttles.end()));
 }
 
+void NavigationThrottleRunner::
+    RegisterNavigationThrottlesForCommitWithoutUrlLoader() {
+  // Note: |throttle_| might not be empty. Some NavigationThrottles might have
+  // been registered with RegisterThrottleForTesting. These must reside at the
+  // end of |throttles_|. TestNavigationManagerThrottle expects that the
+  // NavigationThrottles added for test are the last NavigationThrottles to
+  // execute. Take them out while appending the rest of the
+  // NavigationThrottles.
+  std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles =
+      std::move(throttles_);
+
+  // The NavigationRequest associated with the NavigationThrottles this
+  // NavigationThrottleRunner manages.
+  // Unit tests that do not use NavigationRequest should never call
+  // RegisterNavigationThrottlesForCommitWithoutUrlLoader as this function
+  // expects |delegate_| to be a NavigationRequest.
+  //
+  // TODO(japhet): Uncomment this once there are throttles for commits without
+  // a URL loader.
+  // NavigationRequest* request = static_cast<NavigationRequest*>(delegate_);
+
+  // Insert all testing NavigationThrottles last.
+  throttles_.insert(throttles_.end(),
+                    std::make_move_iterator(testing_throttles.begin()),
+                    std::make_move_iterator(testing_throttles.end()));
+}
+
 NavigationThrottle* NavigationThrottleRunner::GetDeferringThrottle() const {
   if (next_index_ == 0)
     return nullptr;
diff --git a/content/browser/renderer_host/navigation_throttle_runner.h b/content/browser/renderer_host/navigation_throttle_runner.h
index ca43aba..c0460205 100644
--- a/content/browser/renderer_host/navigation_throttle_runner.h
+++ b/content/browser/renderer_host/navigation_throttle_runner.h
@@ -28,6 +28,7 @@
     WillRedirectRequest = 2,
     WillFailRequest = 3,
     WillProcessResponse = 4,
+    WillCommitWithoutUrlLoader = 5,
   };
 
   class Delegate {
@@ -64,8 +65,16 @@
   // deferring NavigationThrottle do the resuming.
   void CallResumeForTesting();
 
+  // Registers the appropriate NavigationThrottles are added for a "standard"
+  // navigation (i.e., one with a URLLoader that goes through the
+  // WillSendRequest/WillProcessResponse callback sequence).
   void RegisterNavigationThrottles();
 
+  // Registers the appropriate NavigationThrottles for a navigation that can
+  // immediately commit because no URLLoader is required (about:blank,
+  // about:srcdoc, and most same-document navigations).
+  void RegisterNavigationThrottlesForCommitWithoutUrlLoader();
+
   // Returns the throttle that is currently deferring the navigation (i.e. the
   // throttle at index |next_index_ -1|). If the handle is not deferred, returns
   // nullptr;
diff --git a/content/browser/renderer_host/navigation_throttle_runner_unittest.cc b/content/browser/renderer_host/navigation_throttle_runner_unittest.cc
index 91f14a5..c2eff8cb 100644
--- a/content/browser/renderer_host/navigation_throttle_runner_unittest.cc
+++ b/content/browser/renderer_host/navigation_throttle_runner_unittest.cc
@@ -46,6 +46,12 @@
     return NavigationThrottle::PROCEED;
   }
 
+  NavigationThrottle::ThrottleCheckResult WillCommitWithoutUrlLoader()
+      override {
+    deletion_callback_.Run();
+    return NavigationThrottle::PROCEED;
+  }
+
   const char* GetNameForLogging() override {
     return "DeletingNavigationThrottle";
   }
@@ -131,6 +137,13 @@
       CHECK_EQ(0, throttle->GetCallCount(
                       TestNavigationThrottle::WILL_PROCESS_RESPONSE));
     }
+    if (event == NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader) {
+      CHECK_EQ(1, throttle->GetCallCount(
+                      TestNavigationThrottle::WILL_COMMIT_WITHOUT_URL_LOADER));
+    } else {
+      CHECK_EQ(0, throttle->GetCallCount(
+                      TestNavigationThrottle::WILL_COMMIT_WITHOUT_URL_LOADER));
+    }
   }
 
   // Creates, register and returns a TestNavigationThrottle that will
@@ -264,10 +277,12 @@
 INSTANTIATE_TEST_SUITE_P(
     AllEvents,
     NavigationThrottleRunnerTestWithEvent,
-    ::testing::Values(NavigationThrottleRunner::Event::WillStartRequest,
-                      NavigationThrottleRunner::Event::WillRedirectRequest,
-                      NavigationThrottleRunner::Event::WillFailRequest,
-                      NavigationThrottleRunner::Event::WillProcessResponse));
+    ::testing::Values(
+        NavigationThrottleRunner::Event::WillStartRequest,
+        NavigationThrottleRunner::Event::WillRedirectRequest,
+        NavigationThrottleRunner::Event::WillFailRequest,
+        NavigationThrottleRunner::Event::WillProcessResponse,
+        NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader));
 
 class NavigationThrottleRunnerTestWithEventAndAction
     : public NavigationThrottleRunnerTest,
@@ -411,10 +426,12 @@
     AllEvents,
     NavigationThrottleRunnerTestWithEventAndAction,
     ::testing::Combine(
-        ::testing::Values(NavigationThrottleRunner::Event::WillStartRequest,
-                          NavigationThrottleRunner::Event::WillRedirectRequest,
-                          NavigationThrottleRunner::Event::WillFailRequest,
-                          NavigationThrottleRunner::Event::WillProcessResponse),
+        ::testing::Values(
+            NavigationThrottleRunner::Event::WillStartRequest,
+            NavigationThrottleRunner::Event::WillRedirectRequest,
+            NavigationThrottleRunner::Event::WillFailRequest,
+            NavigationThrottleRunner::Event::WillProcessResponse,
+            NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader),
         ::testing::Values(NavigationThrottle::PROCEED,
                           NavigationThrottle::CANCEL,
                           NavigationThrottle::CANCEL_AND_IGNORE,
@@ -490,10 +507,12 @@
     AllEvents,
     NavigationThrottleRunnerTestWithEventAndError,
     ::testing::Combine(
-        ::testing::Values(NavigationThrottleRunner::Event::WillStartRequest,
-                          NavigationThrottleRunner::Event::WillRedirectRequest,
-                          NavigationThrottleRunner::Event::WillFailRequest,
-                          NavigationThrottleRunner::Event::WillProcessResponse),
+        ::testing::Values(
+            NavigationThrottleRunner::Event::WillStartRequest,
+            NavigationThrottleRunner::Event::WillRedirectRequest,
+            NavigationThrottleRunner::Event::WillFailRequest,
+            NavigationThrottleRunner::Event::WillProcessResponse,
+            NavigationThrottleRunner::Event::WillCommitWithoutUrlLoader),
         ::testing::Values(net::ERR_BLOCKED_BY_ADMINISTRATOR, net::ERR_ABORTED),
         ::testing::Values(absl::nullopt, "<html><body>test</body></html>")));
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 7da6528..f8da6ee 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -14448,12 +14448,6 @@
                         "security_origin", security_origin, "target_url",
                         target_url);
 
-  // TODO(nick, estark): Should we call FilterURL using this frame's process on
-  // these parameters? |target_url| seems unused, except for a log message. And
-  // |security_origin| might be replaceable with the origin of the main frame.
-
-  LOG(WARNING) << security_origin << " ran insecure content from "
-               << target_url.possibly_invalid_spec();
   RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
   if (base::EndsWith(security_origin.spec(), kDotGoogleDotCom,
                      base::CompareCase::INSENSITIVE_ASCII)) {
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index a03092f9..136a9007 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3788,8 +3788,10 @@
   // SiteInstance::GetProcess()/GetOrCreateAgentSchedulingGroupHost() has the
   // side effect of creating the process again if it is gone.
   //
-  // TODO(https://crbug.com/1382971): Change back to `raw_ref` after the ad-hoc
-  // debugging is no longer needed to investigate the bug.
+  // It is a `SafeRef` so that the browser process crashes cleanly if `this`
+  // unintentionally outlives its associated `RenderFrameProcessHost` but tries
+  // to access it or its associated `AgentSchedulingGroupHost` (see
+  // crbug.com/1297030).
   const base::SafeRef<AgentSchedulingGroupHost> agent_scheduling_group_;
 
   // Reference to the whole frame tree that this RenderFrameHost belongs to.
diff --git a/content/browser/web_contents/aura/OWNERS b/content/browser/web_contents/aura/OWNERS
index c65e542..90b3e80 100644
--- a/content/browser/web_contents/aura/OWNERS
+++ b/content/browser/web_contents/aura/OWNERS
@@ -1 +1 @@
-mohsen@chromium.org
+sky@chromium.org
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 705e3fa4..c71f65f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4595,13 +4595,6 @@
     std::vector<ui::AXPropertyFilter> property_filters) {
   OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::DumpAccessibilityTree");
   auto* ax_mgr = GetOrCreateRootBrowserAccessibilityManager();
-  DCHECK(ax_mgr);
-
-  // Developer mode: crash immediately on any accessibility fatal error.
-  // This only runs during integration tests, or if a developer is
-  // using an inspection tool, e.g. chrome://accessibility.
-  BrowserAccessibilityManager::AlwaysFailFast();
-
   // Since for Web Content we get the AXTree updates through the renderer at a
   // point after the manager is created, there are cases where at this point in
   // the lifecycle the AXTree associated with `ax_mgr` does not have a valid
@@ -4609,9 +4602,14 @@
   // we don't have this check, there will be a scenario where we then try to get
   // the manager using the ID (which at this point is invalid) which leads to a
   // crash. See https://crbug.com/1405036.
-  if (!ax_mgr->HasValidTreeID())
+  if (!ax_mgr || !ax_mgr->HasValidTreeID())
     return "-";
 
+  // Developer mode: crash immediately on any accessibility fatal error.
+  // This only runs during integration tests, or if a developer is
+  // using an inspection tool, e.g. chrome://accessibility.
+  BrowserAccessibilityManager::AlwaysFailFast();
+
   std::unique_ptr<ui::AXTreeFormatter> formatter =
       internal ? AXInspectFactory::CreateBlinkFormatter()
                : AXInspectFactory::CreatePlatformFormatter();
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index a1fbaede..2433969 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -310,6 +310,26 @@
             load_observer.controller_);
 }
 
+// Regression test for https://crbug.com/1405036
+// Dumping the accessibility tree should not crash, even if it has not received
+// an ID through a renderer tree yet.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       DumpAccessibilityTreeWithoutTreeID) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  LoadStopNotificationObserver load_observer(
+      &shell()->web_contents()->GetController());
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  load_observer.Wait();
+  std::string expected = "-";
+
+  std::vector<ui::AXPropertyFilter> property_filters;
+  EXPECT_EQ(
+      shell()->web_contents()->DumpAccessibilityTree(false, property_filters),
+      expected);
+}
+
 // Test that DidStopLoading includes the correct URL in the details when a
 // pending entry is present.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
diff --git a/content/public/browser/navigation_throttle.cc b/content/public/browser/navigation_throttle.cc
index 0fdd474cb..1d47d841 100644
--- a/content/public/browser/navigation_throttle.cc
+++ b/content/public/browser/navigation_throttle.cc
@@ -80,6 +80,11 @@
   return NavigationThrottle::PROCEED;
 }
 
+NavigationThrottle::ThrottleCheckResult
+NavigationThrottle::WillCommitWithoutUrlLoader() {
+  return NavigationThrottle::PROCEED;
+}
+
 void NavigationThrottle::Resume() {
   if (resume_callback_) {
     resume_callback_.Run();
diff --git a/content/public/browser/navigation_throttle.h b/content/public/browser/navigation_throttle.h
index fb335d4a..ea059b7 100644
--- a/content/public/browser/navigation_throttle.h
+++ b/content/public/browser/navigation_throttle.h
@@ -169,6 +169,24 @@
   // asynchronously.
   virtual ThrottleCheckResult WillProcessResponse();
 
+  // Called when a navigation is about to immediately commit because there's no
+  // need for a url loader. This includes browser-initiated same-document
+  // navigations, same-document history navigations, about:blank, about:srcdoc,
+  // any other empty document scheme, and MHTML subframes.
+  // Renderer-initiated non-history same-document navigations do NOT go through
+  // this path, because they are handled synchronously in the renderer and the
+  // browser process is only notified after the fact.
+  // BFCache and prerender activation also do NOT go through this path, because
+  // they are considered already loaded when they are activated.
+  // In order to get this event, a NavigationThrottle must register itself with
+  // RegisterNavigationThrottlesForCommitWithoutUrlLoader().
+  // This event is mutually exclusive with WillStartRequest,
+  // WillRedirectRequest, and WillProcessResponse. Only WillFailRequest can
+  // be called after WillCommitWithoutUrlLoader.
+  // Only PROCEED, DEFER, and CANCEL_AND_IGNORE results are supported at this
+  // time.
+  virtual ThrottleCheckResult WillCommitWithoutUrlLoader();
+
   // Returns the name of the throttle for logging purposes. It must not return
   // nullptr.
   virtual const char* GetNameForLogging() = 0;
diff --git a/content/public/test/test_navigation_throttle.cc b/content/public/test/test_navigation_throttle.cc
index c5e7fc60..41c112ba 100644
--- a/content/public/test/test_navigation_throttle.cc
+++ b/content/public/test/test_navigation_throttle.cc
@@ -37,6 +37,11 @@
   return ProcessMethod(WILL_PROCESS_RESPONSE);
 }
 
+NavigationThrottle::ThrottleCheckResult
+TestNavigationThrottle::WillCommitWithoutUrlLoader() {
+  return ProcessMethod(WILL_COMMIT_WITHOUT_URL_LOADER);
+}
+
 const char* TestNavigationThrottle::GetNameForLogging() {
   return "TestNavigationThrottle";
 }
diff --git a/content/public/test/test_navigation_throttle.h b/content/public/test/test_navigation_throttle.h
index 7538fe6..886c504 100644
--- a/content/public/test/test_navigation_throttle.h
+++ b/content/public/test/test_navigation_throttle.h
@@ -25,6 +25,7 @@
     WILL_REDIRECT_REQUEST,
     WILL_FAIL_REQUEST,
     WILL_PROCESS_RESPONSE,
+    WILL_COMMIT_WITHOUT_URL_LOADER,
     NUM_THROTTLE_METHODS
   };
 
@@ -45,6 +46,7 @@
   NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;
   NavigationThrottle::ThrottleCheckResult WillFailRequest() override;
   NavigationThrottle::ThrottleCheckResult WillProcessResponse() override;
+  NavigationThrottle::ThrottleCheckResult WillCommitWithoutUrlLoader() override;
   const char* GetNameForLogging() override;
 
   // Return how often the indicated |method| was called.
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index a0811da..8bb04c9 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -239,6 +239,15 @@
 RendererBlinkPlatformImpl::WrapURLLoaderFactory(
     blink::CrossVariantMojoRemote<network::mojom::URLLoaderFactoryInterfaceBase>
         url_loader_factory) {
+  return WrapURLLoaderFactory(
+      base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
+          mojo::PendingRemote<network::mojom::URLLoaderFactory>(
+              std::move(url_loader_factory))));
+}
+
+std::unique_ptr<blink::WebURLLoaderFactory>
+RendererBlinkPlatformImpl::WrapURLLoaderFactory(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   // Check that there is always a main thread. It used to be possible to run
   // this code with a fuzzer without having a main thread, which is no longer
   // possible now.
@@ -252,10 +261,7 @@
                    return blink::WebString::FromLatin1(h);
                  });
   return std::make_unique<blink::WebURLLoaderFactory>(
-      base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
-          mojo::PendingRemote<network::mojom::URLLoaderFactory>(
-              std::move(url_loader_factory))),
-      web_cors_exempt_header_list,
+      std::move(url_loader_factory), web_cors_exempt_header_list,
       /*terminate_sync_load_event=*/nullptr);
 }
 
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index f9b61ff32..9678df0 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -36,6 +36,10 @@
 #include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
 #endif
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 namespace blink {
 namespace scheduler {
 class WebThreadScheduler;
@@ -208,6 +212,9 @@
       blink::CrossVariantMojoRemote<
           network::mojom::URLLoaderFactoryInterfaceBase> url_loader_factory)
       override;
+  std::unique_ptr<blink::WebURLLoaderFactory> WrapURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override;
   std::unique_ptr<media::MediaLog> GetMediaLog(
       blink::MediaInspectorContext* inspector_context,
       scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner,
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
index 23467ba..a7c189b8 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
+++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.cc
@@ -15,7 +15,6 @@
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 
@@ -104,25 +103,13 @@
     request.SetFetchWindowId(context()->fetch_request_window_id());
 }
 
-std::unique_ptr<blink::WebURLLoader>
-ServiceWorkerNetworkProviderForFrame::CreateURLLoader(
-    const blink::WebURLRequest& request,
-    std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
-        freezable_task_runner_handle,
-    std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
-        unfreezable_task_runner_handle,
-    blink::CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>
-        keep_alive_handle,
-    blink::WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper) {
+scoped_refptr<network::SharedURLLoaderFactory>
+ServiceWorkerNetworkProviderForFrame::GetSubresourceLoaderFactory(
+    const blink::WebURLRequest& request) {
   // RenderThreadImpl is nullptr in some tests.
   if (!RenderThreadImpl::current())
     return nullptr;
 
-  // We need SubresourceLoaderFactory populated in order to create our own
-  // URLLoader for subresource loading.
-  if (!context() || !context()->GetSubresourceLoaderFactory())
-    return nullptr;
-
   // If the URL is not http(s) or otherwise allowed, do not intercept the
   // request. Schemes like 'blob' and 'file' are not eligible to be intercepted
   // by service workers.
@@ -137,6 +124,11 @@
   if (request.GetSkipServiceWorker())
     return nullptr;
 
+  // We need SubresourceLoaderFactory populated.
+  if (!context() || !context()->GetSubresourceLoaderFactory()) {
+    return nullptr;
+  }
+
   // Record use counter for intercepting requests from opaque stylesheets.
   // TODO(crbug.com/898497): Remove this feature usage once we have enough data.
   if (observer_ && request.IsFromOriginDirtyStyleSheet()) {
@@ -145,24 +137,9 @@
             kServiceWorkerInterceptedRequestFromOriginDirtyStyleSheet);
   }
 
-  std::vector<std::string> cors_exempt_header_list =
-      RenderThreadImpl::current()->cors_exempt_header_list();
-  blink::WebVector<blink::WebString> web_cors_exempt_header_list(
-      cors_exempt_header_list.size());
-  std::transform(cors_exempt_header_list.begin(), cors_exempt_header_list.end(),
-                 web_cors_exempt_header_list.begin(), [](const std::string& h) {
-                   return blink::WebString::FromLatin1(h);
-                 });
-
-  // Create our own SubresourceLoader to route the request to the controller
+  // Returns our own SubresourceLoader to route the request to the controller
   // ServiceWorker.
-  return std::make_unique<blink::WebURLLoader>(
-      web_cors_exempt_header_list,
-      /*terminate_sync_load_event=*/nullptr,
-      std::move(freezable_task_runner_handle),
-      std::move(unfreezable_task_runner_handle),
-      context()->GetSubresourceLoaderFactory(), std::move(keep_alive_handle),
-      back_forward_cache_loader_helper);
+  return context()->GetSubresourceLoaderFactory();
 }
 
 blink::mojom::ControllerServiceWorkerMode
diff --git a/content/renderer/service_worker/service_worker_network_provider_for_frame.h b/content/renderer/service_worker/service_worker_network_provider_for_frame.h
index 348e794b..172707a 100644
--- a/content/renderer/service_worker/service_worker_network_provider_for_frame.h
+++ b/content/renderer/service_worker/service_worker_network_provider_for_frame.h
@@ -43,16 +43,8 @@
 
   // Implements WebServiceWorkerNetworkProvider.
   void WillSendRequest(blink::WebURLRequest& request) override;
-  std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
-      const blink::WebURLRequest& request,
-      std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
-          freezable_task_runner_handle,
-      std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
-          unfreezable_task_runner_handle,
-      blink::CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>
-          keep_alive_handle,
-      blink::WebBackForwardCacheLoaderHelper back_forward_cache_loader_helper)
-      override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetSubresourceLoaderFactory(
+      const blink::WebURLRequest& request) override;
   blink::mojom::ControllerServiceWorkerMode GetControllerServiceWorkerMode()
       override;
   blink::mojom::ServiceWorkerFetchHandlerType GetFetchHandlerType() override;
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index a4d5f0a..af0eea2 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -558,8 +558,12 @@
   declare_args() {
     # The bundle identifier. Overriding this will affect the provisioning profile
     # used, and hence will affect the app's capabilities.
-    ios_content_shell_bundle_identifier =
-        "$ios_app_bundle_id_prefix.ios-content-shell"
+    if (ios_use_shared_bundle_id_for_test_apps) {
+      ios_content_shell_bundle_identifier = shared_bundle_id_for_test_apps
+    } else {
+      ios_content_shell_bundle_identifier =
+          "$ios_app_bundle_id_prefix.ios-content-shell"
+    }
 
     # Path to an entitlements file used in ios_content_shell. Can be overridden
     # to provide an alternative.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index f3ba504..c43e0003 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1899,7 +1899,7 @@
       "../browser/direct_sockets/direct_sockets_udp_browsertest.cc",
       "../browser/file_system_access/file_system_access_clipboard_browsertest.cc",
       "../browser/file_system_access/file_system_access_drag_drop_browsertest.cc",
-      "../browser/file_system_access/file_system_access_file_handle_move_browsertest.cc",
+      "../browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc",
       "../browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc",
       "../browser/file_system_access/file_system_chooser_browsertest.cc",
       "../browser/font_preferences_browsertest.cc",
diff --git a/content/test/data/accessibility/html/selectmenu-expected-blink.txt b/content/test/data/accessibility/html/selectmenu-expected-blink.txt
index 08d69fd..065b897e 100644
--- a/content/test/data/accessibility/html/selectmenu-expected-blink.txt
+++ b/content/test/data/accessibility/html/selectmenu-expected-blink.txt
@@ -4,9 +4,10 @@
 ++++++genericContainer
 ++++++++genericContainer ignored
 ++++++++++comboBoxMenuButton collapsed focusable value='Option 1' haspopup=listbox
-++++++++++++genericContainer
-++++++++++++++staticText name='Option 1'
-++++++++++++++++inlineTextBox name='Option 1'
+++++++++++++genericContainer ignored
+++++++++++++++genericContainer
+++++++++++++++++staticText name='Option 1'
+++++++++++++++++++inlineTextBox name='Option 1'
 ++++++++++++genericContainer ignored
 ++++++++++++++genericContainer ignored
 ++++++++genericContainer ignored
diff --git a/content/test/data/accessibility/html/selectmenu-expected-fuchsia.txt b/content/test/data/accessibility/html/selectmenu-expected-fuchsia.txt
index 9101076..802f8fa 100644
--- a/content/test/data/accessibility/html/selectmenu-expected-fuchsia.txt
+++ b/content/test/data/accessibility/html/selectmenu-expected-fuchsia.txt
@@ -4,9 +4,10 @@
 ++++++UNKNOWN
 ++++++++UNKNOWN hidden
 ++++++++++UNKNOWN focusable actions='{DEFAULT}' value='Option 1'
-++++++++++++UNKNOWN actions='{DEFAULT}'
-++++++++++++++STATIC_TEXT label='Option 1' actions='{DEFAULT}'
-++++++++++++++++UNKNOWN label='Option 1'
+++++++++++++UNKNOWN hidden
+++++++++++++++UNKNOWN actions='{DEFAULT}'
+++++++++++++++++STATIC_TEXT label='Option 1' actions='{DEFAULT}'
+++++++++++++++++++UNKNOWN label='Option 1'
 ++++++++++++UNKNOWN hidden
 ++++++++++++++UNKNOWN hidden
 ++++++++UNKNOWN hidden
diff --git a/content/test/data/attribution_reporting/interop/success_debug_aggregatable.json b/content/test/data/attribution_reporting/interop/success_debug_aggregatable.json
new file mode 100644
index 0000000..f94a82d
--- /dev/null
+++ b/content/test/data/attribution_reporting/interop/success_debug_aggregatable.json
@@ -0,0 +1,290 @@
+{
+  "description": "Success debug aggregatable report sent when permitted and debug keys set",
+  "input": {
+    "sources": [
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-source",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://destination.test",
+              "aggregation_keys": {
+                "a": "0x1"
+              },
+              "debug_key": "111"
+            }
+          }
+        }]
+      },
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://another-reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://another-reporter.test/register-source",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://destination.test",
+              "aggregation_keys": {
+                "a": "0x2"
+              }
+            }
+          }
+        }]
+      },
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-source",
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://another-destination.test",
+              "aggregation_keys": {
+                "a": "0x3"
+              },
+              "debug_key": "222"
+            }
+          }
+        }]
+      }
+    ],
+    "triggers": [
+      // Will result in a debug report.
+      {
+        "timestamp": "1643235574000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x10"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 111
+              },
+              "debug_key": "333"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as debug key is not set.
+      {
+        "timestamp": "1643235575000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x10"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 222
+              }
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as debug permission is not set.
+      {
+        "timestamp": "1643235576000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x10"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 333
+              },
+              "debug_key": "444"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as source debug key is not set.
+      {
+        "timestamp": "1643235577000",
+        "registration_request": {
+          "attribution_src_url": "https://another-reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://another-reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x10"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 444
+              },
+              "debug_key": "555"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as source debug permission is not set.
+      {
+        "timestamp": "1643235578000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://another-destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x10"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 555
+              },
+              "debug_key": "666"
+            }
+          }
+        }]
+      }
+    ]
+  },
+  "output": {
+    "aggregatable_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x11",
+              "value": 111
+            }
+          ],
+          "source_debug_key": "111",
+          "trigger_debug_key": "333"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239174000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x11",
+              "value": 222
+            }
+          ],
+          "source_debug_key": "111"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239175000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x11",
+              "value": 333
+            }
+          ],
+          "source_debug_key": "111"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239176000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x12",
+              "value": 444
+            }
+          ],
+          "trigger_debug_key": "555"
+        },
+        "report_url": "https://another-reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239177000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://another-destination.test",
+          "histograms": [
+            {
+              "key": "0x13",
+              "value": 555
+            }
+          ],
+          "trigger_debug_key": "666"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239178000"
+      }
+    ],
+    "debug_aggregatable_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x11",
+              "value": 111
+            }
+          ],
+          "source_debug_key": "111",
+          "trigger_debug_key": "333"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/debug/report-aggregate-attribution",
+        "report_time": "1643235574000"
+      }
+    ]
+  }
+}
diff --git a/content/test/data/attribution_reporting/interop/success_debug_event_level.json b/content/test/data/attribution_reporting/interop/success_debug_event_level.json
new file mode 100644
index 0000000..e021172
--- /dev/null
+++ b/content/test/data/attribution_reporting/interop/success_debug_event_level.json
@@ -0,0 +1,258 @@
+{
+  "description": "Success debug event-level report sent when permitted and debug keys set",
+  "input": {
+    "sources": [
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-source",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://destination.test",
+              "source_event_id": "123",
+              "debug_key": "111"
+            }
+          }
+        }]
+      },
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://another-reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://another-reporter.test/register-source",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://destination.test",
+              "source_event_id": "456"
+            }
+          }
+        }]
+      },
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-source",
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://another-destination.test",
+              "source_event_id": "789",
+              "debug_key": "222"
+            }
+          }
+        }]
+      }
+    ],
+    "triggers": [
+      // Will result in a debug report.
+      {
+        "timestamp": "1643235574000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "7"
+                }
+              ],
+              "debug_key": "333"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as debug key is not set.
+      {
+        "timestamp": "1643235575000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "6"
+                }
+              ]
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as debug permission is not set.
+      {
+        "timestamp": "1643235576000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "5"
+                }
+              ],
+              "debug_key": "444"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as source debug key is not set.
+      {
+        "timestamp": "1643235577000",
+        "registration_request": {
+          "attribution_src_url": "https://another-reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://another-reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "4"
+                }
+              ],
+              "debug_key": "555"
+            }
+          }
+        }]
+      },
+      // Will not result in a debug report as source debug permission is not set.
+      {
+        "timestamp": "1643235578000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://another-destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "debug_permission": true,
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "3"
+                }
+              ],
+              "debug_key": "666"
+            }
+          }
+        }]
+      }
+    ]
+  },
+  "output": {
+    "event_level_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "7",
+          "source_debug_key": "111",
+          "trigger_debug_key": "333"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643411973000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "6",
+          "source_debug_key": "111"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643411973000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "5",
+          "source_debug_key": "111"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643411973000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "456",
+          "source_type": "navigation",
+          "trigger_data": "4",
+          "trigger_debug_key": "555"
+        },
+        "report_url": "https://another-reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643411973000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://another-destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "789",
+          "source_type": "navigation",
+          "trigger_data": "3",
+          "trigger_debug_key": "666"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643411973000"
+      }
+    ],
+    "debug_event_level_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "scheduled_report_time": "1643411973",
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "7",
+          "source_debug_key": "111",
+          "trigger_debug_key": "333"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/debug/report-event-attribution",
+        "report_time": "1643235574000"
+      }
+    ]
+  }
+}
diff --git a/content/test/data/gpu/webcodecs/audio-encode-decode.html b/content/test/data/gpu/webcodecs/audio-encode-decode.html
index 3ec01e5..816d889 100644
--- a/content/test/data/gpu/webcodecs/audio-encode-decode.html
+++ b/content/test/data/gpu/webcodecs/audio-encode-decode.html
@@ -38,8 +38,14 @@
     codec: args.codec,
     sampleRate: args.sample_rate,
     numberOfChannels: args.channels,
-    bitrate: 96000,
+    bitrate: 96000
   };
+
+  if (args.aac_format) {
+    config.aac = {
+      format : args.aac_format
+    };
+  }
   let decoder_config = null;
 
   let support = await AudioEncoder.isConfigSupported(config);
@@ -92,6 +98,13 @@
   timestamp_us += 2 * (2112 / config.sampleRate) * 1_000_000;
 
   TEST.assert(decoder_config != null, "No decoder config");
+  if (args.aac_format == "adts") {
+    TEST.assert(decoder_config.description == null, "ADTS should carry desc");
+  } else if (args.aac_format == "aac") {
+    TEST.assert(decoder_config.description != null, "AAC should carry desc");
+    TEST.assert(decoder_config.description.byteLength > 1,
+                "AAC desc is too short");
+  }
   TEST.assert(outputs.length > 0, "no outputs");
   TEST.assert(outputs[0].timestamp == 0, "first chunk timestamp non zero");
 
@@ -102,6 +115,12 @@
         `chunk timestamp is too small. ${timestamp_us} vs ${chunk.timestamp}`);
     TEST.assert(chunk.duration >= 0, "chunk duration is zero");
     total_encoded_duration += chunk.duration;
+    let buf = new ArrayBuffer(chunk.byteLength);
+    chunk.copyTo(buf);
+    if (args.aac_format == "adts") {
+      let adts_header = new DataView(buf).getUint8(0);
+      TEST.assert(adts_header == 0xff,  "Incorrect ADTS header");
+    }
   }
 
   // The total duration might be padded with silence.
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
index 858623ec1..728a082 100644
--- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py
+++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -88,7 +88,19 @@
         'sample_rate':
         48000,
         'channels':
-        2
+        2,
+        'aac_format':
+        'aac'
+    }])
+    yield ('WebCodecs_AudioEncoding_AAC_LC_ADTS', 'audio-encode-decode.html', [{
+        'codec':
+        'mp4a.67',
+        'sample_rate':
+        48000,
+        'channels':
+        2,
+        'aac_format':
+        'adts'
     }])
 
   @classmethod
diff --git a/docs/navigation-request-navigation-state.gv b/docs/navigation-request-navigation-state.gv
index e8ceef28..984b0202 100644
--- a/docs/navigation-request-navigation-state.gv
+++ b/docs/navigation-request-navigation-state.gv
@@ -6,12 +6,13 @@
   NOT_STARTED -> {WAITING_FOR_RENDERER_RESPONSE, WILL_START_NAVIGATION, WILL_START_REQUEST};
   WAITING_FOR_RENDERER_RESPONSE -> {WILL_START_NAVIGATION, WILL_START_REQUEST};
   WILL_START_NAVIGATION -> {WILL_START_REQUEST, WILL_FAIL_REQUEST};
-  WILL_START_REQUEST -> {WILL_REDIRECT_REQUEST, WILL_PROCESS_RESPONSE, READY_TO_COMMIT, DID_COMMIT, CANCELING, WILL_FAIL_REQUEST, DID_COMMIT_ERROR_PAGE};
+  WILL_START_REQUEST -> {WILL_REDIRECT_REQUEST, WILL_PROCESS_RESPONSE, WILL_COMMIT_WITHOUT_URL_LOADER, READY_TO_COMMIT, DID_COMMIT, CANCELING, WILL_FAIL_REQUEST, DID_COMMIT_ERROR_PAGE};
   WILL_REDIRECT_REQUEST -> {WILL_REDIRECT_REQUEST, WILL_PROCESS_RESPONSE, CANCELING, WILL_FAIL_REQUEST};
   WILL_PROCESS_RESPONSE -> {READY_TO_COMMIT, CANCELING, WILL_FAIL_REQUEST};
+  WILL_COMMIT_WITHOUT_URL_LOADER -> {READY_TO_COMMIT, CANCELING, WILL_FAIL_REQUEST};
   READY_TO_COMMIT -> {NOT_STARTED, DID_COMMIT, DID_COMMIT_ERROR_PAGE};
-  DID_COMMIT -> {};
   CANCELING -> {READY_TO_COMMIT, WILL_FAIL_REQUEST};
   WILL_FAIL_REQUEST -> {READY_TO_COMMIT, CANCELING, WILL_FAIL_REQUEST};
+  DID_COMMIT -> {};
   DID_COMMIT_ERROR_PAGE -> {};
 }
diff --git a/docs/navigation-request-navigation-state.png b/docs/navigation-request-navigation-state.png
index 572a0ce..aa2430d0 100644
--- a/docs/navigation-request-navigation-state.png
+++ b/docs/navigation-request-navigation-state.png
Binary files differ
diff --git a/docs/navigation.md b/docs/navigation.md
index d481150..3e4a425 100644
--- a/docs/navigation.md
+++ b/docs/navigation.md
@@ -160,10 +160,17 @@
 `NavigationThrottleRunner::RegisterNavigationThrottles` or
 `ContentBrowserClient::CreateThrottlesForNavigation`.
 
-NavigationThrottles are only invoked on navigations that require a URLLoader
-(see NavigationRequest::NeedsUrlLoader).  This means they don't typically run in
-cases like same-document navigations, about:blank, etc. They are also not run in
-page-activation navigations, such as activating a prerendered page or restoring
-a page from the back-forward cache.
+The most common NavigationThrottles events are `WillStartRequest`,
+`WillRedirectRequest`, and `WillProcessResponse`, which allow intercepting a
+navigation before sending the network request, during any redirects, and after
+receiving the response. These events are only invoked on navigations that
+require a URLLoader (see NavigationRequest::NeedsUrlLoader).
+A NavigationThrottle that wishes to intercept a non-URLLoader navigation
+(same-document navigations, about:blank, etc.) should register itself in
+`NavigationThrottleRunner::RegisterNavigationThrottlesForCommitWithoutUrlLoader`,
+and will get a single `WillCommitWithoutUrlLoader` event instead of the full
+set of events centered on network requests. Page-activation navigations, such
+as activating a prerendered page or restoring a page from the back-forward
+cache, skip NavigationThrottles entirely.
 
 [WebContentsObserver]: https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/web_contents_observer.h
diff --git a/gpu/GRAPHICS_TEAM_OWNERS b/gpu/GRAPHICS_TEAM_OWNERS
index 8080ca3..60e0ff7d 100644
--- a/gpu/GRAPHICS_TEAM_OWNERS
+++ b/gpu/GRAPHICS_TEAM_OWNERS
@@ -5,15 +5,12 @@
 vmiura@chromium.org
 geofflang@chromium.org
 fserb@chromium.org
-sadrul@chromium.org
 rockot@google.com
 rjkroege@chromium.org
 zmo@chromium.org
 
 # ANGLE team
-jmadill@chromium.org
 jonahr@chromium.org
-srisser@chromium.org
 syoussefi@chromium.org
 ynovikov@chromium.org
 
@@ -25,13 +22,10 @@
 yiyix@chromium.org
 
 # Metrics team
-behdadb@chromium.org
 jonross@chromium.org
 mjzhang@chromium.org
-mohsen@chromium.org
 
 # Platforms Team
-backer@chromium.org
 boliu@chromium.org
 ccameron@chromium.org
 fangzhoug@chromium.org
@@ -41,7 +35,6 @@
 magchen@chromium.org
 penghuang@chromium.org
 petermcneeley@chromium.org
-rivr@chromium.org
 sunnyps@chromium.org
 vasilyt@chromium.org
 vikassoni@chromium.org
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 5cd7459e..8427ca3b 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -128,11 +128,10 @@
 
   std::unique_ptr<TransferBuffer> transfer_buffer =
       std::make_unique<TransferBuffer>(helper_);
-  if (!transfer_buffer->Initialize(limits.start_transfer_buffer_size,
-                                   /* start offset */ 0,
-                                   limits.min_transfer_buffer_size,
-                                   limits.max_transfer_buffer_size,
-                                   /* alignment */ 8)) {
+  if (!transfer_buffer->Initialize(
+          limits.start_transfer_buffer_size,
+          /* start offset */ 0, limits.min_transfer_buffer_size,
+          limits.max_transfer_buffer_size, kAlignment)) {
     return gpu::ContextResult::kFatalFailure;
   }
 
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 0dd275c..9dbc018 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -2820,17 +2820,17 @@
     return;
   }
 
-  alignas(
-      cc::PaintOpBuffer::kPaintOpAlign) char data[sizeof(cc::LargestPaintOp)];
+  alignas(cc::PaintOpBuffer::kPaintOpAlign) char
+      data[cc::kLargestPaintOpAlignedSize];
 
   size_t paint_buffer_size = raster_shm_size;
   gl::ScopedProgressReporter report_progress(
       shared_context_state_->progress_reporter());
   while (paint_buffer_size > 0) {
     size_t skip = 0;
-    cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
-        paint_buffer_memory, paint_buffer_size, &data[0],
-        sizeof(cc::LargestPaintOp), &skip, options);
+    cc::PaintOp* deserialized_op =
+        cc::PaintOp::Deserialize(paint_buffer_memory, paint_buffer_size, data,
+                                 std::size(data), &skip, options);
     if (!deserialized_op) {
       LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glRasterCHROMIUM",
                          "RasterCHROMIUM: serialization failure");
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
index 1e70198..7a2ecea 100644
--- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
@@ -201,6 +201,11 @@
 
     passthrough_texture_.reset();
     egl_image_.reset();
+
+    if (need_gl_finish_before_destroy_ && have_context()) {
+      gl::GLApi* api = gl::g_current_gl_context;
+      api->glFinishFn();
+    }
   }
 
   if (vulkan_image_) {
@@ -399,8 +404,9 @@
     --gl_reads_in_process_;
 
     // For the last GL read access, release texture from ANGLE.
-    if (gl_reads_in_process_ == 0)
+    if (gl_reads_in_process_ == 0) {
       ReleaseTextureANGLE();
+    }
 
     return;
   }
@@ -427,6 +433,9 @@
   GLuint texture = passthrough_texture_->service_id();
   // Release the texture from ANGLE, so it can be used elsewhere.
   api->glReleaseTexturesANGLEFn(1, &texture, &layout_);
+  // Releasing the texture will submit all related works to queue, so to be
+  // safe, glFinish() should be called before releasing the VkImage.
+  need_gl_finish_before_destroy_ = true;
 }
 
 void AngleVulkanImageBacking::PrepareBackendTexture() {
@@ -506,6 +515,11 @@
       return;
   }
 
+  // The backing is used by skia, so skia should submit related work to the
+  // queue, and we can use vulkan fence helper to release the VkImage.
+  // glFinish() is not necessary anymore.
+  need_gl_finish_before_destroy_ = false;
+
   SyncImageLayoutFromBackendTexture();
 
   if (gl_reads_in_process_ > 0) {
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h
index daec0c06..8d28076 100644
--- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.h
@@ -77,6 +77,7 @@
   bool is_gl_write_in_process_ = false;
   int skia_reads_in_process_ = 0;
   int gl_reads_in_process_ = 0;
+  bool need_gl_finish_before_destroy_ = false;
 };
 
 }  // namespace gpu
diff --git a/headless/test/data/protocol/input/input-clipboard-ops-expected.txt b/headless/test/data/protocol/input/input-clipboard-ops-expected.txt
index 79fdbfc..17f868e6 100644
--- a/headless/test/data/protocol/input/input-clipboard-ops-expected.txt
+++ b/headless/test/data/protocol/input/input-clipboard-ops-expected.txt
@@ -1,4 +1,4 @@
 Tests input field clipboard operations.
 input: input_value
-input: abc
-input: input_value
\ No newline at end of file
+input: 123
+input: 123input_value
\ No newline at end of file
diff --git a/headless/test/data/protocol/input/input-clipboard-ops.js b/headless/test/data/protocol/input/input-clipboard-ops.js
index 682d682..3363661b 100644
--- a/headless/test/data/protocol/input/input-clipboard-ops.js
+++ b/headless/test/data/protocol/input/input-clipboard-ops.js
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  const {page, session, dp} = await testRunner.startBlank(
-      `Tests input field clipboard operations.`);
+  const html = `<!doctype html>
+    <html><body>
+    <input type="text" id="input" value="input_value" autofocus>
+    </body></html>
+  `;
 
-  await dp.Page.enable();
-  dp.Page.navigate({url: testRunner.url('/resources/input.html')});
-  await dp.Page.onceLoadEventFired();
+  const {page, session, dp} = await testRunner.startHTML(
+      html, `Tests input field clipboard operations.`);
 
   async function logElementValue(id) {
     const value = await session.evaluate(`
@@ -34,19 +36,23 @@
     });
   }
 
-  await logElementValue("input");
-  await sendKey('a', 65, 2, ["selectAll"]);
-  await sendKey('c', 67, 2, ["copy"]);
+  const modControl = 2;
+  const modCommand = 4;
+  const mod = navigator.platform.includes('Mac') ? modCommand : modControl;
 
-  await sendKey('a', 65);
-  await sendKey('b', 66);
-  await sendKey('c', 67);
+  await logElementValue("input");
+  await sendKey('a', 65, mod, ['selectAll']);
+  await sendKey('c', 67, mod, ['copy']);
+
+  await sendKey('1', 61);
+  await sendKey('2', 62);
+  await sendKey('3', 63);
   await logElementValue("input");
 
-  await sendKey('a', 65, 2, ["selectAll"]);
-  await sendKey('c', 67, 2, ["paste"]);
+  // Don't send Ctrl+A here because this would cause clipboard copy on
+  // systems that support selection clipboard, e.g. Linux.
+  await sendKey('v', 86, mod, ['paste']);
   await logElementValue("input");
 
   testRunner.completeTest();
 })
-
diff --git a/headless/test/data/protocol/input/resources/input.html b/headless/test/data/protocol/input/resources/input.html
deleted file mode 100644
index a750341..0000000
--- a/headless/test/data/protocol/input/resources/input.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<html> <body>
-  <input type="text" id="input" value="input_value" autofocus>
-</body></html>
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index a8dae8c..c6e76ad2 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -302,8 +302,8 @@
 
 HEADLESS_PROTOCOL_TEST(DragStarted, "input/dragIntercepted.js")
 
-// https://crbug.com/1204620
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+// https://crbug.com/1414190
+#if BUILDFLAG(IS_MAC)
 #define MAYBE_InputClipboardOps DISABLED_InputClipboardOps
 #else
 #define MAYBE_InputClipboardOps InputClipboardOps
diff --git a/infra/archive_config/linux-chromiumos-full.json b/infra/archive_config/linux-chromiumos-full.json
index 4cf51096..0db71b1 100644
--- a/infra/archive_config/linux-chromiumos-full.json
+++ b/infra/archive_config/linux-chromiumos-full.json
@@ -9,7 +9,12 @@
                 "chrome_crashpad_handler",
                 "icudtl.dat",
                 "keyboard_resources.pak",
+                "libEGL.so",
+                "libGLESv2.so",
                 "libminigbm.so",
+                "libmojo_core.so",
+                "libmojo_core_arc32.so",
+                "libmojo_core_arc64.so",
                 "MEIPreload/manifest.json",
                 "MEIPreload/preloaded_data.pb",
                 "nacl_helper",
@@ -21,7 +26,7 @@
                 "xdg-mime",
                 "xdg-settings"
             ],
-            "dirs": ["ClearKeyCdm", "locales", "resources"],
+            "dirs": ["ClearKeyCdm", "locales", "resources", "mojo_service_manager"],
             "rename_dirs": [
                 {"from_dir": ".", "to_dir": "chrome-chromeos"}
             ],
diff --git a/infra/config/generated/builders/ci/Mac Builder Next/properties.json b/infra/config/generated/builders/ci/Mac Builder Next/properties.json
index 4fbdcc1..59401df 100644
--- a/infra/config/generated/builders/ci/Mac Builder Next/properties.json
+++ b/infra/config/generated/builders/ci/Mac Builder Next/properties.json
@@ -17,7 +17,7 @@
                 "apply_configs": [
                   "mb"
                 ],
-                "build_config": "Release",
+                "build_config": "Debug",
                 "config": "chromium",
                 "target_arch": "arm",
                 "target_bits": 64
diff --git a/infra/config/generated/builders/ci/linux-js-code-coverage/properties.json b/infra/config/generated/builders/ci/linux-js-code-coverage/properties.json
index 8cac476..5a2e7de 100644
--- a/infra/config/generated/builders/ci/linux-js-code-coverage/properties.json
+++ b/infra/config/generated/builders/ci/linux-js-code-coverage/properties.json
@@ -45,6 +45,7 @@
     }
   },
   "$build/code_coverage": {
+    "export_coverage_to_zoss": true,
     "use_javascript_coverage": true
   },
   "$build/reclient": {
diff --git a/infra/config/generated/builders/try/android-12-x64-rel/properties.json b/infra/config/generated/builders/try/android-12-x64-rel/properties.json
index 2341f30c..f7e9fef 100644
--- a/infra/config/generated/builders/try/android-12-x64-rel/properties.json
+++ b/infra/config/generated/builders/try/android-12-x64-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "android-12-x64-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/android-arm64-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/android-arm64-rel-inverse-fyi/properties.json
index 8d211f28..547487f 100644
--- a/infra/config/generated/builders/try/android-arm64-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/android-arm64-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "android-arm64-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/android-arm64-rel/properties.json b/infra/config/generated/builders/try/android-arm64-rel/properties.json
index 8d211f28..547487f 100644
--- a/infra/config/generated/builders/try/android-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/android-arm64-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "android-arm64-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/android-nougat-x86-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/android-nougat-x86-rel-inverse-fyi/properties.json
index 27cc6358..b37bead 100644
--- a/infra/config/generated/builders/try/android-nougat-x86-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/android-nougat-x86-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "android-nougat-x86-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/android-nougat-x86-rel/properties.json b/infra/config/generated/builders/try/android-nougat-x86-rel/properties.json
index 27cc6358..b37bead 100644
--- a/infra/config/generated/builders/try/android-nougat-x86-rel/properties.json
+++ b/infra/config/generated/builders/try/android-nougat-x86-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "android-nougat-x86-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json b/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
index a508abe..fbbb60e 100644
--- a/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
+++ b/infra/config/generated/builders/try/chromeos-amd64-generic-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "chromeos-amd64-generic-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
index a78a8e3..ad7bcfdf 100644
--- a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "fuchsia-arm64-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
index ee33e86..50e84fc 100644
--- a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "fuchsia-x64-cast-receiver-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/ios-simulator/properties.json b/infra/config/generated/builders/try/ios-simulator/properties.json
index 4bd8399..e47e00ae 100644
--- a/infra/config/generated/builders/try/ios-simulator/properties.json
+++ b/infra/config/generated/builders/try/ios-simulator/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "ios-simulator-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/lacros-amd64-generic-rel-orchestrator/properties.json b/infra/config/generated/builders/try/lacros-amd64-generic-rel-orchestrator/properties.json
index 8cb1356..fbef280a 100644
--- a/infra/config/generated/builders/try/lacros-amd64-generic-rel-orchestrator/properties.json
+++ b/infra/config/generated/builders/try/lacros-amd64-generic-rel-orchestrator/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "lacros-amd64-generic-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-chromeos-rel/properties.json b/infra/config/generated/builders/try/linux-chromeos-rel/properties.json
index 15f9eb6..c3e15d6 100644
--- a/infra/config/generated/builders/try/linux-chromeos-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-chromeos-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-chromeos-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-lacros-rel/properties.json b/infra/config/generated/builders/try/linux-lacros-rel/properties.json
index 52e3b47f7..0ba42f1 100644
--- a/infra/config/generated/builders/try/linux-lacros-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-lacros-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-lacros-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/linux-rel-inverse-fyi/properties.json
index 03d03cb..591ea80 100644
--- a/infra/config/generated/builders/try/linux-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/linux-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-rel/properties.json b/infra/config/generated/builders/try/linux-rel/properties.json
index 03d03cb..591ea80 100644
--- a/infra/config/generated/builders/try/linux-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-wayland-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/linux-wayland-rel-inverse-fyi/properties.json
index 45eea6f..275ecf99 100644
--- a/infra/config/generated/builders/try/linux-wayland-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/linux-wayland-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-wayland-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux-wayland-rel/properties.json b/infra/config/generated/builders/try/linux-wayland-rel/properties.json
index 45eea6f..275ecf99 100644
--- a/infra/config/generated/builders/try/linux-wayland-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-wayland-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux-wayland-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-inverse-fyi/properties.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-inverse-fyi/properties.json
index e65ed2a..ea99e46e 100644
--- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux_chromium_asan_rel_ng-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/properties.json
index e65ed2a..ea99e46e 100644
--- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux_chromium_asan_rel_ng-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-inverse-fyi/properties.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-inverse-fyi/properties.json
index e7490ef3..d1fe41a 100644
--- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux_chromium_tsan_rel_ng-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
index e7490ef3..d1fe41a 100644
--- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "linux_chromium_tsan_rel_ng-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/mac-builder-next-rel/properties.json b/infra/config/generated/builders/try/mac-builder-next-rel/properties.json
index dc0d327e..f39d9cb 100644
--- a/infra/config/generated/builders/try/mac-builder-next-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-builder-next-rel/properties.json
@@ -17,7 +17,7 @@
                 "apply_configs": [
                   "mb"
                 ],
-                "build_config": "Release",
+                "build_config": "Debug",
                 "config": "chromium",
                 "target_arch": "arm",
                 "target_bits": 64
diff --git a/infra/config/generated/builders/try/mac-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/mac-rel-inverse-fyi/properties.json
index 760c6f5..4757703 100644
--- a/infra/config/generated/builders/try/mac-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/mac-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "mac-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/mac-rel/properties.json b/infra/config/generated/builders/try/mac-rel/properties.json
index 760c6f5..4757703 100644
--- a/infra/config/generated/builders/try/mac-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "mac-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/mac12-arm64-rel/properties.json b/infra/config/generated/builders/try/mac12-arm64-rel/properties.json
index 06a90182..c435c0a 100644
--- a/infra/config/generated/builders/try/mac12-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/mac12-arm64-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "mac12-arm64-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/win-rel-inverse-fyi/properties.json b/infra/config/generated/builders/try/win-rel-inverse-fyi/properties.json
index 14f1682..aa57c503 100644
--- a/infra/config/generated/builders/try/win-rel-inverse-fyi/properties.json
+++ b/infra/config/generated/builders/try/win-rel-inverse-fyi/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "win-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/builders/try/win-rel/properties.json b/infra/config/generated/builders/try/win-rel/properties.json
index 14f1682..aa57c503 100644
--- a/infra/config/generated/builders/try/win-rel/properties.json
+++ b/infra/config/generated/builders/try/win-rel/properties.json
@@ -1,7 +1,7 @@
 {
   "$build/chromium_orchestrator": {
     "compilator": "win-rel-compilator",
-    "compilator_watcher_git_revision": "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+    "compilator_watcher_git_revision": "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
   },
   "$build/chromium_tests_builder_config": {
     "builder_config": {
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index 388833f8..bced30d 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.37.2"
+  version: "1.38.1"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/infra/config/lib/orchestrator.star b/infra/config/lib/orchestrator.star
index 314b429..03f0f22 100644
--- a/infra/config/lib/orchestrator.star
+++ b/infra/config/lib/orchestrator.star
@@ -16,7 +16,7 @@
 
 # infra/infra git revision to use for the compilator_watcher luciexe sub_build
 # Used by chromium orchestrators
-_COMPILATOR_WATCHER_GIT_REVISION = "ed88e894b6a9f09ab3604fb3276c5810389cbcf4"
+_COMPILATOR_WATCHER_GIT_REVISION = "e6d08be3fd589d4f222dae5d18dbc972e6117b23"
 
 # Nodes for the definition of an orchestrator builder
 _ORCHESTRATOR = nodes.create_bucket_scoped_node_type("orchestrator")
diff --git a/infra/config/subprojects/chromium/ci/chromium.coverage.star b/infra/config/subprojects/chromium/ci/chromium.coverage.star
index b1b7160..b84a513 100644
--- a/infra/config/subprojects/chromium/ci/chromium.coverage.star
+++ b/infra/config/subprojects/chromium/ci/chromium.coverage.star
@@ -251,6 +251,7 @@
     ],
     reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI,
     use_javascript_coverage = True,
+    export_coverage_to_zoss = True,
 )
 
 coverage_builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 306c83ab..eedc56d 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -2278,7 +2278,7 @@
         chromium_config = builder_config.chromium_config(
             config = "chromium",
             apply_configs = ["mb"],
-            build_config = builder_config.build_config.RELEASE,
+            build_config = builder_config.build_config.DEBUG,
             target_arch = builder_config.target_arch.ARM,
             target_bits = 64,
         ),
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper.h b/ios/chrome/browser/ntp/new_tab_page_tab_helper.h
index 59a5dfc..82e03ac 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper.h
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper.h
@@ -83,8 +83,9 @@
                           web::NavigationContext* navigation_context) override;
   void DidFinishNavigation(web::WebState* web_state,
                            web::NavigationContext* navigation_context) override;
-  void DidStopLoading(web::WebState* web_state) override;
-  void DidStartLoading(web::WebState* web_state) override;
+  void PageLoaded(
+      web::WebState* web_state,
+      web::PageLoadCompletionStatus load_completion_status) override;
 
   // Enable or disable the tab helper.
   void SetActive(bool active);
@@ -95,8 +96,8 @@
   // The WebState with which this object is associated.
   web::WebState* web_state_ = nullptr;
 
-  // `YES` if the current tab helper is active.
-  BOOL active_ = NO;
+  // `true` if the current tab helper is active.
+  bool active_ = false;
 
   // `YES` if the NTP for this WebState should be configured to show the Start
   // Surface.
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
index adfa0fd..31ab0a7 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper.mm
@@ -152,32 +152,27 @@
   }
 
   UpdateItem(web_state_->GetNavigationManager()->GetLastCommittedItem());
-  SetActive(IsNTPURL(web_state->GetLastCommittedURL()));
 }
 
-void NewTabPageTabHelper::DidStartLoading(web::WebState* web_state) {
-  // This is needed to avoid flashing the NTP when loading error pages.
-  if (!IsNTPURL(web_state->GetVisibleURL())) {
-    SetActive(false);
-  }
-}
-
-void NewTabPageTabHelper::DidStopLoading(web::WebState* web_state) {
-  if (IsNTPURL(web_state->GetVisibleURL())) {
-    SetActive(true);
+void NewTabPageTabHelper::PageLoaded(
+    web::WebState* web_state,
+    web::PageLoadCompletionStatus load_completion_status) {
+  if (load_completion_status == web::PageLoadCompletionStatus::SUCCESS) {
+    if (IsNTPURL(web_state->GetVisibleURL())) {
+      SetActive(true);
+    }
   }
 }
 
 #pragma mark - Private
 
 void NewTabPageTabHelper::SetActive(bool active) {
-  bool was_active = active_;
+  if (active_ == active) {
+    return;
+  }
   active_ = active;
 
-  // Tell `delegate_` to show or hide the NTP, if necessary.
-  if (active_ != was_active) {
-    [delegate_ newTabPageHelperDidChangeVisibility:this forWebState:web_state_];
-  }
+  [delegate_ newTabPageHelperDidChangeVisibility:this forWebState:web_state_];
 }
 
 WEB_STATE_USER_DATA_KEY_IMPL(NewTabPageTabHelper)
diff --git a/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm b/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
index 452d805..e6c2195 100644
--- a/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
+++ b/ios/chrome/browser/ntp/new_tab_page_tab_helper_unittest.mm
@@ -123,7 +123,7 @@
   web::FakeNavigationContext context;
   context.SetUrl(url);
   fake_navigation_manager_->SetLastCommittedItem(pending_item_.get());
-  fake_web_state_.OnNavigationFinished(&context);
+  fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
   EXPECT_TRUE(tab_helper()->IsActive());
 
   GURL not_ntp_url(kTestURL);
@@ -131,16 +131,17 @@
   context.SetUrl(not_ntp_url);
   pending_item_->SetURL(not_ntp_url);
   fake_web_state_.OnNavigationStarted(&context);
+  fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
   EXPECT_FALSE(tab_helper()->IsActive());
   fake_navigation_manager_->SetLastCommittedItem(pending_item_.get());
-  fake_web_state_.OnNavigationFinished(&context);
+  fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
   EXPECT_FALSE(tab_helper()->IsActive());
 
   context.SetUrl(url);
   pending_item_->SetURL(url);
   fake_web_state_.SetCurrentURL(url);
   fake_navigation_manager_->SetLastCommittedItem(pending_item_.get());
-  fake_web_state_.OnNavigationFinished(&context);
+  fake_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
   EXPECT_TRUE(tab_helper()->IsActive());
 
   context.SetUrl(not_ntp_url);
@@ -172,6 +173,5 @@
   fake_web_state_.SetCurrentURL(not_ntp_url);
   fake_navigation_manager_->SetLastCommittedItem(pending_item_.get());
   fake_web_state_.OnNavigationFinished(&context);
-  EXPECT_FALSE(tab_helper()->IsActive());
   EXPECT_EQ(GURL(kTestURL), pending_item_->GetVirtualURL());
 }
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
index f9e6f0e..4eede526 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
@@ -37,6 +37,7 @@
 #import "ios/chrome/browser/web/web_state_delegate_browser_agent.h"
 #import "ios/chrome/browser/web_state_list/tab_insertion_browser_agent.h"
 #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
+#import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -169,10 +170,14 @@
     UrlLoadParams urlLoadParams = UrlLoadParams::InCurrentTab(url);
     urlLoadingBrowserAgent->Load(urlLoadParams);
 
-    // Force the DidStopLoading callback.
+    // Force the WebStateObserver callbacks that simulate a page load.
     web::WebStateObserver* ntpHelper =
         (web::WebStateObserver*)NewTabPageTabHelper::FromWebState(web_state);
-    ntpHelper->DidStopLoading(web_state);
+    web::FakeNavigationContext context;
+    context.SetUrl(url);
+    context.SetIsSameDocument(false);
+    ntpHelper->DidStartNavigation(web_state, &context);
+    ntpHelper->PageLoaded(web_state, web::PageLoadCompletionStatus::SUCCESS);
   }
 
   IOSChromeScopedTestingLocalState local_state_;
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 015a3c2..2bc602d 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2644,19 +2644,6 @@
   }
 }
 
-- (void)tabDidLoadURL:(GURL)URL
-       transitionType:(ui::PageTransition)transitionType {
-  // Deactivate the NTP immediately on a load to hide the NTP quickly, but
-  // after calling UrlLoadingService::Load.  Otherwise, if the
-  // webState has never been visible (such as during startup with an NTP), it's
-  // possible the webView can trigger a unnecessary load for chrome://newtab.
-  if (self.currentWebState->GetVisibleURL() != kChromeUINewTabURL) {
-    if (self.isNTPActiveForCurrentWebState) {
-      NewTabPageTabHelper::FromWebState(self.currentWebState)->Deactivate();
-    }
-  }
-}
-
 - (void)newTabWillLoadURL:(GURL)URL isUserInitiated:(BOOL)isUserInitiated {
   if (isUserInitiated) {
     // Send either the "New Tab Opened" or "New Incognito Tab" opened to the
diff --git a/ios/chrome/browser/ui/lens/lens_coordinator.mm b/ios/chrome/browser/ui/lens/lens_coordinator.mm
index 7a80e0ee..449c3d0e 100644
--- a/ios/chrome/browser/ui/lens/lens_coordinator.mm
+++ b/ios/chrome/browser/ui/lens/lens_coordinator.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/lens/lens_coordinator.h"
 
 #import "base/strings/sys_string_conversions.h"
-#import "base/task/sequenced_task_runner.h"
 #import "ios/chrome/browser/application_context/application_context.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
@@ -195,8 +194,8 @@
     contentArea = [delegate webContentAreaForLensCoordinator:self];
   }
 
-  UIViewController* viewController = [lensController
-      inputSelectionViewControllerWithWebContentFrame:contentArea];
+  UIViewController* viewController =
+      [lensController inputSelectionViewController];
 
   // TODO(crbug.com/1353430): the returned UIViewController
   // must not be nil, remove this check once the internal
@@ -284,6 +283,15 @@
   [self dismissViewController];
 }
 
+- (CGRect)webContentFrame {
+  id<LensPresentationDelegate> delegate = self.delegate;
+  if (delegate) {
+    return [delegate webContentAreaForLensCoordinator:self];
+  }
+
+  return [UIScreen mainScreen].bounds;
+}
+
 #pragma mark - WebStateListObserving methods
 
 - (void)webStateList:(WebStateList*)webStateList
@@ -317,6 +325,13 @@
   }
 }
 
+- (void)webStateDidStartLoading:(web::WebState*)webState {
+  const id<ChromeLensController> lensController = self.lensController;
+  if (self.lensWebPageLoadTriggeredFromInputSelection && lensController) {
+    [lensController triggerSecondaryTransitionAnimation];
+  }
+}
+
 - (void)webStateDestroyed:(web::WebState*)webState {
   DCHECK_EQ(webState, self.loadingWebState);
   self.loadingWebState = nil;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
index 1fdc17c..94591f04 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
@@ -29,6 +29,8 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
+#import "ios/web/public/test/fakes/fake_navigation_context.h"
+#import "ios/web/public/test/fakes/fake_navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gtest/include/gtest/gtest.h"
@@ -99,9 +101,14 @@
         std::make_unique<web::FakeWebState>();
     NewTabPageTabHelper::CreateForWebState(web_state.get());
     web_state->SetVisibleURL(url);
-    // Force the DidStopLoading callback.
-    web_state->SetLoading(true);
-    web_state->SetLoading(false);
+    auto navigation_manager = std::make_unique<web::FakeNavigationManager>();
+    navigation_manager->AddItem(url, ui::PAGE_TRANSITION_LINK);
+    web_state->SetNavigationManager(std::move(navigation_manager));
+
+    // Force the URL load callbacks.
+    web::FakeNavigationContext navigation_context;
+    web_state->OnNavigationStarted(&navigation_context);
+    web_state->OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
     return std::move(web_state);
   }
 
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 4d3f909f..73caff3c 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-be03c64b44569baa3fb4bbe064975d06fa76ba36
\ No newline at end of file
+670528dc9ab978f0dc68fad0b6fdd1ce8a1ab666
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index bff45aa..6701690 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-569ff963ca1bfabe7a236de0c057a441e0e52b1f
\ No newline at end of file
+f547cce9256a37fd4ef8c47ddc434c0b0fe25f27
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index c793a3c..26eb40b 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 @@
-e79514092cdfbc88a1652c4dc32635e4d8afb751
\ No newline at end of file
+189887952b3931c6775033ac5fca80d36ae10e7d
\ 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 94947bd87..bcce62b 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 @@
-6f79178cd83c34d9c4bbaf934c781291f28a67d7
\ No newline at end of file
+d4087b1be923e5664a9cf90d794a8ea782e00b93
\ 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 4ba2d1ce..b904ed2 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 @@
-e81db22aada10b50cacc7081e5a7d813bdb30472
\ No newline at end of file
+afd248c2a332da19c893ddab96981e8c014c1f12
\ 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 a2409f3..75dfe4a9 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 @@
-8e87da09581e62c7f1c8b388570cad3bb909e21a
\ No newline at end of file
+73450b008f4d33dec59ac7da3e86e6bbf9d37821
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 33aaf72..6a8cb63e 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-bd8328d2ba2ad45101d98629285b2c5bfaf76418
\ No newline at end of file
+deecc81491bcfc37cda31ee621ca4e1475d6eb7d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 06c7974..759f70a 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-f8645712304e4d2e00c864a3d656c16b1847ead3
\ No newline at end of file
+f1209d487eedf56e3a73ce6410bbffa601beaf95
\ 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 30b3d839..e4157ac 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 @@
-1d6bee1f7d6c43af22ef5e40297d696cc38db9d1
\ No newline at end of file
+2e47ed454b0d78f159124e7655593cdb881d83c8
\ 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 fb35a144..e7070a7 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 @@
-073bd03d62aba80f6e09d7c78c2a9068000b53af
\ No newline at end of file
+2f995d271eb8ca4b088090234ab10b7ca35e37a0
\ 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 8eb2b69..6d61079 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 @@
-dacd257107fa3d8aa7b6aecca454f5224661791f
\ No newline at end of file
+3136bc310c5ec219e4692b04b2d677edf5833d35
\ 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 b873b71..6b2b343 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 @@
-057984130adb4015eaadb28fb5fb5e48d46873ef
\ No newline at end of file
+5b500e5196c9eb7bcdaeedaf04a7c84187b950ba
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/lens/lens_api.h b/ios/public/provider/chrome/browser/lens/lens_api.h
index 11d17db..719101df 100644
--- a/ios/public/provider/chrome/browser/lens/lens_api.h
+++ b/ios/public/provider/chrome/browser/lens/lens_api.h
@@ -31,6 +31,9 @@
 - (void)lensControllerDidGenerateLoadParams:
     (const web::NavigationManager::WebLoadParams&)params;
 
+// Returns the frame of the web content area of the browser.
+- (CGRect)webContentFrame;
+
 @end
 
 // A controller that can facilitate communication with the downstream Lens
@@ -40,10 +43,11 @@
 // A delegate that can receive Lens events forwarded by the controller.
 @property(nonatomic, weak) id<ChromeLensControllerDelegate> delegate;
 
-// Returns an input selection UIViewController with the provided
-// web content frame.
-- (UIViewController*)inputSelectionViewControllerWithWebContentFrame:
-    (CGRect)webContentFrame;
+// Returns an input selection UIViewController.
+- (UIViewController*)inputSelectionViewController;
+
+// Triggers the secondary transition animation from native LVF to Lens Web.
+- (void)triggerSecondaryTransitionAnimation;
 
 @end
 
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 7ed9889..71f4de9 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -2084,6 +2084,9 @@
 - (void)loadCancelled {
   // TODO(crbug.com/821995):  Check if this function should be removed.
   if (self.navigationState != web::WKNavigationState::FINISHED) {
+    UMA_HISTOGRAM_BOOLEAN("IOS.NavigationStateNotFinishedInLoadCancelled",
+                          self.beingDestroyed);
+
     self.navigationState = web::WKNavigationState::FINISHED;
     if (!self.beingDestroyed) {
       self.webStateImpl->SetIsLoading(false);
diff --git a/media/gpu/windows/mf_audio_encoder.cc b/media/gpu/windows/mf_audio_encoder.cc
index aa54a0a..5578040 100644
--- a/media/gpu/windows/mf_audio_encoder.cc
+++ b/media/gpu/windows/mf_audio_encoder.cc
@@ -155,6 +155,7 @@
 HRESULT CreateOutputMediaType(const int sample_rate,
                               const int channels,
                               const int bitrate,
+                              media::AudioEncoder::AacOutputFormat format,
                               ComPtr<IMFMediaType>* output_media_type) {
   // https://docs.microsoft.com/en-us/windows/win32/medfound/aac-encoder#output-types
   ComPtr<IMFMediaType> media_type;
@@ -173,9 +174,14 @@
   RETURN_IF_FAILED(media_type->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND,
                                          adjusted_bitrate / 8));
 
-  // The encoder can produce ADTS headers for us if we set the payload
-  // type to 1.
-  RETURN_IF_FAILED(media_type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 1));
+  // Set payload format.
+  // https://learn.microsoft.com/en-us/windows/win32/medfound/mf-mt-aac-payload-type
+  // 0 - The stream contains raw_data_block elements only. (default)
+  // 1 - Audio Data Transport Stream (ADTS).
+  //     The stream contains an adts_sequence, as defined by MPEG-2.
+  if (format == media::AudioEncoder::AacOutputFormat::ADTS) {
+    RETURN_IF_FAILED(media_type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 1));
+  }
 
   *output_media_type = std::move(media_type);
   return S_OK;
@@ -429,9 +435,10 @@
     return;
   }
 
+  auto format = options_.aac.value_or(AacOptions()).format;
   ComPtr<IMFMediaType> output_media_type;
   hr = CreateOutputMediaType(options_.sample_rate, options_.channels, bitrate,
-                             &output_media_type);
+                             format, &output_media_type);
   if (FAILED(hr) || !output_media_type) {
     std::move(done_cb).Run(EncoderStatus::Codes::kEncoderInitializationError);
     return;
@@ -457,6 +464,33 @@
   hr =
       GetOutputBufferRequirements(mf_encoder_, output_media_type,
                                   options_.channels, &output_buffer_alignment_);
+
+  /*
+    https://learn.microsoft.com/en-us/windows/win32/medfound/aac-encoder
+
+    After the output type is set, the AAC encoder updates the type by adding
+    the MF_MT_USER_DATA attribute. This attribute contains the portion of
+    the HEAACWAVEINFO structure that appears after the WAVEFORMATEX structure
+    (that is, after the wfx member).
+    This is followed by the AudioSpecificConfig() data,
+    as defined by ISO/IEC 14496-3.
+  */
+  UINT32 desc_size = 0;
+  if (output_media_type->GetBlobSize(MF_MT_USER_DATA, &desc_size) == S_OK &&
+      desc_size > 0 && format == media::AudioEncoder::AacOutputFormat::AAC) {
+    codec_desc_.resize(desc_size);
+    size_t aac_config_offset =
+        sizeof(HEAACWAVEINFO) - offsetof(HEAACWAVEINFO, wPayloadType);
+    hr = output_media_type->GetBlob(MF_MT_USER_DATA, codec_desc_.data(),
+                                    desc_size, nullptr);
+    if (FAILED(hr) || aac_config_offset > codec_desc_.size()) {
+      std::move(done_cb).Run(EncoderStatus::Codes::kEncoderInitializationError);
+      return;
+    }
+    codec_desc_.erase(codec_desc_.begin(),
+                      codec_desc_.begin() + aac_config_offset);
+  }
+
   if (FAILED(hr)) {
     std::move(done_cb).Run(EncoderStatus::Codes::kEncoderInitializationError);
     return;
@@ -728,7 +762,13 @@
       return;
     }
 
-    output_cb_.Run(std::move(encoded_audio), absl::nullopt);
+    absl::optional<CodecDescription> desc;
+    if (!codec_desc_.empty()) {
+      desc = codec_desc_;
+      codec_desc_.clear();
+    }
+
+    output_cb_.Run(std::move(encoded_audio), desc);
     samples_in_encoder_ -= kSamplesPerFrame;
     hr = mf_encoder_->GetOutputStatus(&status);
   }
diff --git a/media/gpu/windows/mf_audio_encoder.h b/media/gpu/windows/mf_audio_encoder.h
index 1f721eb8..078a89b 100644
--- a/media/gpu/windows/mf_audio_encoder.h
+++ b/media/gpu/windows/mf_audio_encoder.h
@@ -186,6 +186,7 @@
   int input_buffer_alignment_;
   int output_buffer_alignment_;
   bool initialized_ = false;
+  std::vector<uint8_t> codec_desc_;
 
   // We can't produce output until at least `kMinSamplesForOutput` have been
   // provided. Until then, `output_cb_` will not be run.
diff --git a/media/mojo/mojom/audio_encoder.mojom b/media/mojo/mojom/audio_encoder.mojom
index 9283796..3bd42d43 100644
--- a/media/mojo/mojom/audio_encoder.mojom
+++ b/media/mojo/mojom/audio_encoder.mojom
@@ -8,6 +8,11 @@
 import "media/mojo/mojom/audio_parameters.mojom";
 import "mojo/public/mojom/base/time.mojom";
 
+enum AacOutputFormat { kAAC, kADTS };
+struct AacAudioEncoderConfig {
+  AacOutputFormat format;
+};
+
 // This defines a mojo transport format for media::AudioEncoderConfig.
 // See media/base/audio_encoder.h for descriptions.
 struct AudioEncoderConfig {
@@ -23,6 +28,9 @@
   // Target encoded bitrate - bits per second of playback
   // 0 - if client has no bitrate preference.
   uint32 bitrate;
+
+  // AAC specific parts of the config
+  AacAudioEncoderConfig aac;
 };
 
 // This defines a mojo transport format for media::EncodedAudioBuffer.
diff --git a/media/mojo/mojom/audio_encoder_config_mojom_traits.cc b/media/mojo/mojom/audio_encoder_config_mojom_traits.cc
index 263929e6..529246ad 100644
--- a/media/mojo/mojom/audio_encoder_config_mojom_traits.cc
+++ b/media/mojo/mojom/audio_encoder_config_mojom_traits.cc
@@ -12,6 +12,51 @@
 namespace mojo {
 
 // static
+media::mojom::AacOutputFormat EnumTraits<media::mojom::AacOutputFormat,
+                                         media::AudioEncoder::AacOutputFormat>::
+    ToMojom(media::AudioEncoder::AacOutputFormat input) {
+  switch (input) {
+    case media::AudioEncoder::AacOutputFormat::ADTS:
+      return media::mojom::AacOutputFormat::kADTS;
+    case media::AudioEncoder::AacOutputFormat::AAC:
+      return media::mojom::AacOutputFormat::kAAC;
+  }
+  NOTREACHED();
+  return media::mojom::AacOutputFormat::kAAC;
+}
+
+// static
+bool EnumTraits<media::mojom::AacOutputFormat,
+                media::AudioEncoder::AacOutputFormat>::
+    FromMojom(media::mojom::AacOutputFormat format,
+              media::AudioEncoder::AacOutputFormat* output) {
+  switch (format) {
+    case media::mojom::AacOutputFormat::kADTS:
+      *output = media::AudioEncoder::AacOutputFormat::ADTS;
+      return true;
+    case media::mojom::AacOutputFormat::kAAC:
+      *output = media::AudioEncoder::AacOutputFormat::AAC;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+// static
+bool StructTraits<media::mojom::AacAudioEncoderConfigDataView,
+                  media::AudioEncoder::AacOptions>::
+    Read(media::mojom::AacAudioEncoderConfigDataView input,
+         media::AudioEncoder::AacOptions* output) {
+  media::AudioEncoder::AacOutputFormat format;
+  if (!input.ReadFormat(&format)) {
+    return false;
+  }
+
+  output->format = format;
+  return true;
+}
+
+// static
 bool StructTraits<media::mojom::AudioEncoderConfigDataView,
                   media::AudioEncoderConfig>::
     Read(media::mojom::AudioEncoderConfigDataView input,
@@ -33,6 +78,12 @@
     return false;
   output->channels = input.channel_count();
 
+  media::AudioEncoder::AacOptions aac;
+  if (!input.ReadAac(&aac)) {
+    return false;
+  }
+  output->aac = aac;
+
   return true;
 }
 
diff --git a/media/mojo/mojom/audio_encoder_config_mojom_traits.h b/media/mojo/mojom/audio_encoder_config_mojom_traits.h
index d99908a1..b97f391 100644
--- a/media/mojo/mojom/audio_encoder_config_mojom_traits.h
+++ b/media/mojo/mojom/audio_encoder_config_mojom_traits.h
@@ -13,6 +13,28 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<media::mojom::AacOutputFormat,
+                  media::AudioEncoder::AacOutputFormat> {
+  static media::mojom::AacOutputFormat ToMojom(
+      media::AudioEncoder::AacOutputFormat input);
+
+  static bool FromMojom(media::mojom::AacOutputFormat,
+                        media::AudioEncoder::AacOutputFormat* output);
+};
+
+template <>
+struct StructTraits<media::mojom::AacAudioEncoderConfigDataView,
+                    media::AudioEncoder::AacOptions> {
+  static media::AudioEncoder::AacOutputFormat format(
+      media::AudioEncoder::AacOptions& input) {
+    return input.format;
+  }
+
+  static bool Read(media::mojom::AacAudioEncoderConfigDataView input,
+                   media::AudioEncoder::AacOptions* output);
+};
+
+template <>
 struct StructTraits<media::mojom::AudioEncoderConfigDataView,
                     media::AudioEncoderConfig> {
   static media::AudioCodec codec(const media::AudioEncoderConfig& input) {
@@ -31,6 +53,11 @@
     return input.bitrate.value_or(0);
   }
 
+  static media::AudioEncoder::AacOptions aac(
+      const media::AudioEncoderConfig& input) {
+    return input.aac.value_or(media::AudioEncoder::AacOptions());
+  }
+
   static bool Read(media::mojom::AudioEncoderConfigDataView input,
                    media::AudioEncoderConfig* output);
 };
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index b97612a..2d15a5c 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -669,44 +669,18 @@
                               overlay_plane_id_);
       break;
     }
-    case VideoFrameResourceType::YUV: {
-      DCHECK_EQ(frame_resources_.size(),
-                VideoFrame::NumPlanes(frame->format()));
-      if (frame->HasTextures()) {
-        DCHECK(frame->format() == PIXEL_FORMAT_NV12 ||
-               frame->format() == PIXEL_FORMAT_P016LE ||
-               frame->format() == PIXEL_FORMAT_I420);
-      }
-
-      // Get the scaling factor of the YA texture relative to the UV texture.
-      const gfx::Size uv_sample_size =
-          VideoFrame::SampleSize(frame->format(), VideoFrame::kUPlane);
-
-      auto* yuv_video_quad =
-          render_pass->CreateAndAppendDrawQuad<viz::YUVVideoDrawQuad>();
-      yuv_video_quad->SetNew(
-          shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
-          coded_size, visible_rect, uv_sample_size, frame_resources_[0].id,
-          frame_resources_[1].id,
-          frame_resources_.size() > 2 ? frame_resources_[2].id
-                                      : frame_resources_[1].id,
-          frame_resources_.size() > 3 ? frame_resources_[3].id
-                                      : viz::kInvalidResourceId,
-          frame->ColorSpace(), frame_resource_offset_,
-          frame_resource_multiplier_, frame_bits_per_channel_,
-          ProtectedVideoTypeFromMetadata(frame->metadata()),
-          frame->hdr_metadata());
-
-      for (viz::ResourceId resource_id : yuv_video_quad->resources) {
-        resource_provider_->ValidateResource(resource_id);
-      }
-      break;
-    }
+    case VideoFrameResourceType::YUV:
     case VideoFrameResourceType::YUVA: {
       DCHECK_EQ(frame_resources_.size(),
                 VideoFrame::NumPlanes(frame->format()));
       if (frame->HasTextures()) {
-        DCHECK_EQ(frame->format(), PIXEL_FORMAT_NV12A);
+        if (frame_resource_type_ == VideoFrameResourceType::YUV) {
+          DCHECK(frame->format() == PIXEL_FORMAT_NV12 ||
+                 frame->format() == PIXEL_FORMAT_P016LE ||
+                 frame->format() == PIXEL_FORMAT_I420);
+        } else {
+          DCHECK_EQ(frame->format(), PIXEL_FORMAT_NV12A);
+        }
       }
 
       // Get the scaling factor of the YA texture relative to the UV texture.
@@ -715,16 +689,25 @@
 
       auto* yuv_video_quad =
           render_pass->CreateAndAppendDrawQuad<viz::YUVVideoDrawQuad>();
+      viz::ResourceId v_plane_id;
+      viz::ResourceId a_plane_id;
+      if (frame_resource_type_ == VideoFrameResourceType::YUV) {
+        v_plane_id = frame_resources_.size() > 2 ? frame_resources_[2].id
+                                                 : frame_resources_[1].id;
+        a_plane_id = frame_resources_.size() > 3 ? frame_resources_[3].id
+                                                 : viz::kInvalidResourceId;
+      } else {
+        v_plane_id = frame_resources_.size() > 3 ? frame_resources_[2].id
+                                                 : frame_resources_[1].id;
+        a_plane_id = frame_resources_.size() > 3 ? frame_resources_[3].id
+                                                 : frame_resources_[2].id;
+      }
       yuv_video_quad->SetNew(
           shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
           coded_size, visible_rect, uv_sample_size, frame_resources_[0].id,
-          frame_resources_[1].id,
-          frame_resources_.size() > 3 ? frame_resources_[2].id
-                                      : frame_resources_[1].id,
-          frame_resources_.size() > 3 ? frame_resources_[3].id
-                                      : frame_resources_[2].id,
-          frame->ColorSpace(), frame_resource_offset_,
-          frame_resource_multiplier_, frame_bits_per_channel_,
+          frame_resources_[1].id, v_plane_id, a_plane_id, frame->ColorSpace(),
+          frame_resource_offset_, frame_resource_multiplier_,
+          frame_bits_per_channel_,
           ProtectedVideoTypeFromMetadata(frame->metadata()),
           frame->hdr_metadata());
 
diff --git a/pdf/loader/url_loader_unittest.cc b/pdf/loader/url_loader_unittest.cc
index 1d23935..ea1d4bc 100644
--- a/pdf/loader/url_loader_unittest.cc
+++ b/pdf/loader/url_loader_unittest.cc
@@ -168,8 +168,8 @@
   std::unique_ptr<UrlLoader> loader_;
 
   // Becomes invalid if `loader_` is closed or destructed.
-  raw_ptr<MockWebAssociatedURLLoader> mock_url_loader_ =
-      fake_client_.mock_url_loader();
+  raw_ptr<MockWebAssociatedURLLoader, DisableDanglingPtrDetection>
+      mock_url_loader_ = fake_client_.mock_url_loader();
 
   blink::WebURLRequest saved_request_;
 };
diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc
index 38601d0..86a96e44 100644
--- a/sandbox/policy/win/sandbox_win.cc
+++ b/sandbox/policy/win/sandbox_win.cc
@@ -718,11 +718,13 @@
       process_type == switches::kGpuProcess ||
       process_type == switches::kUtilityProcess) {
     if (logging::IsLoggingToFileEnabled()) {
-      DCHECK(base::FilePath(logging::GetLogFileFullPath()).IsAbsolute());
+      auto log_path = logging::GetLogFileFullPath();
+      DCHECK(base::FilePath(log_path).IsAbsolute());
       result = config->AddRule(SubSystem::kFiles, Semantics::kFilesAllowAny,
-                               logging::GetLogFileFullPath().c_str());
-      if (result != SBOX_ALL_OK)
+                               log_path.c_str());
+      if (result != SBOX_ALL_OK) {
         return result;
+      }
     }
   }
 
diff --git a/services/data_decoder/public/cpp/BUILD.gn b/services/data_decoder/public/cpp/BUILD.gn
index 373e9007..bc4e847 100644
--- a/services/data_decoder/public/cpp/BUILD.gn
+++ b/services/data_decoder/public/cpp/BUILD.gn
@@ -42,7 +42,7 @@
     "//net",
     "//services/data_decoder/public/mojom",
   ]
-  deps = []
+  deps = [ "//build:blink_buildflags" ]
 
   if (is_android) {
     sources += [ "json_sanitizer_android.cc" ]
@@ -57,7 +57,7 @@
     # NOTE: We depend on this target here for iOS only, to support in-process
     # use of the service. Non-test targets in this directory should otherwise
     # NEVER depend on this target.
-    deps = [ "//services/data_decoder:lib" ]
+    deps += [ "//services/data_decoder:lib" ]
   } else {
     public += [
       "decode_image.h",
diff --git a/services/data_decoder/public/cpp/data_decoder.cc b/services/data_decoder/public/cpp/data_decoder.cc
index 358bdac..185915f4 100644
--- a/services/data_decoder/public/cpp/data_decoder.cc
+++ b/services/data_decoder/public/cpp/data_decoder.cc
@@ -12,6 +12,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
+#include "build/blink_buildflags.h"
 #include "build/build_config.h"
 #include "net/http/structured_headers.h"
 #include "services/data_decoder/public/mojom/gzipper.mojom.h"
@@ -23,7 +24,7 @@
 #include "services/data_decoder/public/cpp/json_sanitizer.h"
 #endif
 
-#if BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(USE_BLINK)
 #include "services/data_decoder/data_decoder_service.h"  // nogncheck
 #endif
 
@@ -114,7 +115,7 @@
   scoped_refptr<DataDecoder::CancellationFlag> is_cancelled_;
 };
 
-#if BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(USE_BLINK)
 void BindInProcessService(
     mojo::PendingReceiver<mojom::DataDecoderService> receiver) {
   static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>>
@@ -167,7 +168,7 @@
     if (provider) {
       provider->BindDataDecoderService(service_.BindNewPipeAndPassReceiver());
     } else {
-#if BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(USE_BLINK)
       BindInProcessService(service_.BindNewPipeAndPassReceiver());
 #else
       LOG(FATAL) << "data_decoder::ServiceProvider::Set() must be called "
diff --git a/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc b/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
index 9ddb806..04309021 100644
--- a/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/paint_filter_mojom_traits.cc
@@ -4,6 +4,8 @@
 
 #include "services/viz/public/cpp/compositing/paint_filter_mojom_traits.h"
 
+#include <utility>
+
 #include "cc/paint/paint_filter.h"
 
 namespace mojo {
@@ -13,8 +15,7 @@
 StructTraits<viz::mojom::PaintFilterDataView, sk_sp<cc::PaintFilter>>::data(
     const sk_sp<cc::PaintFilter>& filter) {
   std::vector<uint8_t> memory;
-  memory.resize(cc::PaintOpWriter::HeaderBytes() +
-                cc::PaintFilter::GetFilterSize(filter.get()));
+  memory.resize(cc::PaintOpWriter::SerializedSize(filter.get()));
   // No need to populate the SerializeOptions here since the security
   // constraints explicitly disable serializing images using the transfer cache
   // and serialization of PaintRecords.
diff --git a/services/viz/public/cpp/gpu/gpu.cc b/services/viz/public/cpp/gpu/gpu.cc
index f05b721..506d9b6 100644
--- a/services/viz/public/cpp/gpu/gpu.cc
+++ b/services/viz/public/cpp/gpu/gpu.cc
@@ -127,7 +127,9 @@
   // request. This must be called from main thread.
   void SetWaitableEvent(base::WaitableEvent* establish_event) {
     DCHECK(main_task_runner_->BelongsToCurrentThread());
+    DCHECK(establish_event);
     base::AutoLock mutex(lock_);
+    DCHECK(!establish_event_);
 
     // If we've already received a response then don't reset |establish_event|.
     // The caller won't block and will immediately process the response.
@@ -323,7 +325,7 @@
   }
 
   establish_callbacks_.push_back(std::move(callback));
-  SendEstablishGpuChannelRequest();
+  SendEstablishGpuChannelRequest(/*waitable_event=*/nullptr);
 }
 
 scoped_refptr<gpu::GpuChannelHost> Gpu::EstablishGpuChannelSync() {
@@ -335,10 +337,9 @@
     return channel;
 
   SCOPED_UMA_HISTOGRAM_TIMER("GPU.EstablishGpuChannelSyncTime");
-  SendEstablishGpuChannelRequest();
   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                             base::WaitableEvent::InitialState::SIGNALED);
-  pending_request_->SetWaitableEvent(&event);
+  SendEstablishGpuChannelRequest(&event);
   event.Wait();
 
   // Running FinishOnMain() will create |gpu_channel_| and run any callbacks
@@ -367,12 +368,19 @@
   return gpu_channel_;
 }
 
-void Gpu::SendEstablishGpuChannelRequest() {
-  if (pending_request_)
+void Gpu::SendEstablishGpuChannelRequest(base::WaitableEvent* waitable_event) {
+  if (pending_request_) {
+    if (waitable_event) {
+      pending_request_->SetWaitableEvent(waitable_event);
+    }
     return;
+  }
 
   pending_request_ =
       base::MakeRefCounted<EstablishRequest>(this, main_task_runner_);
+  if (waitable_event) {
+    pending_request_->SetWaitableEvent(waitable_event);
+  }
   io_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&EstablishRequest::SendRequest, pending_request_,
diff --git a/services/viz/public/cpp/gpu/gpu.h b/services/viz/public/cpp/gpu/gpu.h
index 85fb350b..a13e9679 100644
--- a/services/viz/public/cpp/gpu/gpu.h
+++ b/services/viz/public/cpp/gpu/gpu.h
@@ -74,7 +74,7 @@
 
   // Sends a request to establish a gpu channel. If a request is currently
   // pending this will do nothing.
-  void SendEstablishGpuChannelRequest();
+  void SendEstablishGpuChannelRequest(base::WaitableEvent* waitable_event);
 
   // Handles results of request to establish a gpu channel in
   // |pending_request_|.
diff --git a/sql/database_unittest.cc b/sql/database_unittest.cc
index 3ee7f5a5..13be18fa 100644
--- a/sql/database_unittest.cc
+++ b/sql/database_unittest.cc
@@ -1746,7 +1746,7 @@
   ASSERT_TRUE(!db_->DoesTableExist("meta"));
 
   // When the meta table is first created, it sets up to map everything.
-  MetaTable().Init(db_.get(), 1, 1);
+  ASSERT_TRUE(MetaTable().Init(db_.get(), 1, 1));
   ASSERT_TRUE(db_->DoesTableExist("meta"));
   ASSERT_GT(db_->ComputeMmapSizeForOpen(), kMmapAlot);
   ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
@@ -1765,7 +1765,7 @@
   // Re-initializing the meta table does not re-create the key if the table
   // already exists.
   ASSERT_TRUE(db_->Execute("DELETE FROM meta WHERE key = 'mmap_status'"));
-  MetaTable().Init(db_.get(), 1, 1);
+  ASSERT_TRUE(MetaTable().Init(db_.get(), 1, 1));
   ASSERT_EQ(MetaTable::kMmapSuccess, mmap_status);
   ASSERT_TRUE(MetaTable::GetMmapStatus(db_.get(), &mmap_status));
   ASSERT_EQ(0, mmap_status);
diff --git a/sql/meta_table.h b/sql/meta_table.h
index a1cc1fa..ce552a9 100644
--- a/sql/meta_table.h
+++ b/sql/meta_table.h
@@ -77,9 +77,7 @@
   // Versions must be greater than 0 to distinguish missing versions (see
   // GetVersionNumber()). If there was no meta table (proxy for a fresh
   // database), mmap status is set to `kMmapSuccess`.
-  // TODO(apaseltiner): Mark this [[nodiscard]] once all callers have been
-  // updated.
-  bool Init(Database* db, int version, int compatible_version);
+  [[nodiscard]] bool Init(Database* db, int version, int compatible_version);
 
   // Resets this MetaTable object, making another call to Init() possible.
   void Reset();
diff --git a/storage/browser/file_system/file_system_url.cc b/storage/browser/file_system/file_system_url.cc
index 9d83fbd..91651be9 100644
--- a/storage/browser/file_system/file_system_url.cc
+++ b/storage/browser/file_system/file_system_url.cc
@@ -22,7 +22,7 @@
 
 namespace {
 
-bool areSameStorageKey(const FileSystemURL& a, const FileSystemURL& b) {
+bool AreSameStorageKey(const FileSystemURL& a, const FileSystemURL& b) {
   // TODO(https://crbug.com/1396116): Make the `storage_key_` member optional.
   // This class improperly uses a StorageKey with an opaque origin to indicate a
   // lack of origin for FileSystemURLs corresponding to non-sandboxed file
@@ -211,7 +211,7 @@
       !base::FeatureList::IsEnabled(
           features::kFileSystemURLComparatorsTreatOpaqueOriginAsNoOrigin) ||
       (is_valid() && other.is_valid());
-  return areSameStorageKey(*this, other) && is_maybe_valid &&
+  return AreSameStorageKey(*this, other) && is_maybe_valid &&
          type() == other.type() && filesystem_id() == other.filesystem_id() &&
          bucket() == other.bucket();
 }
@@ -221,7 +221,7 @@
     return true;
   }
 
-  return areSameStorageKey(*this, that) && type_ == that.type_ &&
+  return AreSameStorageKey(*this, that) && type_ == that.type_ &&
          path_ == that.path_ && filesystem_id_ == that.filesystem_id_ &&
          is_valid_ == that.is_valid_ && bucket_ == that.bucket_;
 }
@@ -229,14 +229,18 @@
 bool FileSystemURL::Comparator::operator()(const FileSystemURL& lhs,
                                            const FileSystemURL& rhs) const {
   DCHECK(lhs.is_valid_ && rhs.is_valid_);
-  if (lhs.storage_key() != rhs.storage_key())
+  if (!AreSameStorageKey(lhs, rhs)) {
     return lhs.storage_key() < rhs.storage_key();
-  if (lhs.type_ != rhs.type_)
+  }
+  if (lhs.type_ != rhs.type_) {
     return lhs.type_ < rhs.type_;
-  if (lhs.filesystem_id_ != rhs.filesystem_id_)
+  }
+  if (lhs.filesystem_id_ != rhs.filesystem_id_) {
     return lhs.filesystem_id_ < rhs.filesystem_id_;
-  if (lhs.bucket_ != rhs.bucket_)
+  }
+  if (lhs.bucket_ != rhs.bucket_) {
     return lhs.bucket_ < rhs.bucket_;
+  }
   return lhs.path_ < rhs.path_;
 }
 
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 7c20f7b..7b5e58a 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3907,7 +3907,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android30.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.crashpad_tests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter"
         ],
         "merge": {
           "args": [
@@ -4914,7 +4914,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android30.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -6707,7 +6707,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android31.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.base_unittests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -7872,7 +7872,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android31.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.crashpad_tests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter"
         ],
         "merge": {
           "args": [
@@ -8881,7 +8881,7 @@
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android31.textpb",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -10790,7 +10790,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -11941,7 +11942,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter"
         ],
         "merge": {
           "args": [
@@ -12946,7 +12948,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -13360,7 +13363,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android32_foldable.textpb",
+          "--gtest_filter=-ScopedDirTest.CloseOutOfScope"
         ],
         "merge": {
           "args": [
@@ -14710,7 +14714,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -15861,7 +15866,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter"
         ],
         "merge": {
           "args": [
@@ -16866,7 +16872,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter"
         ],
         "merge": {
           "args": [
@@ -17280,7 +17287,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android33.textpb",
+          "--gtest_filter=-ScopedDirTest.CloseOutOfScope"
         ],
         "merge": {
           "args": [
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 890874a..02ad0d9d 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -31,7 +31,7 @@
   testonly = true
 
   data = [
-    "//testing/buildbot/filters/android.emulator_12.base_unittests.filter",
+    "//testing/buildbot/filters/android.emulator.base_unittests.filter",
     "//testing/buildbot/filters/android.pie_tot.base_unittests.filter",
     "//testing/buildbot/filters/fuchsia.lsan.base_unittests.filter",
   ]
@@ -169,8 +169,7 @@
   testonly = true
 
   data = [
-    "//testing/buildbot/filters/android.emulator_11.crashpad_tests.filter",
-    "//testing/buildbot/filters/android.emulator_12.crashpad_tests.filter",
+    "//testing/buildbot/filters/android.emulator.crashpad_tests.filter",
     "//testing/buildbot/filters/android.pie_tot.crashpad_tests.filter",
   ]
 }
@@ -315,7 +314,7 @@
 
 source_set("media_unittests_filters") {
   data = [
-    "//testing/buildbot/filters/android.emulator_11_12.media_unittests.filter",
+    "//testing/buildbot/filters/android.emulator.media_unittests.filter",
     "//testing/buildbot/filters/fuchsia.debug.media_unittests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/android.emulator_12.base_unittests.filter b/testing/buildbot/filters/android.emulator.base_unittests.filter
similarity index 100%
rename from testing/buildbot/filters/android.emulator_12.base_unittests.filter
rename to testing/buildbot/filters/android.emulator.base_unittests.filter
diff --git a/testing/buildbot/filters/android.emulator_12.crashpad_tests.filter b/testing/buildbot/filters/android.emulator.crashpad_tests.filter
similarity index 100%
rename from testing/buildbot/filters/android.emulator_12.crashpad_tests.filter
rename to testing/buildbot/filters/android.emulator.crashpad_tests.filter
diff --git a/testing/buildbot/filters/android.emulator_11_12.media_unittests.filter b/testing/buildbot/filters/android.emulator.media_unittests.filter
similarity index 84%
rename from testing/buildbot/filters/android.emulator_11_12.media_unittests.filter
rename to testing/buildbot/filters/android.emulator.media_unittests.filter
index 33612d2..a644e4a4 100644
--- a/testing/buildbot/filters/android.emulator_11_12.media_unittests.filter
+++ b/testing/buildbot/filters/android.emulator.media_unittests.filter
@@ -2,4 +2,3 @@
 # Not applicable to emulator due to not supporting fence sync
 -PaintCanvasVideoRendererWithGLTest.CopyVideoFrameTexturesToGLTexture*
 -PaintCanvasVideoRendererWithGLTest.CopyVideoFrameYUVDataToGLTexture*
--PaintCanvasVideoRendererWithGLTest.Paint*
diff --git a/testing/buildbot/filters/android.emulator_11.crashpad_tests.filter b/testing/buildbot/filters/android.emulator_11.crashpad_tests.filter
deleted file mode 100644
index 4f48442..0000000
--- a/testing/buildbot/filters/android.emulator_11.crashpad_tests.filter
+++ /dev/null
@@ -1,3 +0,0 @@
-# crbug.com/1188310
--CrashReportDatabaseTest.CleanBrokenDatabase
--ProcessReaderLinux.ChildThreadsWithSmallUserStacks
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 91c3a38..a7fee25 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -150,7 +150,17 @@
       },
       'android-12-x64-rel': {
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.base_unittests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter',
+        ],
+      },
+      'android-12l-x64-dbg-tests': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter',
+        ],
+      },
+      'android-13-x64-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter',
         ],
       },
       'fuchsia-code-coverage': {
@@ -2028,12 +2038,22 @@
       },
       'android-11-x86-rel': {
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.crashpad_tests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter',
         ],
       },
       'android-12-x64-rel': {
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.crashpad_tests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter',
+        ],
+      },
+      'android-12l-x64-dbg-tests': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter',
+        ],
+      },
+      'android-13-x64-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.crashpad_tests.filter',
         ],
       },
       # TODO(crbug.com/1254975): dyld was rebuilt for macOS 12, which breaks
@@ -2726,12 +2746,22 @@
     'modifications': {
       'android-11-x86-rel': {
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
         ],
       },
       'android-12-x64-rel': {
         'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
+        ],
+      },
+      'android-12l-x64-dbg-tests': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
+        ],
+      },
+      'android-13-x64-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.media_unittests.filter',
         ],
       },
       'android-pie-arm64-rel': {
@@ -3043,6 +3073,18 @@
           '--gtest_filter=-ScopedDirTest.CloseOutOfScope',
         ],
       },
+      'android-12l-x64-dbg-tests': {
+        'args': [
+          # TODO(crbug.com/1260440): Fix the failed test
+          '--gtest_filter=-ScopedDirTest.CloseOutOfScope',
+        ],
+      },
+      'android-13-x64-rel': {
+        'args': [
+          # TODO(crbug.com/1260440): Fix the failed test
+          '--gtest_filter=-ScopedDirTest.CloseOutOfScope',
+        ],
+      },
       'android-nougat-x86-rel': {
         'args': [
           # TODO(crbug.com/1260440): Fix the failed test
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index eea7ac0..8e23284a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -438,6 +438,7 @@
                 {
                     "name": "Enabled",
                     "params": {
+                        "enable_bookmarks": "true",
                         "enable_longpress_entry": "true",
                         "enable_share": "true"
                     },
@@ -1344,47 +1345,6 @@
             ]
         }
     ],
-    "AutofillSaveCardUiExperiment": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledEncryptedAndSecure",
-                    "params": {
-                        "autofill_save_card_ui_experiment_selector_in_number": "2"
-                    },
-                    "enable_features": [
-                        "AutofillSaveCardUiExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledFasterAndProtected",
-                    "params": {
-                        "autofill_save_card_ui_experiment_selector_in_number": "1"
-                    },
-                    "enable_features": [
-                        "AutofillSaveCardUiExperiment"
-                    ]
-                },
-                {
-                    "name": "EnabledCurrentWithUserAvatarAndEmail",
-                    "params": {
-                        "autofill_save_card_ui_experiment_selector_in_number": "3"
-                    },
-                    "enable_features": [
-                        "AutofillSaveCardUiExperiment"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillServerCommunication": [
         {
             "platforms": [
@@ -5690,6 +5650,27 @@
             ]
         }
     ],
+    "HighlightManagedPrefDisclaimerAndroid": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "HighlightManagedPrefDisclaimerAndroid"
+                    ]
+                },
+                {
+                    "name": "Control",
+                    "disable_features": [
+                        "HighlightManagedPrefDisclaimerAndroid"
+                    ]
+                }
+            ]
+        }
+    ],
     "HoldbackRemoveMobileViewportDoubleTap": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 253de9a..7687280f 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1507,11 +1507,11 @@
 // TODO(mahesh.ma): Enable for supported Android versions once feature is ready.
 BASE_FEATURE(kStylusWritingToInput,
              "StylusWritingToInput",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kAndroidExtendedEditingCommands,
              "AndroidExtendedEditingCommands",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kStylusPointerAdjustment,
              "StylusPointerAdjustment",
diff --git a/third_party/blink/perf_tests/view_transitions/OWNERS b/third_party/blink/perf_tests/view_transitions/OWNERS
new file mode 100644
index 0000000..1fbd23f
--- /dev/null
+++ b/third_party/blink/perf_tests/view_transitions/OWNERS
@@ -0,0 +1,3 @@
+bokan@chromium.org
+khushalsagar@chromium.org
+vmpstr@chromium.org
diff --git a/third_party/blink/perf_tests/view_transitions/huge_element_capture.html b/third_party/blink/perf_tests/view_transitions/huge_element_capture.html
new file mode 100644
index 0000000..9adb40e
--- /dev/null
+++ b/third_party/blink/perf_tests/view_transitions/huge_element_capture.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+html { view-transition-name: unset }
+#target {
+  height: 100000px;
+  width: 1000px;
+  position: absolute;
+  background: lightblue;
+  contain: layout;
+  view-transition-name: target;
+}
+.left {
+  left: 8px;
+}
+.right {
+  right: 8px;
+}
+::view-transition-group(*) {
+  animation-duration: 0s;
+}
+</style>
+<script src="../resources/runner.js"></script>
+<script>
+function startTest() {
+  var transition;
+  PerfTestRunner.measureFrameTime({
+      description: "Measures performance starting/finishing a transition with a large element",
+      setup: () => {
+        transition = document.startViewTransition(() => {
+          target.classList.toggle("left");
+          target.classList.toggle("right");
+        });
+      },
+      run: async () => { await transition.finished },
+      done: () => {}
+  });
+}
+</script>
+</head>
+<body onload="startTest()">
+<div id=target class=left>This is a div!</div>
+<div id="log"></div>
+</body></html>
diff --git a/third_party/blink/perf_tests/view_transitions/many_small_elements_capture.html b/third_party/blink/perf_tests/view_transitions/many_small_elements_capture.html
new file mode 100644
index 0000000..09f7d17
--- /dev/null
+++ b/third_party/blink/perf_tests/view_transitions/many_small_elements_capture.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+html { view-transition-name: unset }
+#container > * {
+  contain: layout;
+  display: inline-block;
+  border: 1px solid black;
+  width: 20px;
+  height: 20px;
+}
+.green > * {
+  background: green;
+}
+.blue > * {
+  background: blue;
+}
+::view-transition-group(*) {
+  animation-duration: 0s;
+}
+</style>
+<script src="../resources/runner.js"></script>
+
+<script>
+const kCount = 1500;
+
+function startTest() {
+  var transition;
+  for (let i = 0; i < kCount; i++) {
+    let e = document.createElement("div");
+    e.viewTransitionName = "e" + i;
+    container.appendChild(e);
+  }
+  PerfTestRunner.measureFrameTime({
+      description: "Measures performance starting/finishing a transition with many small elements",
+      setup: () => {
+        transition = document.startViewTransition(() => {
+          container.classList.toggle("green");
+          container.classList.toggle("blue");
+        });
+      },
+      run: async () => { await transition.finished },
+      done: () => {}
+  });
+}
+</script>
+</head>
+<body onload="startTest()">
+<div id=container class=green></div>
+<div id="log"></div>
+</body></html>
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
index a214b9c4..a9592b2 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h
@@ -31,19 +31,15 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_NETWORK_PROVIDER_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_NETWORK_PROVIDER_H_
 
-#include <memory>
-
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/public/mojom/frame/frame.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom-shared.h"
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
-#include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
 
 namespace blink {
 
-class WebBackForwardCacheLoaderHelper;
 class WebURLRequest;
 
 // This interface allows the Blink embedder to implement loading functionality
@@ -63,14 +59,10 @@
   // request made.
   virtual void WillSendRequest(WebURLRequest&) = 0;
 
-  // Returns a URLLoader for loading |request|. May return nullptr to fall back
-  // to the default loading behavior.
-  virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
-      const WebURLRequest& request,
-      std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>,
-      std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>,
-      CrossVariantMojoRemote<blink::mojom::KeepAliveHandleInterfaceBase>,
-      WebBackForwardCacheLoaderHelper) = 0;
+  // Returns a SharedURLLoaderFactory for loading |request|. May return nullptr
+  // to fall back to the default loading behavior.
+  virtual scoped_refptr<network::SharedURLLoaderFactory>
+  GetSubresourceLoaderFactory(const WebURLRequest& request) = 0;
 
   // For service worker clients.
   virtual blink::mojom::ControllerServiceWorkerMode
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index b2de9ae2..1bd8703 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -99,6 +99,7 @@
 class URLLoaderFactoryInterfaceBase;
 }
 class PendingSharedURLLoaderFactory;
+class SharedURLLoaderFactory;
 }
 
 namespace url {
@@ -263,6 +264,8 @@
   virtual std::unique_ptr<WebURLLoaderFactory> WrapURLLoaderFactory(
       CrossVariantMojoRemote<network::mojom::URLLoaderFactoryInterfaceBase>
           url_loader_factory);
+  virtual std::unique_ptr<blink::WebURLLoaderFactory> WrapURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
   // Returns the default User-Agent string, it can either full User-Agent string
   // or reduced User-Agent string based on policy setting.
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 7d406160..0453c00 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2614,15 +2614,12 @@
   }
 
   gfx::RectF reference_box = ReferenceBoxForTransform(*layout_object);
-  const auto* layout_box = layout_object->IsSVGChild()
-                               ? nullptr
-                               : DynamicTo<LayoutBox>(*layout_object);
+
   gfx::Transform transform;
-  style.ApplyTransform(transform, layout_box, reference_box,
-                       ComputedStyle::kIncludeTransformOperations,
-                       ComputedStyle::kExcludeTransformOrigin,
-                       ComputedStyle::kExcludeMotionPath,
-                       ComputedStyle::kExcludeIndependentTransformProperties);
+  style.ApplyTransform(
+      transform, reference_box, ComputedStyle::kIncludeTransformOperations,
+      ComputedStyle::kExcludeTransformOrigin, ComputedStyle::kExcludeMotionPath,
+      ComputedStyle::kExcludeIndependentTransformProperties);
 
   // FIXME: Need to print out individual functions
   // (https://bugs.webkit.org/show_bug.cgi?id=23924)
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 98731f742..e4a87eb 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1042,11 +1042,6 @@
   // We don't set computed style for text nodes.
   DCHECK(IsElementNode());
 
-  if (auto* element = DynamicTo<Element>(this)) {
-    ViewTransitionSupplement::From(GetDocument())
-        ->UpdateViewTransitionNames(*element, computed_style.get());
-  }
-
   // Already pointing to a non empty NodeData so just set the pointer
   // to the new LayoutObject.
   if (!data_->IsSharedEmptyData()) {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc b/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
index 4d0e11d..2fb8f9bc 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_menu_element.cc
@@ -242,6 +242,10 @@
   button_part_->addEventListener(event_type_names::kKeydown,
                                  button_part_listener_, /*use_capture=*/false);
 
+  selected_value_slot_ = MakeGarbageCollected<HTMLSlotElement>(document);
+  selected_value_slot_->setAttribute(html_names::kNameAttr,
+                                     kSelectedValuePartName);
+
   selected_value_part_ = MakeGarbageCollected<HTMLDivElement>(document);
   selected_value_part_->setAttribute(html_names::kPartAttr,
                                      kSelectedValuePartName);
@@ -269,9 +273,11 @@
 
   auto* options_slot = MakeGarbageCollected<HTMLSlotElement>(document);
 
-  button_part_->AppendChild(selected_value_part_);
+  button_part_->AppendChild(selected_value_slot_);
   button_part_->AppendChild(marker_slot_);
 
+  selected_value_slot_->AppendChild(selected_value_part_);
+
   marker_slot_->AppendChild(marker_icon);
 
   button_slot_->AppendChild(button_part_);
@@ -1048,6 +1054,7 @@
   visitor->Trace(button_slot_);
   visitor->Trace(listbox_slot_);
   visitor->Trace(marker_slot_);
+  visitor->Trace(selected_value_slot_);
   visitor->Trace(selected_option_);
   visitor->Trace(selected_option_when_listbox_opened_);
   HTMLFormControlElementWithState::Trace(visitor);
diff --git a/third_party/blink/renderer/core/html/forms/html_select_menu_element.h b/third_party/blink/renderer/core/html/forms/html_select_menu_element.h
index 7b873e2..39fc3a2b 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_menu_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_select_menu_element.h
@@ -173,6 +173,7 @@
   Member<HTMLSlotElement> button_slot_;
   Member<HTMLSlotElement> listbox_slot_;
   Member<HTMLSlotElement> marker_slot_;
+  Member<HTMLSlotElement> selected_value_slot_;
   Member<HTMLOptionElement> selected_option_;
   Member<HTMLOptionElement> selected_option_when_listbox_opened_;
   bool queued_check_for_missing_parts_{false};
diff --git a/third_party/blink/renderer/core/layout/svg/transform_helper.cc b/third_party/blink/renderer/core/layout/svg/transform_helper.cc
index d016bb1..54fed35 100644
--- a/third_party/blink/renderer/core/layout/svg/transform_helper.cc
+++ b/third_party/blink/renderer/core/layout/svg/transform_helper.cc
@@ -80,11 +80,10 @@
   // https://svgwg.org/svg2-draft/coords.html#ObjectBoundingBoxUnits
   gfx::Transform transform;
   gfx::RectF reference_box = ComputeReferenceBox(layout_object);
-  style.ApplyTransform(transform, nullptr, reference_box,
-                       ComputedStyle::kIncludeTransformOperations,
-                       apply_transform_origin,
-                       ComputedStyle::kIncludeMotionPath,
-                       ComputedStyle::kIncludeIndependentTransformProperties);
+  style.ApplyTransform(
+      transform, reference_box, ComputedStyle::kIncludeTransformOperations,
+      apply_transform_origin, ComputedStyle::kIncludeMotionPath,
+      ComputedStyle::kIncludeIndependentTransformProperties);
   const float zoom = style.EffectiveZoom();
   if (zoom != 1)
     transform.Zoom(1 / zoom);
diff --git a/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc b/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
index c0e817f..41bb077 100644
--- a/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
+++ b/third_party/blink/renderer/core/loader/loader_factory_for_frame.cc
@@ -109,15 +109,17 @@
     mojo::PendingRemote<mojom::blink::KeepAliveHandle> pending_remote;
     mojo::PendingReceiver<mojom::blink::KeepAliveHandle> pending_receiver =
         pending_remote.InitWithNewPipeAndPassReceiver();
-    auto loader =
-        document_loader_->GetServiceWorkerNetworkProvider()->CreateURLLoader(
-            webreq, CreateTaskRunnerHandle(freezable_task_runner),
-            CreateTaskRunnerHandle(unfreezable_task_runner),
-            std::move(pending_remote), back_forward_cache_loader_helper);
-    if (loader) {
+    auto loader_factory = document_loader_->GetServiceWorkerNetworkProvider()
+                              ->GetSubresourceLoaderFactory(webreq);
+    if (loader_factory) {
       IssueKeepAliveHandleIfRequested(request, frame->GetLocalFrameHostRemote(),
                                       std::move(pending_receiver));
-      return loader;
+      return Platform::Current()
+          ->WrapURLLoaderFactory(std::move(loader_factory))
+          ->CreateURLLoader(
+              webreq, CreateTaskRunnerHandle(freezable_task_runner),
+              CreateTaskRunnerHandle(unfreezable_task_runner),
+              std::move(pending_remote), back_forward_cache_loader_helper);
     }
   }
 
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
index 5c073ca..97e02a5 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -461,9 +461,7 @@
   image_resource->ResponseReceived(resource_response);
   image_resource->AppendData(reinterpret_cast<const char*>(kJpegImage),
                              sizeof(kJpegImage));
-  EXPECT_NE(0u, image_resource->EncodedSizeMemoryUsageForTesting());
   image_resource->FinishForTest();
-  EXPECT_EQ(0u, image_resource->EncodedSizeMemoryUsageForTesting());
   EXPECT_FALSE(image_resource->ErrorOccurred());
   ASSERT_TRUE(image_resource->GetContent()->HasImage());
   EXPECT_FALSE(image_resource->GetContent()->GetImage()->IsNull());
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index 03b634c1..b0dcdff9 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -108,7 +108,7 @@
     // is probably good enough for a use counter.
     auto& box = To<LayoutBox>(layout_object);
     gfx::Transform matrix;
-    style.ApplyTransform(matrix, &box, box.Size(),
+    style.ApplyTransform(matrix, box.Size(),
                          ComputedStyle::kIncludeTransformOperations,
                          ComputedStyle::kExcludeTransformOrigin,
                          ComputedStyle::kExcludeMotionPath,
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 6fbccc2..e76c2cfd 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -331,8 +331,7 @@
     DCHECK(box);
     transform->MakeIdentity();
     box->StyleRef().ApplyTransform(
-        *transform, box, box->Size(),
-        ComputedStyle::kIncludeTransformOperations,
+        *transform, box->Size(), ComputedStyle::kIncludeTransformOperations,
         ComputedStyle::kIncludeTransformOrigin,
         ComputedStyle::kIncludeMotionPath,
         ComputedStyle::kIncludeIndependentTransformProperties);
@@ -2105,8 +2104,17 @@
   PhysicalRect result = LocalBoundingBox();
   ExpandRectForSelfPaintingDescendants(result);
   gfx::RectF reference_box(result);
-  if (!ResourceInfo() || ResourceInfo()->FilterReferenceBox() != reference_box)
-    GetLayoutObject().SetNeedsPaintPropertyUpdate();
+  if (!ResourceInfo() ||
+      ResourceInfo()->FilterReferenceBox() != reference_box) {
+    if (GetLayoutObject().GetDocument().Lifecycle().GetState() ==
+        DocumentLifecycle::kInPrePaint) {
+      GetLayoutObject()
+          .GetMutableForPainting()
+          .SetOnlyThisNeedsPaintPropertyUpdate();
+    } else {
+      GetLayoutObject().SetNeedsPaintPropertyUpdate();
+    }
+  }
   EnsureResourceInfo().SetFilterReferenceBox(reference_box);
 }
 
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 9707f30..a1b7e4ff 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -250,7 +250,7 @@
 
   void UpdateIndividualTransform(
       bool (*needs_property)(const LayoutObject&, CompositingReasons),
-      void (*compute_matrix)(const LayoutBox* box,
+      void (*compute_matrix)(const ComputedStyle& style,
                              const PhysicalSize& size,
                              gfx::Transform& matrix),
       CompositingReasons compositing_reasons_for_property,
@@ -1082,11 +1082,11 @@
 static TransformPaintPropertyNode::TransformAndOrigin TransformAndOriginState(
     const LayoutBox& box,
     const PhysicalSize& size,
-    void (*compute_matrix)(const LayoutBox* box,
+    void (*compute_matrix)(const ComputedStyle& style,
                            const PhysicalSize& size,
                            gfx::Transform& matrix)) {
   gfx::Transform matrix;
-  compute_matrix(&box, size, matrix);
+  compute_matrix(box.StyleRef(), size, matrix);
   return {matrix, GetTransformOrigin(box, size)};
 }
 
@@ -1099,7 +1099,7 @@
 
 void FragmentPaintPropertyTreeBuilder::UpdateIndividualTransform(
     bool (*needs_property)(const LayoutObject&, CompositingReasons),
-    void (*compute_matrix)(const LayoutBox* box,
+    void (*compute_matrix)(const ComputedStyle& style,
                            const PhysicalSize& size,
                            gfx::Transform& matrix),
     CompositingReasons compositing_reasons_for_property,
@@ -1222,9 +1222,8 @@
 void FragmentPaintPropertyTreeBuilder::UpdateTranslate() {
   UpdateIndividualTransform(
       &NeedsTranslate,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         if (style.Translate())
           style.Translate()->Apply(matrix, gfx::SizeF(size));
       },
@@ -1239,9 +1238,8 @@
 void FragmentPaintPropertyTreeBuilder::UpdateRotate() {
   UpdateIndividualTransform(
       &NeedsRotate,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         if (style.Rotate())
           style.Rotate()->Apply(matrix, gfx::SizeF(size));
       },
@@ -1255,9 +1253,8 @@
 void FragmentPaintPropertyTreeBuilder::UpdateScale() {
   UpdateIndividualTransform(
       &NeedsScale,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         if (style.Scale())
           style.Scale()->Apply(matrix, gfx::SizeF(size));
       },
@@ -1271,11 +1268,10 @@
 void FragmentPaintPropertyTreeBuilder::UpdateOffset() {
   UpdateIndividualTransform(
       &NeedsOffset,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         style.ApplyTransform(
-            matrix, box, size.ToLayoutSize(),
+            matrix, size.ToLayoutSize(),
             ComputedStyle::kExcludeTransformOperations,
             ComputedStyle::kExcludeTransformOrigin,
             ComputedStyle::kIncludeMotionPath,
@@ -1293,11 +1289,10 @@
 void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
   UpdateIndividualTransform(
       &NeedsTransform,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         style.ApplyTransform(
-            matrix, box, size.ToLayoutSize(),
+            matrix, size.ToLayoutSize(),
             ComputedStyle::kIncludeTransformOperations,
             ComputedStyle::kExcludeTransformOrigin,
             ComputedStyle::kExcludeMotionPath,
@@ -4235,11 +4230,10 @@
   auto* transform = properties->Transform();
   auto transform_and_origin = TransformAndOriginState(
       box, size,
-      [](const LayoutBox* box, const PhysicalSize& size,
+      [](const ComputedStyle& style, const PhysicalSize& size,
          gfx::Transform& matrix) {
-        const auto& style = box->StyleRef();
         style.ApplyTransform(
-            matrix, box, size.ToLayoutSize(),
+            matrix, size.ToLayoutSize(),
             ComputedStyle::kIncludeTransformOperations,
             ComputedStyle::kExcludeTransformOrigin,
             ComputedStyle::kExcludeMotionPath,
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 4a27d2e..4f410dd 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/renderer/core/html/html_body_element.h"
 #include "third_party/blink/renderer/core/html/html_html_element.h"
 #include "third_party/blink/renderer/core/html/html_progress_element.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
@@ -1341,21 +1340,19 @@
 
 void ComputedStyle::ApplyTransform(
     gfx::Transform& result,
-    const LayoutBox* box,
     const LayoutSize& border_box_size,
     ApplyTransformOperations apply_operations,
     ApplyTransformOrigin apply_origin,
     ApplyMotionPath apply_motion_path,
     ApplyIndependentTransformProperties apply_independent_transform_properties)
     const {
-  ApplyTransform(result, box, gfx::RectF(gfx::SizeF(border_box_size)),
+  ApplyTransform(result, gfx::RectF(gfx::SizeF(border_box_size)),
                  apply_operations, apply_origin, apply_motion_path,
                  apply_independent_transform_properties);
 }
 
 void ComputedStyle::ApplyTransform(
     gfx::Transform& result,
-    const LayoutBox* box,
     const gfx::RectF& bounding_box,
     ApplyTransformOperations apply_operations,
     ApplyTransformOrigin apply_origin,
@@ -1403,7 +1400,7 @@
   }
 
   if (apply_motion_path == kIncludeMotionPath) {
-    ApplyMotionPathTransform(origin_x, origin_y, box, bounding_box, result);
+    ApplyMotionPathTransform(origin_x, origin_y, bounding_box, result);
   }
 
   if (apply_operations == kIncludeTransformOperations) {
@@ -1421,111 +1418,56 @@
   return FilterInternal().Get() && !FilterInternal()->operations_.IsEmpty();
 }
 
-static const LayoutBox* GetContainingBox(const LayoutBox* box,
-                                         const EPosition& position) {
-  if (!box) {
-    return nullptr;
-  }
-  if (position == EPosition::kStatic || position == EPosition::kRelative) {
-    return box->ParentBox();
-  }
-  if (position == EPosition::kSticky) {
-    return box->ContainingScrollContainer();
-  }
-  LayoutObject* container = nullptr;
-  if (position == EPosition::kAbsolute) {
-    container = box->ContainerForAbsolutePosition();
-  }
-  if (position == EPosition::kFixed) {
-    container = box->ContainerForFixedPosition();
-  }
-  if (container) {
-    return container->EnclosingBox();
-  }
-  return nullptr;
-}
-
-static gfx::SizeF GetContainingBoxSize(const LayoutBox* box,
-                                       const EPosition& position,
-                                       const gfx::RectF& bounding_box) {
-  const auto* containing_box = GetContainingBox(box, position);
-  if (containing_box) {
-    // FIXME(sakhapov): return based <coord-box> once the spec is clarified.
-    return gfx::SizeF(containing_box->ContentSize());
-  }
-  return bounding_box.size();
-}
-
-static gfx::PointF GetOffsetFromContainingBox(const LayoutBox* box) {
-  if (box && box->ParentBox()) {
-    if (Element* element = DynamicTo<Element>(box->ParentBox()->GetNode())) {
-      const auto& offset = box->OffsetPoint(element);
-      return {offset.left, offset.top};
-    }
-  }
-  return {0, 0};
-}
-
-static gfx::PointF GetInitialPositionForMotionPath(
-    const LayoutBox* box,
-    const LengthPoint& offset_position,
-    const gfx::SizeF& containing_box_size) {
-  if (offset_position.X().IsAuto()) {
-    return GetOffsetFromContainingBox(box);
-  }
-  return PointForLengthPoint(offset_position, containing_box_size);
-}
-
-PointAndTangent ComputedStyle::CalculatePointAndTangentOnRay(
-    const LayoutBox* box,
-    const gfx::RectF& bounding_box,
-    const gfx::PointF& anchor_point) const {
-  const auto& ray = To<StyleRay>(*OffsetPath());
-  const gfx::SizeF containing_box_size =
-      GetContainingBoxSize(box, PositionInternal(), bounding_box);
-  const gfx::PointF initial_position = GetInitialPositionForMotionPath(
-      box, OffsetPosition(), containing_box_size);
-  const float path_length =
-      ray.CalculateLength(anchor_point, OffsetDistance(), OffsetRotate(),
-                          initial_position, bounding_box, containing_box_size);
-  return ray.PointAndNormalAtLength(path_length);
-}
-
-PointAndTangent ComputedStyle::CalculatePointAndTangentOnPath() const {
-  float zoom = EffectiveZoom();
-  const StylePath& path = To<StylePath>(*OffsetPath());
-  float path_length = path.length();
-  float float_distance =
-      FloatValueForLength(OffsetDistance(), path_length * zoom) / zoom;
-  float computed_distance;
-  if (path.IsClosed() && path_length > 0) {
-    computed_distance = fmod(float_distance, path_length);
-    if (computed_distance < 0) {
-      computed_distance += path_length;
-    }
-  } else {
-    computed_distance = ClampTo<float>(float_distance, 0, path_length);
-  }
-  PointAndTangent path_position =
-      path.GetPath().PointAndNormalAtLength(computed_distance);
-  path_position.point.Scale(zoom, zoom);
-  return path_position;
-}
-
 void ComputedStyle::ApplyMotionPathTransform(float origin_x,
                                              float origin_y,
-                                             const LayoutBox* box,
                                              const gfx::RectF& bounding_box,
                                              gfx::Transform& transform) const {
   // TODO(ericwilligers): crbug.com/638055 Apply offset-position.
-  const BasicShape* path = OffsetPath();
-  if (!path) {
+  if (!OffsetPath()) {
     return;
   }
   const LengthPoint& position = OffsetPosition();
   const LengthPoint& anchor = OffsetAnchor();
+  const Length& distance = OffsetDistance();
+  const BasicShape* path = OffsetPath();
   const StyleOffsetRotation& rotate = OffsetRotate();
 
+  PointAndTangent path_position;
+  if (path->GetType() == BasicShape::kStyleRayType) {
+    // TODO(ericwilligers): crbug.com/641245 Support <size> for ray paths.
+    float float_distance = FloatValueForLength(distance, 0);
+
+    // Use ClampTo() to convert infinite values to min/max finite ones.
+    path_position.tangent_in_degrees =
+        ClampTo<float, float>(To<StyleRay>(*path).Angle() - 90);
+    float tangent_in_radians = Deg2rad(path_position.tangent_in_degrees);
+    path_position.point.set_x(float_distance * cos(tangent_in_radians));
+    path_position.point.set_y(float_distance * sin(tangent_in_radians));
+  } else {
+    float zoom = EffectiveZoom();
+    const StylePath& motion_path = To<StylePath>(*path);
+    float path_length = motion_path.length();
+    float float_distance =
+        FloatValueForLength(distance, path_length * zoom) / zoom;
+    float computed_distance;
+    if (motion_path.IsClosed() && path_length > 0) {
+      computed_distance = fmod(float_distance, path_length);
+      if (computed_distance < 0) {
+        computed_distance += path_length;
+      }
+    } else {
+      computed_distance = ClampTo<float>(float_distance, 0, path_length);
+    }
+
+    path_position =
+        motion_path.GetPath().PointAndNormalAtLength(computed_distance);
+    path_position.point.Scale(zoom, zoom);
+  }
+
+  if (rotate.type == OffsetRotationType::kFixed) {
+    path_position.tangent_in_degrees = 0;
+  }
+
   float origin_shift_x = 0;
   float origin_shift_y = 0;
   // If the offset-position and offset-anchor properties are not yet enabled,
@@ -1540,18 +1482,6 @@
     origin_shift_y = anchor_point.y() - origin_y;
   }
 
-  PointAndTangent path_position;
-  if (path->GetType() == BasicShape::kStyleRayType) {
-    path_position =
-        CalculatePointAndTangentOnRay(box, bounding_box, anchor_point);
-  } else {
-    path_position = CalculatePointAndTangentOnPath();
-  }
-
-  if (rotate.type == OffsetRotationType::kFixed) {
-    path_position.tangent_in_degrees = 0;
-  }
-
   transform.Translate(
       path_position.point.x() - anchor_point.x() + origin_shift_x,
       path_position.point.y() - anchor_point.y() + origin_shift_y);
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 9944a16..f140b973 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -63,7 +63,6 @@
 #include "third_party/blink/renderer/platform/geometry/length_point.h"
 #include "third_party/blink/renderer/platform/geometry/length_size.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/path.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
@@ -2035,14 +2034,12 @@
     kExcludeTransformOperations
   };
   void ApplyTransform(gfx::Transform&,
-                      const LayoutBox* box,
                       const LayoutSize& border_box_data_size,
                       ApplyTransformOperations,
                       ApplyTransformOrigin,
                       ApplyMotionPath,
                       ApplyIndependentTransformProperties) const;
   void ApplyTransform(gfx::Transform&,
-                      const LayoutBox* box,
                       const gfx::RectF& bounding_box,
                       ApplyTransformOperations,
                       ApplyTransformOrigin,
@@ -2528,14 +2525,8 @@
 
   void ApplyMotionPathTransform(float origin_x,
                                 float origin_y,
-                                const LayoutBox* box,
                                 const gfx::RectF& bounding_box,
                                 gfx::Transform&) const;
-  PointAndTangent CalculatePointAndTangentOnRay(
-      const LayoutBox* box,
-      const gfx::RectF& bounding_box,
-      const gfx::PointF& anchor_point) const;
-  PointAndTangent CalculatePointAndTangentOnPath() const;
 
   bool ScrollAnchorDisablingPropertyChanged(const ComputedStyle& other,
                                             const StyleDifference&) const;
@@ -3440,8 +3431,6 @@
   void AddAppliedTextDecoration(const AppliedTextDecoration&);
   void OverrideTextDecorationColors(blink::Color propagated_color);
 
-  ComputedStyleBuilder() = default;
-
   scoped_refptr<ComputedStyle> style_;
 };
 
diff --git a/third_party/blink/renderer/core/style/style_ray.cc b/third_party/blink/renderer/core/style/style_ray.cc
index cc6f664..f8f6b2e 100644
--- a/third_party/blink/renderer/core/style/style_ray.cc
+++ b/third_party/blink/renderer/core/style/style_ray.cc
@@ -3,12 +3,6 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/core/style/style_ray.h"
-#include "third_party/blink/renderer/core/style/style_offset_rotation.h"
-#include "third_party/blink/renderer/platform/geometry/length_functions.h"
-#include "third_party/blink/renderer/platform/graphics/path.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/size_f.h"
 
 #include "base/notreached.h"
 
@@ -35,197 +29,4 @@
   NOTREACHED();
 }
 
-static float CalculatePerpendicularDistanceToBoundingBoxSide(
-    const gfx::PointF& point,
-    const gfx::SizeF& box_size,
-    float (*comp)(std::initializer_list<float>)) {
-  return comp({std::abs(point.x()), std::abs(point.x() - box_size.width()),
-               std::abs(point.y()), std::abs(point.y() - box_size.height())});
-}
-
-static float CalculateDistance(const gfx::PointF& a, const gfx::PointF& b) {
-  return (a - b).Length();
-}
-
-float CalculateDistanceToBoundingBoxCorner(
-    const gfx::PointF& point,
-    const gfx::SizeF& box_size,
-    float (*comp)(std::initializer_list<float>)) {
-  return comp({CalculateDistance(point, {0, 0}),
-               CalculateDistance(point, {box_size.width(), 0}),
-               CalculateDistance(point, {box_size.width(), box_size.height()}),
-               CalculateDistance(point, {0, box_size.height()})});
-}
-
-static float CalculateDistanceToBoundingBoxSide(const gfx::PointF& point,
-                                                const float angle,
-                                                const gfx::SizeF& box_size) {
-  if (!gfx::RectF(box_size).InclusiveContains(point)) {
-    return 0;
-  }
-  const float theta = Deg2rad(angle);
-  float cos_t = cos(theta);
-  float sin_t = sin(theta);
-  // We are looking for % point, let's swap signs and lines
-  // so that we end up in situation like this:
-  //         (0, 0) #--------------%--# (box.width, 0)
-  //                |        |    /   |
-  //                |        v   /    |
-  //                |        |  /     |
-  //                |        |t/      |
-  //                |        |/       |
-  //                 (point) *---h----* (box.width, point.y)
-  //                |        |        |
-  //                |        |        |
-  // (0, box.height)#-----------------# (box.width, box.height)
-
-  // cos_t and sin_t swapped due to the 0 angle is pointing up.
-  const float vertical = cos_t >= 0 ? point.y() : box_size.height() - point.y();
-  const float horizontal =
-      sin_t >= 0 ? box_size.width() - point.x() : point.x();
-  cos_t = abs(cos_t);
-  sin_t = abs(sin_t);
-  // Check what side we hit.
-  if (vertical * sin_t > horizontal * cos_t) {
-    return horizontal / sin_t;
-  }
-  return vertical / cos_t;
-}
-
-float StyleRay::CalculateRayPathLength(
-    const gfx::PointF& initial_position,
-    const gfx::SizeF& containing_box_size) const {
-  switch (Size()) {
-    case StyleRay::RaySize::kClosestSide:
-      return CalculatePerpendicularDistanceToBoundingBoxSide(
-          initial_position, containing_box_size, std::min);
-    case StyleRay::RaySize::kFarthestSide:
-      return CalculatePerpendicularDistanceToBoundingBoxSide(
-          initial_position, containing_box_size, std::max);
-    case StyleRay::RaySize::kClosestCorner:
-      return CalculateDistanceToBoundingBoxCorner(
-          initial_position, containing_box_size, std::min);
-    case StyleRay::RaySize::kFarthestCorner:
-      return CalculateDistanceToBoundingBoxCorner(
-          initial_position, containing_box_size, std::max);
-    case StyleRay::RaySize::kSides:
-      return CalculateDistanceToBoundingBoxSide(initial_position, Angle(),
-                                                containing_box_size);
-  }
-}
-
-static void RotateVertices(std::array<gfx::PointF, 4>& vertices,
-                           const float ray_angle,
-                           const StyleOffsetRotation& rotate) {
-  // https://drafts.fxtf.org/motion/#offset-rotate-property
-  // For ray paths, the rotation implied by auto is 90 degrees less
-  // than the ray’s bearing <angle>.
-  float angle = rotate.angle;
-  // NOTE: rotation type 'reverse' is handled during parsing and translated to
-  // auto, 180deg.
-  if (rotate.type == OffsetRotationType::kAuto) {
-    angle += ray_angle - 90;
-  }
-  // Rotate ray to x-axis + rotate object by its rotate angle.
-  const float angle_to_x_axis = Deg2rad(angle + 90 - ray_angle);
-  const float cos_t = cos(angle_to_x_axis);
-  const float sin_t = sin(angle_to_x_axis);
-  for (auto& v : vertices) {
-    const float vx = v.x();
-    const float vy = v.y();
-    v.set_x(cos_t * vx - sin_t * vy);
-    v.set_y(cos_t * vy + sin_t * vx);
-  }
-}
-
-float StyleRay::CalculateLength(const gfx::PointF& anchor,
-                                const Length& offset_distance,
-                                const StyleOffsetRotation& offset_rotate,
-                                const gfx::PointF& initial_position,
-                                const gfx::RectF& bounding_box,
-                                const gfx::SizeF& containing_box_size) const {
-  const float ray_length =
-      CalculateRayPathLength(initial_position, containing_box_size);
-  float float_length = FloatValueForLength(offset_distance, ray_length);
-  if (!Contain()) {
-    return float_length;
-  }
-  const float width = bounding_box.width();
-  const float height = bounding_box.height();
-  std::array<gfx::PointF, 4> vertices{{
-      {-anchor.x(), -anchor.y()},
-      {width - anchor.x(), -anchor.y()},
-      {width - anchor.x(), height - anchor.y()},
-      {-anchor.x(), height - anchor.y()},
-  }};
-  // Rotate ray to x axis;
-  RotateVertices(vertices, Angle(), offset_rotate);
-  float upper = std::numeric_limits<float>::max();
-  float lower = std::numeric_limits<float>::lowest();
-  bool should_increase = false;
-  // Find path intervals that enclose the box.
-  for (const auto& v : vertices) {
-    const float d = ray_length * ray_length - v.y() * v.y();
-    if (d < 0) {
-      should_increase = true;
-      break;
-    }
-    const float sqrt_d = sqrt(d);
-    upper = std::min(upper, -v.x() + sqrt_d);
-    lower = std::max(lower, -v.x() - sqrt_d);
-  }
-  if (!should_increase) {
-    return std::max(lower, std::min(upper, float_length));
-  }
-
-  // Path length should be increased.
-  // We find the smallest path length such that an offset exists
-  // for all vertices to lie within the path.
-  const auto comp = [](const auto& a, const auto& b) {
-    return std::abs(a.y()) >= std::abs(b.y());
-  };
-  std::sort(vertices.begin(), vertices.end(), comp);
-  float radius = std::abs(vertices[0].y());
-  float_length = -vertices[0].x();
-  const float eps = 1e-5;
-
-  // Find the path length such that, for some offset,
-  // vertices[i] and vertices[j] both lie within the path.
-  for (size_t i = 0; i < 3; ++i) {
-    for (size_t j = i + 1; j < 4; ++j) {
-      const float xi = vertices[i].x();
-      const float yi = vertices[i].y();
-      const float xj = vertices[j].x();
-      const float yj = vertices[j].y();
-      const float dx = xi - xj;
-
-      // Any path that encloses vertices[i] would also enclose vertices[j].
-      if (dx * dx + yj * yj <= yi * yi + eps) {
-        continue;
-      }
-
-      // If both lie on the path,
-      // (offset + xi)**2 + yi**2 = (offset + xj)**2 + yj**2 = (path length)**2
-      // 2 * xi * offset + xi**2 + yi**2 = 2 * xj * offset + xj**2 + yj**2
-      const float new_length =
-          (xj * xj + yj * yj - xi * xi - yi * yi) / dx / 2.0;
-      const float x0 = xi + new_length;
-      const float new_radius = sqrt(x0 * x0 + yi * yi);
-      if (new_radius > radius) {
-        radius = new_radius;
-        float_length = new_length;
-      }
-    }
-  }
-  return float_length;
-}
-
-PointAndTangent StyleRay::PointAndNormalAtLength(float length) const {
-  const float angle = Angle() - 90;
-  const float rad = Deg2rad(angle);
-  const float x = length * cos(rad);
-  const float y = length * sin(rad);
-  return {{x, y}, angle};
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_ray.h b/third_party/blink/renderer/core/style/style_ray.h
index cc3d335..a1bf4ee 100644
--- a/third_party/blink/renderer/core/style/style_ray.h
+++ b/third_party/blink/renderer/core/style/style_ray.h
@@ -6,16 +6,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_RAY_H_
 
 #include "third_party/blink/renderer/core/style/basic_shapes.h"
-
-namespace gfx {
-class PointF;
-}
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
-struct PointAndTangent;
-struct StyleOffsetRotation;
-
 class StyleRay : public BasicShape {
  public:
   enum class RaySize {
@@ -29,17 +23,7 @@
   static scoped_refptr<StyleRay> Create(float angle, RaySize, bool contain);
   ~StyleRay() override = default;
 
-  float CalculateRayPathLength(const gfx::PointF& initial_position,
-                               const gfx::SizeF& containing_box_size) const;
-  float CalculateLength(const gfx::PointF& anchor,
-                        const Length& offset_distance,
-                        const StyleOffsetRotation& offset_rotate,
-                        const gfx::PointF& initial_position,
-                        const gfx::RectF& bounding_box,
-                        const gfx::SizeF& containing_box_size) const;
-  PointAndTangent PointAndNormalAtLength(float length) const;
-
-  float Angle() const { return ClampTo<float, float>(angle_); }
+  float Angle() const { return angle_; }
   RaySize Size() const { return size_; }
   bool Contain() const { return contain_; }
 
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 2828818..2025225 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2272,6 +2272,9 @@
   document->View()->UpdateAllLifecyclePhasesForTest();
 
   auto* hit_test_rects = MakeGarbageCollected<HitTestLayerRectList>();
+  if (!document->View()->RootCcLayer()) {
+    return hit_test_rects;
+  }
   for (const auto& layer : document->View()->RootCcLayer()->children()) {
     const cc::TouchActionRegion& touch_action_region =
         layer->touch_action_region();
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
index bf7c4bb..7406dad 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
@@ -185,15 +185,6 @@
   return transition_;
 }
 
-void ViewTransitionSupplement::UpdateViewTransitionNames(
-    const Element& element,
-    const ComputedStyle* style) {
-  if (style && style->ViewTransitionName())
-    elements_with_view_transition_name_.insert(&element);
-  else
-    elements_with_view_transition_name_.erase(&element);
-}
-
 ViewTransitionSupplement::ViewTransitionSupplement(Document& document)
     : Supplement<Document>(document) {}
 
@@ -201,7 +192,6 @@
 
 void ViewTransitionSupplement::Trace(Visitor* visitor) const {
   visitor->Trace(transition_);
-  visitor->Trace(elements_with_view_transition_name_);
 
   Supplement<Document>::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_supplement.h b/third_party/blink/renderer/core/view_transition/view_transition_supplement.h
index 0068aee..53d97661 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_supplement.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition_supplement.h
@@ -51,14 +51,6 @@
 
   ViewTransition* GetActiveTransition();
 
-  // Tracks the set of elements with a valid |view-transition-name|.
-  void UpdateViewTransitionNames(const Element& element,
-                                 const ComputedStyle* style);
-  const HeapHashSet<Member<const Element>>& ElementsWithViewTransitionName()
-      const {
-    return elements_with_view_transition_name_;
-  }
-
   explicit ViewTransitionSupplement(Document&);
   ~ViewTransitionSupplement() override;
 
@@ -92,8 +84,6 @@
 
   VectorOf<std::unique_ptr<ViewTransitionRequest>> pending_requests_;
 
-  HeapHashSet<Member<const Element>> elements_with_view_transition_name_;
-
   mojom::ViewTransitionSameOriginOptIn same_origin_opt_in_ =
       mojom::ViewTransitionSameOriginOptIn::kDisabled;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
index 5547a7f..4b9eb5f5 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -281,6 +281,18 @@
                                    {44100, 48000})) {
           return false;
         }
+#if BUILDFLAG(IS_MAC)
+        if (config->options.aac.has_value() &&
+            config->options.aac->format ==
+                media::AudioEncoder::AacOutputFormat::ADTS) {
+          if (exception_state) {
+            exception_state->ThrowDOMException(
+                DOMExceptionCode::kNotSupportedError,
+                "ADTS is not supported on Mac yet");
+          }
+          return false;
+        }
+#endif  // BUILDFLAG(IS_MAC)
 
         return true;
       }
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index c8d72af..4af008c 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -305,6 +305,11 @@
   return nullptr;
 }
 
+std::unique_ptr<WebURLLoaderFactory> Platform::WrapURLLoaderFactory(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return nullptr;
+}
+
 std::unique_ptr<WebDedicatedWorkerHostFactoryClient>
 Platform::CreateDedicatedWorkerHostFactoryClient(
     WebDedicatedWorker*,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc
index 286dbba6..b72f0f5 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -144,7 +144,6 @@
     : type_(type),
       status_(ResourceStatus::kNotStarted),
       encoded_size_(0),
-      encoded_size_memory_usage_(0),
       decoded_size_(0),
       cache_identifier_(MemoryCache::DefaultCacheIdentifier()),
       link_preload_(false),
@@ -278,7 +277,6 @@
 
 void Resource::ClearData() {
   data_ = nullptr;
-  encoded_size_memory_usage_ = 0;
 }
 
 void Resource::TriggerNotificationForFinishObservers(
@@ -684,12 +682,11 @@
 }
 
 void Resource::SetEncodedSize(size_t encoded_size) {
-  if (encoded_size == encoded_size_ &&
-      encoded_size == encoded_size_memory_usage_)
+  if (encoded_size == encoded_size_) {
     return;
+  }
   size_t old_size = size();
   encoded_size_ = encoded_size;
-  encoded_size_memory_usage_ = encoded_size;
   if (IsMainThread())
     MemoryCache::Get()->Update(this, old_size, size());
 }
@@ -852,11 +849,6 @@
   const String dump_name = GetMemoryDumpName();
   WebMemoryAllocatorDump* dump =
       memory_dump->CreateMemoryAllocatorDump(dump_name);
-  dump->AddScalar("encoded_size", "bytes", encoded_size_memory_usage_);
-  if (HasClientsOrObservers())
-    dump->AddScalar("live_size", "bytes", encoded_size_memory_usage_);
-  else
-    dump->AddScalar("dead_size", "bytes", encoded_size_memory_usage_);
 
   if (data_)
     GetSharedBufferMemoryDump(Data(), dump_name, memory_dump);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h
index 5d99c79..eb7b8a5 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -226,16 +226,6 @@
   // need to be refactored (crbug/643135).
   size_t EncodedSize() const { return encoded_size_; }
 
-  // Returns the current memory usage for the encoded data. Adding a new usage
-  // of this function is not recommended as the same reason as |EncodedSize()|.
-  //
-  // |EncodedSize()| and |EncodedSizeMemoryUsageForTesting()| can return
-  // different values, e.g., when ImageResource purges encoded image data after
-  // finishing loading.
-  size_t EncodedSizeMemoryUsageForTesting() const {
-    return encoded_size_memory_usage_;
-  }
-
   size_t DecodedSize() const { return decoded_size_; }
   size_t OverheadSize() const { return overhead_size_; }
   virtual size_t CodeCacheSize() const { return 0; }
@@ -532,7 +522,6 @@
   base::TimeTicks load_response_end_;
 
   size_t encoded_size_;
-  size_t encoded_size_memory_usage_;
   size_t decoded_size_;
 
   String cache_identifier_;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index be0ba1d3..f40bf9e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2759,6 +2759,18 @@
 crbug.com/798257 external/wpt/css/css-pseudo/first-line-line-height-002.html [ Failure ]
 
 # motion-1 issues
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-002.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-003.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-004.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-005.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-006.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-007.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-009.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-contain-001.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-contain-002.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-contain-003.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-contain-004.html [ Failure ]
+crbug.com/641245 external/wpt/css/motion/offset-path-ray-contain-005.html [ Failure ]
 crbug.com/654669 external/wpt/css/motion/offset-path-shape.html [ Failure ]
 crbug.com/654666 external/wpt/css/motion/offset-path-url.html [ Failure ]
 
@@ -6352,7 +6364,6 @@
 crbug.com/1395840 [ Mac12 ] http/tests/accessibility/slow-document-load.html [ Failure ]
 crbug.com/1395840 [ Mac12-arm64 Release ] http/tests/accessibility/slow-document-load.html [ Failure ]
 crbug.com/1395840 [ Mac13-arm64 Release ] http/tests/accessibility/slow-document-load.html [ Failure ]
-crbug.com/1404767 [ Debug Linux ] external/wpt/css/css-cascade/all-prop-revert-layer-noop.html [ Failure Timeout ]
 crbug.com/1406027 [ Win ] virtual/media-foundation-for-clear-dcomp/media/controls/overflow-menu-hide-on-resize.html [ Failure ]
 crbug.com/1289607 [ Linux ] external/wpt/cookie-store/cookieStore_subscribe_arguments.https.any.html [ Failure ]
 crbug.com/1408294 [ Debug Linux ] virtual/gpu/external/wpt/mediacapture-record/MediaRecorder-canvas-media-source.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 1a5f490..49723825 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -896,13 +896,6 @@
     "expires": "Jul 1, 2023"
   },
   {
-    "prefix": "top-level-storage-access-api",
-    "platforms": ["Linux", "Mac", "Win"],
-    "bases": [ "external/wpt/top-level-storage-access-api" ],
-    "args": [ "--enable-features=StorageAccessAPI,StorageAccessAPIForOriginExtension" ],
-    "expires": "Jul 1, 2023"
-  },
-  {
     "prefix": "web-bluetooth-new-permissions-backend",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["wpt_internal/bluetooth", "external/wpt/bluetooth"],
diff --git a/third_party/blink/web_tests/WebDriverExpectations b/third_party/blink/web_tests/WebDriverExpectations
index 7662d2c..982b8f0 100644
--- a/third_party/blink/web_tests/WebDriverExpectations
+++ b/third_party/blink/web_tests/WebDriverExpectations
@@ -641,3 +641,7 @@
 crbug.com/1325690 [ Linux ] external/wpt/webdriver/tests/take_screenshot/user_prompts.py>>test_dismiss[capabilities0-prompt-None] [ Failure Pass ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_touch.py>>test_touch_pointer_properties [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/perform_actions/pointer_touch.py>>test_touch_pointer_properties_tilt_twist [ Failure ]
+crbug.com/1414111 [ Linux ] external/wpt/webdriver/tests/forward/forward.py>>test_dismissed_beforeunload [ Failure ]
+crbug.com/1414111 [ Linux ] external/wpt/webdriver/tests/refresh/refresh.py>>test_dismissed_beforeunload [ Failure ]
+crbug.com/1414111 [ Linux ] external/wpt/webdriver/tests/refresh/refresh.py>>test_history_pushstate [ Failure ]
+crbug.com/1414111 [ Linux ] external/wpt/webdriver/tests/refresh/refresh.py>>test_refresh_switches_to_parent_browsing_context [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-layer-noop.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-layer-noop.html
index 66aa2b9..5c31c58 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-layer-noop.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-layer-noop.html
@@ -4,6 +4,18 @@
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
 <link rel="help" href="https://www.w3.org/TR/css-cascade-5/#revert-layer">
 <meta name="assert" content="Checks that adding 'all: revert-layer' inside @layer has no effect on elements with no other author rules.">
+<!-- Split into chunks to avoid timeouts. -->
+<meta name="variant" content="?include=0">
+<meta name="variant" content="?include=1">
+<meta name="variant" content="?include=2">
+<meta name="variant" content="?include=3">
+<meta name="variant" content="?include=4">
+<meta name="variant" content="?include=5">
+<meta name="variant" content="?include=6">
+<meta name="variant" content="?include=7">
+<script>
+  const CHUNKS = 8;
+</script>
 
 <style>
 @layer {
@@ -16,6 +28,7 @@
 <div id="log"></div>
 <div id="wrapper"></div>
 
+<script src="/common/subset-tests-by-key.js"></script>
 <script src="/html/resources/common.js"></script>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -41,8 +54,10 @@
 
 const wrapper = document.getElementById("wrapper");
 const elementNames = [...HTML5_ELEMENTS, "math", "svg", "z-custom"].sort();
-for (let elementName of elementNames) {
-  test(function() {
+for (let i = 0; i < elementNames.length; ++i) {
+  let elementName = elementNames[i];
+  let chunk = i % CHUNKS;
+  subsetTestByKey(chunk.toString(), test, function() {
     const element = document.createElement(elementName);
     wrapper.appendChild(element);
     const style = getComputedStyle(element);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
index d70fa530..e8f560d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/all-prop-revert-noop.html
@@ -4,7 +4,18 @@
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
 <link rel="help" href="https://www.w3.org/TR/css-cascade-4/#default">
 <meta name="assert" content="Checks that adding 'all: revert' has no effect on elements with no other author rules.">
-<meta name="timeout" content="long">
+<!-- Split into chunks to avoid timeouts. -->
+<meta name="variant" content="?include=0">
+<meta name="variant" content="?include=1">
+<meta name="variant" content="?include=2">
+<meta name="variant" content="?include=3">
+<meta name="variant" content="?include=4">
+<meta name="variant" content="?include=5">
+<meta name="variant" content="?include=6">
+<meta name="variant" content="?include=7">
+<script>
+  const CHUNKS = 8;
+</script>
 
 <style>
 .revert-all {
@@ -15,6 +26,7 @@
 <div id="log"></div>
 <div id="wrapper"></div>
 
+<script src="/common/subset-tests-by-key.js"></script>
 <script src="/html/resources/common.js"></script>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -40,8 +52,10 @@
 
 const wrapper = document.getElementById("wrapper");
 const elementNames = [...HTML5_ELEMENTS, "math", "svg", "z-custom"].sort();
-for (let elementName of elementNames) {
-  test(function() {
+for (let i = 0; i < elementNames.length; ++i) {
+  let elementName = elementNames[i];
+  let chunk = i % CHUNKS;
+  subsetTestByKey(chunk.toString(), test, function() {
     const element = document.createElement(elementName);
     wrapper.appendChild(element);
     const style = getComputedStyle(element);
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-002.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-002.html.ini
new file mode 100644
index 0000000..0dc1929
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-002.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-002.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-003.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-003.html.ini
new file mode 100644
index 0000000..6e6b6c0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-003.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-004.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-004.html.ini
new file mode 100644
index 0000000..c5c4730
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-004.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-004.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-005.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-005.html.ini
new file mode 100644
index 0000000..576f2b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-005.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-005.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-006.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-006.html.ini
new file mode 100644
index 0000000..8cd4502
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-006.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-006.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-007.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-007.html.ini
new file mode 100644
index 0000000..4b79075
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-007.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-007.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-009.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-009.html.ini
new file mode 100644
index 0000000..91127da
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-009.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-009.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-001.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-001.html.ini
new file mode 100644
index 0000000..f15f5cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-001.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-contain-001.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-002.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-002.html.ini
new file mode 100644
index 0000000..0362210
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-002.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-contain-002.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-003.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-003.html.ini
new file mode 100644
index 0000000..01290e50
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-003.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-contain-003.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004-ref.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004-ref.html
index 2d62445..38b0d44 100644
--- a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004-ref.html
@@ -15,7 +15,7 @@
         height: 100px;
         background-color: lime;
         /* The movement is about sqrt(150^2 - 50^2) - 50 */
-        transform: rotate(-45deg) translate(91.4214px);
+        transform: rotate(-45deg) translate(91.42px);
       }
     </style>
   </head>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004.html.ini
new file mode 100644
index 0000000..eca174c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-004.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-contain-004.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-005.html.ini b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-005.html.ini
new file mode 100644
index 0000000..7fdbe8d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-ray-contain-005.html.ini
@@ -0,0 +1,2 @@
+[offset-path-ray-contain-005.html]
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior-ref.html
new file mode 100644
index 0000000..bf468c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="support/fake-selectmenu.js"></script>
+<body>
+<script>
+  const selectmenu = createFakeSelectmenu('hello world');
+  document.body.appendChild(selectmenu);
+  selectmenu.querySelector('.fake-selectmenu-selected-value')
+    .style.color = 'blue';
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior.tentative.html
new file mode 100644
index 0000000..799b445
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-behavior.tentative.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=match href="selectmenu-selected-value-behavior-ref.html">
+
+<selectmenu>
+  <div style="color:blue" slot=selected-value behavior=selected-value></div>
+  <option>hello world</option>
+</selectmenu>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part-ref.html
new file mode 100644
index 0000000..744846b5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script src="support/fake-selectmenu.js"></script>
+<body>
+<script>
+  const selectmenu = createFakeSelectmenu('hello world');
+  document.body.appendChild(selectmenu);
+  selectmenu.querySelector('.fake-selectmenu-selected-value')
+    .style.backgroundColor = 'red';
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part.tentative.html
new file mode 100644
index 0000000..e41d2dd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-part.tentative.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=match href="selectmenu-selected-value-part-ref.html">
+
+<style>
+selectmenu::part(selected-value) {
+  background-color: red;
+}
+</style>
+<selectmenu>
+  <option>hello world</option>
+</selectmenu>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot-ref.html
new file mode 100644
index 0000000..1320583
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="support/fake-selectmenu.js"></script>
+<body>
+<script>
+  const selectmenu = createFakeSelectmenu('hello world');
+  document.body.appendChild(selectmenu);
+
+  const oldSelectedValue = selectmenu.querySelector('.fake-selectmenu-selected-value');
+  const newSelectedValue = document.createElement('div');
+  newSelectedValue.textContent = 'new selected value';
+
+  const button = selectmenu.querySelector('.fake-selectmenu-internal-selectmenu-button');
+  button.replaceChild(newSelectedValue, oldSelectedValue);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot.tentative.html
new file mode 100644
index 0000000..9bbf2df
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-selected-value-slot.tentative.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=match href="selectmenu-selected-value-slot-ref.html">
+
+<selectmenu>
+  <div slot=selected-value>new selected value</div>
+  <option>hello world</option>
+</selectmenu>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/set-metadata.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/set-metadata.https.html.ini
index d7ee1367..2c62b325 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/set-metadata.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/set-metadata.https.html.ini
@@ -1,3 +1,3 @@
 [set-metadata.https.html]
-  [[VP8] setMetadata() carries over codec-specific properties]
+  [[VP8\] setMetadata() carries over codec-specific properties]
     expected: [PASS, FAIL] # Temporarily disable to allow WebRTC roll before required Chrome changes land in crrev.com/c/4224473
diff --git a/third_party/blink/web_tests/fast/events/touch/empty-iframe-touch-hit-rects-crash.html b/third_party/blink/web_tests/fast/events/touch/empty-iframe-touch-hit-rects-crash.html
new file mode 100644
index 0000000..164ae26d
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/touch/empty-iframe-touch-hit-rects-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<iframe src="#empty"></iframe>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(()=> {
+  if (window.internals)
+    internals.touchEventTargetLayerRects(document);
+});
+</script>
diff --git a/third_party/blink/web_tests/virtual/top-level-storage-access-api/README.md b/third_party/blink/web_tests/virtual/top-level-storage-access-api/README.md
deleted file mode 100644
index 68a1bd9..0000000
--- a/third_party/blink/web_tests/virtual/top-level-storage-access-api/README.md
+++ /dev/null
@@ -1 +0,0 @@
-See third_party/blink/web_tests/external/wpt/top-level-storage-access-api/README.md
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-multicol/box-reflect-quirk-crash.html b/third_party/blink/web_tests/wpt_internal/css/css-multicol/box-reflect-quirk-crash.html
new file mode 100644
index 0000000..24e7b0d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-multicol/box-reflect-quirk-crash.html
@@ -0,0 +1,32 @@
+<link rel="help" href="https://crbug.com/1403599">
+<style>
+#foo {
+  -webkit-box-reflect: right 1px;
+  border-inline-start-style: dashed;
+  content: url();
+  transition-duration: 6s;
+  height: 1;
+}
+</style>
+<script>
+  function runTest(){
+    document.elementFromPoint(0, 0);
+
+    let node = foo.removeChild(bar);
+    target.appendChild(node);
+
+    document.fgColor = "1";
+  }
+</script>
+<body onload="runTest();")>
+  <div style="columns: 1px;">
+    <span id="target">
+      <ul style="float: left;">
+        <div id="foo">
+          <div id="bar">
+          </div>
+        </div>
+      </ul>
+    </span>
+  </div>
+</body>
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 742ea25..e8433170 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-12-1-180-g27b2cd410
-Revision: 27b2cd4101dfcf7d03904204e078b2de84cce8c4
+Version: VER-2-12-1-181-g4c3916e90
+Revision: 4c3916e901ac88243321b7518c023dc8c51a7586
 CPEPrefix: cpe:/a:freetype:freetype:2.12.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 8baa4e4..09091499 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2014 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni
index a7e8485..8dd0cef 100644
--- a/tools/grit/grit_rule.gni
+++ b/tools/grit/grit_rule.gni
@@ -94,7 +94,7 @@
 import("//build/toolchain/gcc_toolchain.gni")
 import("//tools/grit/grit_args.gni")
 _strip_resource_files = is_android && is_official_build
-_js_minifier = "//tools/grit/minify_with_uglify.py"
+_js_minifier = "//tools/grit/minify_js.py"
 _css_minifier = "//tools/grit/minimize_css.py"
 
 grit_resource_id_target = "//tools/gritsettings:default_resource_ids"
diff --git a/tools/grit/minify_with_uglify.py b/tools/grit/minify_js.py
similarity index 93%
rename from tools/grit/minify_with_uglify.py
rename to tools/grit/minify_js.py
index 69d4e0f..cbf2fbac 100755
--- a/tools/grit/minify_with_uglify.py
+++ b/tools/grit/minify_js.py
@@ -3,7 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-
 import os
 import sys
 import tempfile
@@ -15,8 +14,9 @@
 import node
 import node_modules
 
+
 def Minify(source):
-  # Open two temporary files, so that uglify can read the input from one and
+  # Open two temporary files, so that terser can read the input from one and
   # write its output to the other.
   with tempfile.NamedTemporaryFile(mode="w+", suffix='.js') as infile, \
        tempfile.NamedTemporaryFile(mode="r+", suffix='.js') as outfile:
diff --git a/tools/grit/minify_with_uglify_unittest.py b/tools/grit/minify_js_unittest.py
similarity index 75%
rename from tools/grit/minify_with_uglify_unittest.py
rename to tools/grit/minify_js_unittest.py
index 8bbf65f..4a34e0b 100755
--- a/tools/grit/minify_with_uglify_unittest.py
+++ b/tools/grit/minify_js_unittest.py
@@ -5,7 +5,7 @@
 
 import unittest
 
-import minify_with_uglify
+import minify_js
 
 
 class MinifyWithUglifyTest(unittest.TestCase):
@@ -13,7 +13,7 @@
     source = """
             var foo = 0;
         """
-    minimized = minify_with_uglify.Minify(source)
+    minimized = minify_js.Minify(source)
     self.assertEqual(minimized, "var foo=0;")
 
   def test_complex(self):
@@ -25,6 +25,6 @@
             };
             var qux = foo.bar + foo.baz;
         """
-    minimized = minify_with_uglify.Minify(source)
+    minimized = minify_js.Minify(source)
     self.assertEqual(minimized,
-                      "var foo={bar:0,baz:5};var qux=foo.bar+foo.baz;")
+                     "var foo={bar:0,baz:5};var qux=foo.bar+foo.baz;")
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 9b7d421..7e50c2b7 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -162,7 +162,7 @@
   "chrome/browser/resources/chromeos/app_icon/app_icon_resources.grd": {
     "structures": [1395],
   },
-  "chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd": {
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/login/oobe_conditional_resources.grd": {
     "META": {"sizes": {"includes": [150], "structures": [300]}},
     "includes": [1400],
     "structures": [1420],
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index e36403c..88ead4bf 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -453,7 +453,7 @@
       'mac-upload-perfetto': 'release_bot_perfetto_zlib_reclient',
       'mac10.15-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
       'mac11-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
-      'mac12-arm64-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
+      'mac12-arm64-wpt-content-shell-fyi-rel': 'mac_arm64_release_bot_reclient',
       'mac12-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient',
       'win-annotator-rel': 'release_bot_reclient',
       'win-backuprefptr-x64-fyi-rel': 'release_trybot_backuprefptr_x64_reclient',
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 18b2c3b..903e32b 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -1068,10 +1068,10 @@
   },
   "mac12-arm64-wpt-content-shell-fyi-rel": {
     "gn_args": {
-      "dcheck_always_on": true,
+      "dcheck_always_on": false,
       "is_component_build": false,
       "is_debug": false,
-      "symbol_level": 1,
+      "target_cpu": "arm64",
       "use_remoteexec": true
     }
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 7b42d05..ae2bead 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -25493,7 +25493,7 @@
 </action>
 
 <action name="Overscroll_Cancelled.Reload">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <description>
     When vertical overscroll corresponding to the RELOAD navigation is cancelled
     - either because the user performed an interfering action such as pressing a
@@ -25517,7 +25517,7 @@
 </action>
 
 <action name="Overscroll_Navigated.Reload">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <description>
     When vertical overscroll initiates a RELOAD navigation in the browser.
   </description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 4ddc1f7..304e323 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9249,12 +9249,12 @@
   <int value="14" label="Omnibox icon shown, but not bubble (max strikes)"/>
 </enum>
 
-<enum name="AutofillSaveCreditCardPromptOfferEnum">
+<enum name="AutofillSavePaymentMethodPromptOfferEnum">
   <int value="0" label="Shown"/>
   <int value="1" label="Not shown, max strikes reached"/>
 </enum>
 
-<enum name="AutofillSaveCreditCardPromptResultEnum">
+<enum name="AutofillSavePaymentMethodPromptResultEnum">
   <int value="0" label="Accepted"/>
   <int value="1" label="Cancelled"/>
   <int value="2" label="Closed"/>
@@ -57977,6 +57977,7 @@
   <int value="-2007377632" label="DiscoverFeedMultiColumn:enabled"/>
   <int value="-2006505465"
       label="AutofillRemoveCardExpirationAndTypeTitles:disabled"/>
+  <int value="-2005716090" label="ShareSheetMigrationAndroid:disabled"/>
   <int value="-2005089558" label="BackgroundVideoTrackOptimization:disabled"/>
   <int value="-2004882388" label="AutofillPruneSuggestions:enabled"/>
   <int value="-2004862295" label="FedCmUserInfo:disabled"/>
@@ -60480,6 +60481,7 @@
   <int value="-617452890" label="media-router"/>
   <int value="-616818899" label="SameSiteByDefaultCookies:enabled"/>
   <int value="-616508634" label="DisableCryptAuthV1DeviceSync:enabled"/>
+  <int value="-616414905" label="ThumbnailCacheRefactor:disabled"/>
   <int value="-615974325" label="ArcMouseWheelSmoothScroll:disabled"/>
   <int value="-615254902" label="SystemJapanesePhysicalTyping:enabled"/>
   <int value="-614223913"
@@ -63652,6 +63654,7 @@
   <int value="1220274247" label="AllowReaderForAccessibility:disabled"/>
   <int value="1220464509" label="enable-first-run-ui-transitions"/>
   <int value="1220655015" label="kScrollableTabStripOverflow:enabled"/>
+  <int value="1221104166" label="ThumbnailCacheRefactor:enabled"/>
   <int value="1221394044" label="SharingUseDeviceInfo:enabled"/>
   <int value="1221559505" label="enable-spelling-feedback-field-trial"/>
   <int value="1222017136" label="WebRtcUseEchoCanceller3:disabled"/>
@@ -63734,6 +63737,7 @@
   <int value="1266525177"
       label="AutofillUpstreamUseGooglePayOnAndroidBranding:disabled"/>
   <int value="1266886673" label="delay-reload-stop-button-change"/>
+  <int value="1267585140" label="ShareSheetMigrationAndroid:enabled"/>
   <int value="1268470658" label="disable-android-password-link"/>
   <int value="1268678442" label="KerberosSettingsSection:disabled"/>
   <int value="1269216922" label="MediaAppPhotosIntegrationVideo:enabled"/>
diff --git a/tools/metrics/histograms/extract_histograms.py b/tools/metrics/histograms/extract_histograms.py
index ca8797e4..c3f3e48 100644
--- a/tools/metrics/histograms/extract_histograms.py
+++ b/tools/metrics/histograms/extract_histograms.py
@@ -69,6 +69,8 @@
 import re
 import xml.dom.minidom
 
+import histogram_configuration_model
+
 BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$'
 
 OWNER_PLACEHOLDER = (
@@ -375,6 +377,39 @@
   return owners, has_owner
 
 
+def _ExtractImprovementDirection(histogram_node):
+  """Extracts improvement direction from the given histogram element, if any.
+
+  Args:
+    histogram_node: A DOM Element corresponding to a histogram.
+
+  Returns:
+    A tuple, where the first element is the improvement direction, if any;
+    the second element is an error message if the given direction is invalid.
+  """
+  direction = None
+  error = None
+  improvement_nodes = histogram_node.getElementsByTagName('improvement')
+  if not improvement_nodes:
+    return None, None
+  if len(improvement_nodes) > 1:
+    histogram_name = histogram_node.getAttribute('name')
+    error = f'Histogram "{histogram_name}" has multiple <improvement> tags.'
+    return None, error
+
+  improvement_node = improvement_nodes[0]
+  direction = improvement_node.getAttribute('direction')
+  if (direction not in
+      histogram_configuration_model.IMPROVEMENT_DIRECTION_VALID_VALUES):
+    histogram_name = histogram_node.getAttribute('name')
+    error = (
+        f'Histogram "{histogram_name}" has an invalid direction "{direction}" '
+        f'in its <improvement> tag.')
+    return None, error
+
+  return direction, None
+
+
 def _ExtractComponents(histogram):
   """Extracts component information from the given histogram element.
 
@@ -583,6 +618,15 @@
     if owners:
       histogram_entry['owners'] = owners
 
+    # Find the <improvement> tag, if any.
+    improvement_direction, improvement_error = _ExtractImprovementDirection(
+        histogram)
+    if improvement_direction:
+      histogram_entry['improvement'] = improvement_direction
+    if improvement_error:
+      logging.error(improvement_error)
+      have_errors = True
+
     # Find <component> tag.
     components = _ExtractComponents(histogram)
     if components:
diff --git a/tools/metrics/histograms/extract_histograms_test.py b/tools/metrics/histograms/extract_histograms_test.py
index d6be485..d3474a7 100644
--- a/tools/metrics/histograms/extract_histograms_test.py
+++ b/tools/metrics/histograms/extract_histograms_test.py
@@ -8,6 +8,7 @@
 import xml.dom.minidom
 
 import extract_histograms
+import histogram_configuration_model
 
 TEST_SUFFIX_OBSOLETION_XML_CONTENT = """
 <histogram-configuration>
@@ -938,6 +939,46 @@
     self.assertIn('Test.First.Found', histograms_dict)
     self.assertIn('Test.Last.Found', histograms_dict)
 
+  def testExtractImprovementDirection(self):
+    histogram_name = 'Histogram.With.InterpretationTag'
+    config = """
+<histogram-configuration>
+
+<histograms>
+
+<histogram name="{histogram_name}" expires_after="M100" units="units">
+  <owner>owner@chromium.org</owner>
+  {improvement_tag}
+  <summary>The improvement tag says a higher value is good!</summary>
+</histogram>
+
+</histograms>
+
+</histogram-configuration>"""
+
+    improvement_tag_good = '<improvement direction="HIGHER_IS_BETTER"/>'
+    improvement_tag_bad = '<improvement>HIGHER_IS_BETTER</improvement>'
+
+    config_good = config.format(histogram_name=histogram_name,
+                                improvement_tag=improvement_tag_good)
+    config_bad = config.format(histogram_name=histogram_name,
+                               improvement_tag=improvement_tag_bad)
+
+    histograms_dict, had_errors = extract_histograms.ExtractHistogramsFromDom(
+        xml.dom.minidom.parseString(config_good))
+    self.assertFalse(had_errors)
+    self.assertIn(histogram_name, histograms_dict)
+    self.assertIn('improvement', histograms_dict[histogram_name])
+    self.assertEqual(
+        histogram_configuration_model.IMPROVEMENT_DIRECTION_HIGHER_IS_BETTER,
+        histograms_dict[histogram_name]['improvement'])
+
+    histograms_dict, had_errors = extract_histograms.ExtractHistogramsFromDom(
+        xml.dom.minidom.parseString(config_bad))
+    self.assertTrue(had_errors)
+    self.assertNotIn('improvement', histograms_dict[histogram_name])
+
+
 if __name__ == "__main__":
   logging.basicConfig(level=logging.ERROR + 1)
   unittest.main()
diff --git a/tools/metrics/histograms/histogram_configuration_model.py b/tools/metrics/histograms/histogram_configuration_model.py
index b88c176..278f51b 100644
--- a/tools/metrics/histograms/histogram_configuration_model.py
+++ b/tools/metrics/histograms/histogram_configuration_model.py
@@ -81,6 +81,26 @@
     ])
 
 # The following types are used for histograms.xml.
+IMPROVEMENT_DIRECTION_VALID_VALUES = (
+    IMPROVEMENT_DIRECTION_HIGHER_IS_BETTER := 'HIGHER_IS_BETTER',
+    IMPROVEMENT_DIRECTION_LOWER_IS_BETTER := 'LOWER_IS_BETTER',
+    IMPROVEMENT_DIRECTION_NEITHER_IS_BETTER := 'NEITHER_IS_BETTER',
+)
+
+_IMPROVEMENT_TYPE = models.ObjectNodeType(
+    'improvement',
+    attributes=[
+        (
+            'direction',
+            str,
+            r'^(' + '|'.join(IMPROVEMENT_DIRECTION_VALID_VALUES) + ')$',
+        ),
+    ],
+    required_attributes=['direction'],
+    text_attribute=False,
+    single_line=True,
+)
+
 _VARIANT_TYPE = models.ObjectNodeType(
     'variant',
     attributes=[
@@ -145,6 +165,7 @@
         (_OBSOLETE_TYPE.tag, _KEEP_ORDER),
         (_OWNER_TYPE.tag, _KEEP_ORDER),
         (_COMPONENT_TYPE.tag, _KEEP_ORDER),
+        (_IMPROVEMENT_TYPE.tag, _KEEP_ORDER),
         (_SUMMARY_TYPE.tag, _KEEP_ORDER),
         (_TOKEN_TYPE.tag, _KEEP_ORDER),
     ],
@@ -158,6 +179,9 @@
         models.ChildType(_COMPONENT_TYPE.tag, _COMPONENT_TYPE, multiple=True),
         models.ChildType(_SUMMARY_TYPE.tag, _SUMMARY_TYPE, multiple=False),
         models.ChildType(_TOKEN_TYPE.tag, _TOKEN_TYPE, multiple=True),
+        models.ChildType(_IMPROVEMENT_TYPE.tag,
+                         _IMPROVEMENT_TYPE,
+                         multiple=False),
     ])
 
 _HISTOGRAMS_TYPE = models.ObjectNodeType(
diff --git a/tools/metrics/histograms/histogram_configuration_model_test_histograms.py b/tools/metrics/histograms/histogram_configuration_model_test_histograms.py
index 9f119172..43d7961 100644
--- a/tools/metrics/histograms/histogram_configuration_model_test_histograms.py
+++ b/tools/metrics/histograms/histogram_configuration_model_test_histograms.py
@@ -636,6 +636,38 @@
         etree_util.ParseXMLString(input_xml))
     self.assertMultiLineEqual(result.strip(), expected_xml)
 
+  def testIndividualTagParsing_improvement(self):
+    """Tests that <improvement> has the right format and can be parsed."""
+
+    improvement_tag_good = '<improvement direction="HIGHER_IS_BETTER"/>'
+    improvement_tag_bad = ' <improvement>HIGHER_IS_BETTER</improvement>'
+    config = """
+<histogram-configuration>
+
+<histograms>
+
+<histogram name="Histogram.With.ImprovementTag" expires_after="M100">
+  <owner>owner1@chromium.org</owner>
+  {improvement_tag}
+  <summary>The improvement tag says higher value is good!</summary>
+</histogram>
+
+</histograms>
+
+</histogram-configuration>"""
+
+    config_good = config.format(improvement_tag=improvement_tag_good)
+    config_bad = config.format(improvement_tag=improvement_tag_bad)
+
+    result = histogram_configuration_model.PrettifyTree(
+        etree_util.ParseXMLString(config_good))
+    self.assertMultiLineEqual(result.strip(), config_good.strip())
+
+    with self.assertRaisesRegex(ValueError,
+                                'direction "" does not match regex'):
+      histogram_configuration_model.PrettifyTree(
+          etree_util.ParseXMLString(config_bad))
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/metrics/histograms/metadata/apps/OWNERS b/tools/metrics/histograms/metadata/apps/OWNERS
index b6b66f2..03bcea3f 100644
--- a/tools/metrics/histograms/metadata/apps/OWNERS
+++ b/tools/metrics/histograms/metadata/apps/OWNERS
@@ -4,4 +4,5 @@
 # Use chromium-metrics-reviews@google.com as a backup.
 nancylingwang@chromium.org
 tby@chromium.org
+tsergeant@chromium.org
 yulunwu@chromium.org
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 62a36c9..a4a3976b 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -187,6 +187,23 @@
   <summary>The ways the user opens up the App Management interface.</summary>
 </histogram>
 
+<histogram name="AppPreloadService.FirstLoginFlowTime.{Status}" units="ms"
+    expires_after="2023-08-01">
+  <owner>jshikaram@chromium.org</owner>
+  <owner>chromeos-apps-foundation-team@google.com</owner>
+  <summary>
+    The time it takes for the first login flow of the App Preload service to
+    complete with the final status of {Status}.
+
+    This metric is recorded when the user logs in for the first time on a device
+    and the App Preload service kicks off the first login flow.
+  </summary>
+  <token key="Status">
+    <variant name="Failure" summary="First login flow completed in failure"/>
+    <variant name="Success" summary="First login flow completed successfully"/>
+  </token>
+</histogram>
+
 <histogram name="AppPreloadService.ServerResponseCodes"
     enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-08-01">
   <owner>jshikaram@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index e3cc180..4e15dcf 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -143,8 +143,8 @@
 
 <histogram name="Ash.Accelerators.WindowSnap"
     enum="WindowSnapAcceleratorAction" expires_after="2023-11-20">
-  <owner>amusbach@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wmp@google.com</owner>
   <summary>Captures usage of Alt+[ and Alt+].</summary>
 </histogram>
 
@@ -1499,9 +1499,9 @@
 
 <histogram name="Ash.Desks.AnimationLatency.DeskActivation" units="ms"
     expires_after="2023-06-25">
-  <owner>amusbach@chromium.org</owner>
   <owner>afakhry@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Emitted when the virtual desks activation animation begins, to report the
     latency of starting this animation. In a continuous desk animation, this
@@ -1511,9 +1511,9 @@
 
 <histogram name="Ash.Desks.AnimationLatency.DeskRemoval" units="ms"
     expires_after="2023-06-25">
-  <owner>amusbach@chromium.org</owner>
   <owner>afakhry@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Emitted when the virtual desks removal animation begins, to report the
     latency of starting this animation. In a continuous desk animation, this
@@ -3734,9 +3734,10 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Enter{OverviewAnimationMode}"
-    units="%" expires_after="2022-10-15">
+    units="%" expires_after="2024-02-07">
   <owner>omrilio@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Relative smoothness of animations when entering overview mode, recorded when
     the animation completes. 100% represents ideally smooth 60 frames per
@@ -3746,9 +3747,10 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Exit{OverviewAnimationMode}"
-    units="%" expires_after="2022-10-15">
+    units="%" expires_after="2024-02-07">
   <owner>omrilio@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Relative smoothness of animations when exiting overview mode, recorded when
     the animation completes. 100% represents ideally smooth 60 frames per
@@ -3914,8 +3916,8 @@
 
 <histogram name="Ash.Overview.WindowDrag.Workflow" enum="OverviewDragAction"
     expires_after="2023-07-16">
-  <owner>amusbach@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wmp@google.com</owner>
   <summary>
     Recorded when a drag from overview (not from the top or shelf) is completed,
     and when an overview item is closed by vertically swiping or flinging (even
@@ -4504,7 +4506,7 @@
 </histogram>
 
 <histogram name="Ash.Shelf.Menu.SelectedMenuItemIndex" units="Index"
-    expires_after="2023-02-01">
+    expires_after="2024-02-08">
   <owner>anasalazar@chromium.org</owner>
   <owner>mmourgos@google.com</owner>
   <summary>
@@ -4876,8 +4878,38 @@
   </token>
 </histogram>
 
+<histogram name="Ash.Smoothness.PercentDroppedFrames_1sWindow2{Stage}"
+    units="%" expires_after="2024-01-29">
+  <owner>xiyuan@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
+  <summary>
+    Tracks the percent of dropped frames in a 1 second sliding window.
+
+    PercentDroppedFrames is measured by tracking the number of frames which were
+    not displayed on screen out of the total number of frames expected to be
+    produced and displayed. In other words, the lower this number is, the
+    smoother experience.
+
+    The &quot;.InSession&quot; covers the time of 1 minute beyond into user
+    sessions. The 1 minute timeline is picked based on
+    &quot;Ash.Login.TimeUntilGoodADF&quot; histogram, where about 93-94% user
+    sessions fall under the 1 minute bar.
+
+    The metric is reported {Stage}.
+  </summary>
+  <token key="Stage">
+    <variant name="" summary="on every frame"/>
+    <variant name=".InSession"
+        summary="on every frame after 1 min into session"/>
+  </token>
+</histogram>
+
 <histogram name="Ash.Smoothness.PercentDroppedFrames_1sWindow{Stage}" units="%"
     expires_after="2023-10-30">
+  <obsolete>
+    This metric is reported on every dropped frame instead of every frame. It is
+    deprecated in favor of Ash.Smoothness.PercentDroppedFrames_1sWindow2.
+  </obsolete>
   <owner>xiyuan@chromium.org</owner>
   <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
@@ -4987,8 +5019,8 @@
 
 <histogram name="Ash.SplitView.TimeInMultiDisplaySplitView" units="ms"
     expires_after="2023-07-02">
-  <owner>amusbach@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wmp@google.com</owner>
   <summary>
     The amount of time that the user spent in multi-display split view mode,
     meaning that split view is active on more than one display. The time is
@@ -5044,11 +5076,11 @@
 
 <histogram
     name="Ash.SplitViewResize.PresentationTime.MaxLatency{SplitViewResizeModes}"
-    units="ms" expires_after="2023-01-10">
-  <owner>amusbach@chromium.org</owner>
+    units="ms" expires_after="2024-02-07">
   <owner>xdai@chromium.org</owner>
   <owner>omrilio@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Maximum latency of the presentation time while resizing one or two split
     view windows. {SplitViewResizeModes}
@@ -5058,10 +5090,10 @@
 
 <histogram name="Ash.SplitViewResize.PresentationTime{SplitViewResizeModes}"
     units="ms" expires_after="2023-11-18">
-  <owner>amusbach@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <owner>omrilio@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Presentation time while resizing one or two split view windows.
     {SplitViewResizeModes}
@@ -5790,9 +5822,9 @@
 
 <histogram name="Ash.Window.AnimationSmoothness.Minimize" units="%"
     expires_after="2023-06-25">
-  <owner>amusbach@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <owner>sammiequon@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Relative smoothness of minimizing window animation. 100% represents ideally
     smooth 60 frames per second. 50% represents when only 30 frames per second
@@ -5818,9 +5850,9 @@
 
 <histogram name="Ash.Window.AnimationSmoothness.Unminimize" units="%"
     expires_after="2023-06-25">
-  <owner>amusbach@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <owner>sammiequon@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
     Relative smoothness of unminimizing window animation. 100% represents
     ideally smooth 60 frames per second. 50% represents when only 30 frames per
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 28b2b87d2..d3f096e 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -219,11 +219,6 @@
   <variant name=".Unknown" summary="Unknown form type"/>
 </variants>
 
-<variants name="AutofillLocalCardMigrationBubbleShow">
-  <variant name=".FirstShow" summary="First time bubble is shown"/>
-  <variant name=".Reshows" summary="Bubble was reopened after being closed"/>
-</variants>
-
 <variants name="AutofillProfileCategory">
   <variant name="AccountChrome"
       summary="kAccount profiles originating from Chrome"/>
@@ -2420,34 +2415,26 @@
   </summary>
 </histogram>
 
-<histogram
-    name="Autofill.LocalCardMigrationBubbleOffer{AutofillLocalCardMigrationBubbleShow}"
+<histogram name="Autofill.LocalCardMigrationBubbleOffer.{ShowType}"
     enum="AutofillLocalCardMigrationBubbleOffer" expires_after="2023-09-01">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <summary>
     Record events related to bubble showing. Logged when bubble is requested or
-    is actually shown to users. {AutofillLocalCardMigrationBubbleShow}
+    is actually shown to users.
   </summary>
-  <token key="AutofillLocalCardMigrationBubbleShow"
-      variants="AutofillLocalCardMigrationBubbleShow">
-    <variant name=""/>
-  </token>
+  <token key="ShowType" variants="Autofill.PaymentBubble.Show"/>
 </histogram>
 
-<histogram
-    name="Autofill.LocalCardMigrationBubbleResult{AutofillLocalCardMigrationBubbleShow}"
+<histogram name="Autofill.LocalCardMigrationBubbleResult.{ShowType}"
     enum="AutofillLocalCardMigrationBubbleResult" expires_after="2023-09-01">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <summary>
     Records whether and how the local card migration bubble was accepted or
-    closed. {AutofillLocalCardMigrationBubbleShow}
+    closed.
   </summary>
-  <token key="AutofillLocalCardMigrationBubbleShow"
-      variants="AutofillLocalCardMigrationBubbleShow">
-    <variant name=""/>
-  </token>
+  <token key="ShowType" variants="Autofill.PaymentBubble.Show"/>
 </histogram>
 
 <histogram name="Autofill.LocalCardMigrationBubbleUserInteraction"
@@ -3566,7 +3553,7 @@
 
 <histogram
     name="Autofill.SaveCreditCardPromptOffer{AutofillSaveCreditCardPromptDestination}"
-    enum="AutofillSaveCreditCardPromptOfferEnum" expires_after="2023-11-01">
+    enum="AutofillSavePaymentMethodPromptOfferEnum" expires_after="2023-11-01">
   <owner>jsaul@google.com</owner>
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3583,7 +3570,7 @@
 
 <histogram
     name="Autofill.SaveCreditCardPromptResult{AutofillSaveCreditCardPromptDestination}"
-    enum="AutofillSaveCreditCardPromptResultEnum" expires_after="2023-11-01">
+    enum="AutofillSavePaymentMethodPromptOfferEnum" expires_after="2023-11-01">
   <owner>jsaul@google.com</owner>
   <owner>siyua@chromium.org</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3598,6 +3585,44 @@
   </token>
 </histogram>
 
+<histogram name="Autofill.SaveIbanPromptOffer{IbanTypeToBeSaved}.{ShowType}"
+    enum="AutofillSavePaymentMethodPromptResultEnum" expires_after="2023-09-01">
+  <owner>qihuizhao@google.com</owner>
+  <owner>jsaul@google.com</owner>
+  <owner>payments-autofill-team@google.com</owner>
+  <summary>
+    Records every time the save IBAN bubble or omnibox icon (due to maxstrike
+    reached) is offered to the user, broken down by destination and show type.
+  </summary>
+  <token key="IbanTypeToBeSaved" variants="IbanTypeToBeSaved"/>
+  <token key="ShowType" variants="Autofill.PaymentBubble.Show"/>
+</histogram>
+
+<histogram
+    name="Autofill.SaveIbanPromptResult{IbanTypeToBeSaved}.SavedWithNickname"
+    enum="Boolean" expires_after="2023-09-01">
+  <owner>jsaul@google.com</owner>
+  <owner>payments-autofill-team@google.com</owner>
+  <summary>
+    Records when the user accepts the bubble to save an IBAN, with or without
+    nickname.
+  </summary>
+  <token key="IbanTypeToBeSaved" variants="IbanTypeToBeSaved"/>
+</histogram>
+
+<histogram name="Autofill.SaveIbanPromptResult{IbanTypeToBeSaved}.{ShowType}"
+    enum="AutofillSavePaymentMethodPromptOfferEnum" expires_after="2023-09-01">
+  <owner>qihuizhao@google.com</owner>
+  <owner>jsaul@google.com</owner>
+  <owner>payments-autofill-team@google.com</owner>
+  <summary>
+    Records when the user makes a decision on the save IBAN bubble, broken down
+    by destinations.
+  </summary>
+  <token key="IbanTypeToBeSaved" variants="IbanTypeToBeSaved"/>
+  <token key="ShowType" variants="Autofill.PaymentBubble.Show"/>
+</histogram>
+
 <histogram name="Autofill.ScanCreditCard.Completed" enum="BooleanCompleted"
     expires_after="2023-06-18">
   <owner>battre@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml
index 114e205..9d41db5 100644
--- a/tools/metrics/histograms/metadata/chrome/histograms.xml
+++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -106,6 +106,11 @@
 
 <histogram name="Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow"
     units="%" expires_after="2023-07-25">
+  <obsolete>
+    This metric is reported on every dropped frame instead of every frame. It is
+    deprecated in favor of
+    Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow2
+  </obsolete>
   <owner>xiyuan@chromium.org</owner>
   <owner>chromeos-perfmetrics-eng@google.com</owner>
   <summary>
@@ -114,6 +119,16 @@
   </summary>
 </histogram>
 
+<histogram name="Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow2"
+    units="%" expires_after="2024-01-29">
+  <owner>xiyuan@chromium.org</owner>
+  <owner>chromeos-perfmetrics-eng@google.com</owner>
+  <summary>
+    Similar to Ash.Smoothness.PercentDroppedFrames_1sWindow2 but emitted for the
+    browser UI of lacros-chrome.
+  </summary>
+</histogram>
+
 <histogram name="Chrome.ProcessSingleton.NotifyResult" enum="NotifyResult"
     expires_after="2023-07-30">
   <owner>gab@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 1a1a891c..fd2f85e 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -1246,6 +1246,7 @@
     <variant name="SETMainThreadAnimation"
         summary="main thread animations during a view transition"/>
     <variant name="TouchScroll" summary="touch scrolling"/>
+    <variant name="Video" summary="video playback"/>
     <variant name="WheelScroll" summary="wheel scrolling"/>
   </token>
 </histogram>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index 5192cb3..2430a5db 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -1887,7 +1887,7 @@
     units="microseconds" expires_after="never">
 <!-- expires-never: guiding metric (internal: go/chrome-browser-guiding-metrics) -->
 
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <owner>chrome-analysis-team@google.com</owner>
   <summary>
@@ -1908,7 +1908,7 @@
 
 <histogram name="EventLatency.GestureScrollUpdate.Touchscreen.TotalLatency2"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     When a user performs a scroll using touchscreen, a sequence of touch-move
@@ -1930,7 +1930,7 @@
 <histogram
     name="EventLatency.GestureScrollUpdate.{NonTouchscreenScrollInputType}.TotalLatency{Version}"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of {NonTouchscreenScrollInputType}
@@ -1954,7 +1954,7 @@
 
 <histogram name="EventLatency.TotalLatency" units="microseconds"
     expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of all event types, from when the user input causing
@@ -1968,7 +1968,7 @@
 <histogram
     name="EventLatency.{NonGsuScrollEventType}.{ScrollInputType}.TotalLatency{Version}"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of {ScrollInputType} {NonGsuScrollEventType}, from when
@@ -2001,7 +2001,7 @@
 
 <histogram name="EventLatency.{NonScrollPinchEventType}.TotalLatency"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of {NonScrollPinchEventType}, from when the user input
@@ -2036,7 +2036,7 @@
 
 <histogram name="EventLatency.{PinchEventType}.{PinchInputType}.TotalLatency"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of {PinchInputType} {PinchEventType}, from when the
@@ -2060,7 +2060,7 @@
 
 <histogram name="EventLatency.{ScrollEventType}.TotalLatency{Version}"
     units="microseconds" expires_after="2024-01-16">
-  <owner>mohsen@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
     Tracks total latency of {ScrollEventType}, from when the user input causing
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index a64df8fd..2e77bdc 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1233,6 +1233,21 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.NavigationStateNotFinishedInLoadCancelled" enum="Boolean"
+    expires_after="2023-09-24">
+  <owner>ajuma@chromium.org</owner>
+  <owner>michaeldo@chromium.org</owner>
+  <summary>
+    The method -[CRWWKNavigationHandler loadCancelled] updates the navigation
+    state to finished if it is any other state. Additionally, if
+    `beingDestroyed` is false, the webstate's loading state is set to false.
+    There is a long standing TODO in this method with the comment: &quot;Check
+    if this function should be removed.&quot; This metric is logged when the
+    logic in this method is triggered. The results will be reviewed to see if
+    this logic is still ever called or if it can now be removed.
+  </summary>
+</histogram>
+
 <histogram name="IOS.NSString.stringByReplacingCharactersInRange.NilArgument"
     enum="Boolean" expires_after="2022-12-11">
   <owner>rohitrao@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index d0fe517..a3eb765 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -2224,7 +2224,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.ARVStatus" enum="GscArvStatus"
-    expires_after="2023-11-09">
+    expires_after="2024-02-05">
   <owner>vbendeb@chromium.org</owner>
   <owner>ti50-core+uma@chromium.org</owner>
   <summary>
@@ -2243,7 +2243,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.BoardIdFlags" enum="Cr50BoardIdFlags"
-    expires_after="2023-02-10">
+    expires_after="2024-02-05">
   <owner>apronin@chromium.org</owner>
   <owner>vbendeb@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
@@ -2259,7 +2259,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.BoardIdOfRlzMismatch" enum="Cr50CrosRlzCodes"
-    expires_after="2023-02-10">
+    expires_after="2024-02-05">
   <owner>vbendeb@chromium.org</owner>
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
@@ -2275,7 +2275,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.FlashLog" enum="Cr50FlashLogs"
-    expires_after="2023-02-10">
+    expires_after="2024-02-05">
   <owner>apronin@chromium.org</owner>
   <owner>vbendeb@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
@@ -2293,7 +2293,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.MatchingBoardId" enum="Cr50CrosRlzCodes"
-    expires_after="2023-02-10">
+    expires_after="2024-02-05">
   <owner>vbendeb@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
@@ -2308,7 +2308,7 @@
 </histogram>
 
 <histogram name="Platform.{GSC}.RlzOfBoardIdMismatch" enum="Cr50CrosRlzCodes"
-    expires_after="2023-02-10">
+    expires_after="2024-02-05">
   <owner>vbendeb@chromium.org</owner>
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 6852af3..09988fa 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -385,7 +385,7 @@
 </histogram>
 
 <histogram name="Signin.Enterprise.WorkProfile.ProfileCreatedWithPolicySet"
-    enum="BooleanCreated" expires_after="2023-03-15">
+    enum="BooleanCreated" expires_after="2023-09-15">
   <owner>pastarmovj@chromium.org</owner>
   <owner>ydago@chromium.org</owner>
   <summary>
@@ -397,7 +397,7 @@
 </histogram>
 
 <histogram name="Signin.Enterprise.WorkProfile.ProfileCreatedwithPolicyUnset"
-    enum="BooleanCreated" expires_after="2023-03-15">
+    enum="BooleanCreated" expires_after="2023-09-15">
   <owner>pastarmovj@chromium.org</owner>
   <owner>ydago@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index afbc6614..eca5860 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -7519,8 +7519,7 @@
 </event>
 
 <event name="Graphics.Smoothness.EventLatency">
-  <owner>mohsen@chromium.org</owner>
-  <owner>sadrul@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <summary>
     Tracks the duration of stages in the rendering pipeline when processing a
     single frame in response to an input event. To meet UKM goals for data
@@ -8347,7 +8346,7 @@
 
 <event name="Graphics.Smoothness.Latency">
   <owner>animations-dev@chromium.org</owner>
-  <owner>sadrul@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <owner>schenney@chromium.org</owner>
   <summary>
     Tracks the duration of stages in the rendering pipeline while processing a
@@ -8871,7 +8870,7 @@
 <event name="Graphics.Smoothness.NormalizedPercentDroppedFrames"
     singular="True">
   <owner>animations-dev@chromium.org</owner>
-  <owner>sadrul@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <summary>
     Measures various normalizations for the smoothness metric. The metric is
     measured by counting dropped frames, and various normalization strategies
@@ -9327,7 +9326,7 @@
 
 <event name="Graphics.Smoothness.PercentDroppedFrames">
   <owner>animations-dev@chromium.org</owner>
-  <owner>sadrul@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <summary>
     Tracks the percent of dropped frames for a particular sequence of frames
     such as during scroll or animation. PercentDroppedFrames is measured by
@@ -9656,7 +9655,7 @@
     Deprecated 02/2020.
   </obsolete>
   <owner>animations-dev@chromium.org</owner>
-  <owner>sadrul@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
   <summary>
     As of 2020-02-12, this is deprecated in favor of
     Graphics.Smoothness.PercentDroppedFrames.
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index dffbf79..1e19649 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -6,6 +6,7 @@
 UNSCHEDULED_blink_perf.base64,csharrison@chromium.org,Blink>Internals>WTF,https://bit.ly/blink-perf-benchmarks,all
 UNSCHEDULED_blink_perf.performance_apis,yoavweiss@chromium.org,Blink>PerformanceAPIs,https://bit.ly/blink-perf-benchmarks,all
 UNSCHEDULED_blink_perf.service_worker,"shimazu@chromium.org, falken@chromium.org, ting.shao@intel.com",Blink>ServiceWorker,https://bit.ly/blink-perf-benchmarks,
+UNSCHEDULED_blink_perf.view_transitions,"bokan@chromium.org, khushalsagar@chromium.org, vmpstr@chromium.org",Blink>ViewTransitions,https://bit.ly/blink-perf-benchmarks,all
 UNSCHEDULED_loading.mbi,blink-isolation-dev@chromium.org,Blink>Internals>Modularization,https://bit.ly/loading-benchmarks,many_agents
 UNSCHEDULED_v8.loading_desktop,"cbruni@chromium.org, tmrts@chromium.org, almuthanna@chromium.org",Blink>JavaScript,https://bit.ly/system-health-v8-benchmarks,"2016,2018,2019,2020,emerging_market,health_check,international,javascript_heavy"
 UNSCHEDULED_v8.loading_mobile,"cbruni@chromium.org, leszeks@chromium.org, tmrts@chromium.org",Blink>JavaScript,https://bit.ly/system-health-v8-benchmarks,"2016,2018,2019,2020,emerging_market,health_check,international,javascript_heavy"
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 81d50d5..7a55c96d 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -794,3 +794,17 @@
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs(
         ['--enable-unsafe-webgpu', '--enable-features=V8TurboFastApiCalls'])
+
+
+@benchmark.Info(emails=[
+    'bokan@chromium.org', 'khushalsagar@chromium.org', 'vmpstr@chromium.org'
+],
+                component='Blink>ViewTransitions',
+                documentation_url='https://bit.ly/blink-perf-benchmarks')
+class BlinkPerfViewTransitions(_BlinkPerfBenchmark):
+  SUBDIR = 'view_transitions'
+  TAGS = _BlinkPerfBenchmark.TAGS + ['all']
+
+  @classmethod
+  def Name(cls):
+    return 'UNSCHEDULED_blink_perf.view_transitions'
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 4e4aeb7..868db5b 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,15 +6,15 @@
         },
         "win": {
             "hash": "3bc30c6747aa0fefd2dad9c006415bbc322e7065",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/656582b37c3b7214e3b20aba8fd74d41b35a7160/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/0374f0872ca2a125943edd23e8d27bb606fe47de/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "e945a99da7a66211f847b8049627bbec846d2d1d",
             "full_remote_path": "perfetto-luci-artifacts/3b59f000c939bfe4d05267fd68d282ef0b541334/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "db9551018053d43c61c96765708a25ca01e0bb19",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/656582b37c3b7214e3b20aba8fd74d41b35a7160/trace_processor_shell"
+            "hash": "8a1fc8c9e19df500c3bc81df066a3e9467ed925d",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/0374f0872ca2a125943edd23e8d27bb606fe47de/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "f9caa6dfbdc44573d32a21a9aeeed2058ffc3d68",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "4a5fe0dbde2818c8752df7a36cd8f60c052e8f56",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/a352070f45024ce07dfec791a89ed2af785ce46c/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/0374f0872ca2a125943edd23e8d27bb606fe47de/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index d4ed7d34..f348f7a 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -303,7 +303,6 @@
 crbug.com/1269978 [ fuchsia ] rendering.mobile/svg_icon_raster [ Skip ]
 crbug.com/1271258 [ fuchsia ] rendering.mobile/motionmark* [ Skip ]
 crbug.com/1316726 [ fuchsia ] rendering.mobile/microgame_fps [ Skip ]
-crbug.com/1316721 [ fuchsia ] rendering.mobile/reddit_mobile_2018 [ Skip ]
 crbug.com/1316725 [ fuchsia ] rendering.mobile/mix_10k [ Skip ]
 # Fuchsia does not support the pinch tests.
 crbug.com/1316732 [ fuchsia ] rendering.mobile/accu_weather_mobile_pinch_2018 [ Skip ]
@@ -469,7 +468,6 @@
 crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:media:youtubetv_watch:2020 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:media:youtubetv:2019 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:news:cnn:2021 [ Skip ]
-crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:news:reddit:2020 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse_accessibility:tech:codesearch:2018 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:media:googleplaystore:2021 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:media:imgur [ Skip ]
@@ -477,7 +475,6 @@
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:media:youtubetv_watch:2020 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:media:youtubetv:2019 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:news:cnn:2021 [ Skip ]
-crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:news:reddit:2020 [ Skip ]
 crbug.com/1147969 [ linux ] system_health.memory_desktop/browse:news:reddit:2020 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:search:google_india:2021 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-astro ] system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018 [ Skip ]
@@ -502,7 +499,6 @@
 crbug.com/1192170 [ fuchsia-board-astro ] system_health.memory_desktop/browse:news:nytimes:2020 [ Skip ]
 crbug.com/1192176 [ fuchsia-board-astro ] system_health.memory_desktop/browse:media:tumblr:2018 [ Skip ]
 crbug.com/1232202 [ fuchsia-board-astro ] system_health.memory_desktop/browse:search:google:2020 [ Skip ]
-crbug.com/1316721 [ fuchsia-board-astro ] system_health.memory_desktop/load:news:reddit:2018 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:search:google_india:2021 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018 [ Skip ]
 crbug.com/1147969 [ fuchsia-board-sherlock ] system_health.memory_desktop/browse:social:twitter:2018 [ Skip ]
diff --git a/tools/visual_debugger/filter-ui.js b/tools/visual_debugger/filter-ui.js
index ea4347c..5542d336 100644
--- a/tools/visual_debugger/filter-ui.js
+++ b/tools/visual_debugger/filter-ui.js
@@ -42,7 +42,8 @@
       <div class='label' title='Filter annotation to match.
       For example frame.root.damage' >Annotation </div>
       <div class='input'>
-        <input placeholder='Substring to match' id='annotation' size=40>
+        <input list="knownAnnotations" placeholder='Substring to match'
+         id='annotation' size=40>
         <!-- TODO: A fancy drop-down here would be nice. -->
       </div>
     </div>
@@ -133,6 +134,26 @@
 
 window.customElements.define('filter-ui', FilterUI);
 
+// A <datalist> element containing values of previously seen filter annotations.
+let dataListElement = undefined;
+let knownAnnotations = new Set();
+// Called when processing new sources from a frame.
+function notifyUiOfNewSource(source) {
+  if (dataListElement === undefined) {
+    dataListElement = document.createElement("datalist");
+    dataListElement.id = "knownAnnotations";
+    document.body.appendChild(dataListElement);
+  }
+
+  if (!knownAnnotations.has(source.anno)) {
+    let option = document.createElement("option");
+    option.value = source.anno;
+    dataListElement.appendChild(option);
+
+    knownAnnotations.add(source.anno);
+  }
+}
+
 function createFilterChip(filter) {
   const chip = document.createElement('div');
   chip.className = "mdc-chip";
diff --git a/tools/visual_debugger/frame.js b/tools/visual_debugger/frame.js
index d9de672..b2d3d92 100644
--- a/tools/visual_debugger/frame.js
+++ b/tools/visual_debugger/frame.js
@@ -80,6 +80,7 @@
     if (json.new_sources) {
       for (const s of json.new_sources) {
         new Source(s);
+        notifyUiOfNewSource(s);
       }
     }
 
@@ -217,16 +218,16 @@
     const transformMatrix = context.getTransform();
     context.resetTransform();
 
-    context.fillStyle = 'black';
-    context.font = "16px Courier bold";
+    context.font = "16px 'Courier bold', monospace";
 
-    const frameNumberPosX = 3;
-    const frameNumberPosY = 15;
-    this.drawText(context,
-                  this.num_,
-                  frameNumberPosX,
-                  frameNumberPosY,
-                  transformMatrix);
+    // Draw the frame number
+    {
+      context.textBaseline = "bottom";
+      context.fillStyle = "black";
+      var newTextPos = transformMatrix.transformPoint(new DOMPoint(0, 0));
+      context.fillText(this.num_, newTextPos.x, newTextPos.y);
+    }
+
 
     for (const text of this.drawTexts_) {
       // If thread not enabled, then skip text calls from this thread.
@@ -263,6 +264,35 @@
   drawText(context, text, posX, posY, transformMatrix) {
     // TODO: Set the text alignment based on the transform.
     var newTextPos = transformMatrix.transformPoint(new DOMPoint(posX, posY));
+
+    // Make the origin of text the top-left, similar to rectangles.
+    context.textBaseline = "top";
+
+    // Fill a background rectangle behind the text with the current fill color.
+    const measure = context.measureText(text);
+    context.fillRect(
+      newTextPos.x,
+      newTextPos.y,
+      measure.width,
+      measure.actualBoundingBoxDescent - measure.actualBoundingBoxAscent
+    );
+
+    function perceptualBrightness(hexColor) {
+      const r = parseInt(hexColor.substr(1, 2), 16) / 255;
+      const g = parseInt(hexColor.substr(3, 2), 16) / 255;
+      const b = parseInt(hexColor.substr(5, 2), 16) / 255;
+      return Math.sqrt(
+        0.299 * Math.pow(r, 2) + 0.587 * Math.pow(g, 2) + 0.114 * Math.pow(b, 2)
+      );
+    }
+
+    // Attempt to make the text contrast better against the background.
+    if (perceptualBrightness(context.fillStyle) > 0.65) {
+      context.fillStyle = "black";
+    } else {
+      context.fillStyle = "white";
+    }
+
     context.fillText(text, newTextPos.x, newTextPos.y);
   }
 
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index 1f0bd1e7..fecee724 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -2725,7 +2725,10 @@
   return has_pagination_support_;
 }
 
-void AXTree::NotifyTreeManagerWillBeRemoved() {
+void AXTree::NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id) {
+  if (previous_tree_id == AXTreeIDUnknown())
+    return;
+
   for (AXTreeObserver& observer : observers_)
     observer.OnTreeManagerWillBeRemoved(this);
 }
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
index 9023da5..085bf7e1 100644
--- a/ui/accessibility/ax_tree.h
+++ b/ui/accessibility/ax_tree.h
@@ -250,9 +250,12 @@
   // Event metadata while applying a tree update during unserialization.
   AXEvent* event_data() const { return event_data_.get(); }
 
-  // Notify the delegate that the tree manager for this AXTree will be removed
-  // from the AXTreeManagerMap.
-  void NotifyTreeManagerWillBeRemoved();
+  // Notify the delegate that the tree manager for |previous_tree_id| will be
+  // removed from the AXTreeManagerMap. Because we sometimes remove the tree
+  // manager after the tree's id has been modified, we need to pass the (old)
+  // tree id associated with the manager we are removing even though it is the
+  // same tree.
+  void NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id);
 
  private:
   friend class ScopedTreeUpdateInProgressStateSetter;
diff --git a/ui/accessibility/ax_tree_manager.cc b/ui/accessibility/ax_tree_manager.cc
index e66437b..1c5bb8df 100644
--- a/ui/accessibility/ax_tree_manager.cc
+++ b/ui/accessibility/ax_tree_manager.cc
@@ -149,7 +149,7 @@
 
 void AXTreeManager::WillBeRemovedFromMap() {
   if (HasValidTreeID()) {
-    ax_tree_->NotifyTreeManagerWillBeRemoved();
+    ax_tree_->NotifyTreeManagerWillBeRemoved(GetTreeID());
   }
 }
 
diff --git a/ui/accessibility/ax_tree_manager_base.cc b/ui/accessibility/ax_tree_manager_base.cc
index f0289f7..8b56fa2 100644
--- a/ui/accessibility/ax_tree_manager_base.cc
+++ b/ui/accessibility/ax_tree_manager_base.cc
@@ -57,7 +57,7 @@
     return;
 
   DCHECK_NE(GetTreeID().type(), ax::mojom::AXTreeIDType::kUnknown);
-  tree_->NotifyTreeManagerWillBeRemoved();
+  tree_->NotifyTreeManagerWillBeRemoved(GetTreeID());
   GetTreeManagerMapInstance().erase(GetTreeID());
 }
 
@@ -67,7 +67,7 @@
     return;
   }
 
-  manager.tree_->NotifyTreeManagerWillBeRemoved();
+  manager.tree_->NotifyTreeManagerWillBeRemoved(manager.GetTreeID());
   GetTreeManagerMapInstance().erase(manager.GetTreeID());
   SetTree(std::move(manager.tree_));
 }
@@ -77,7 +77,7 @@
     return *this;
 
   if (manager.tree_) {
-    manager.tree_->NotifyTreeManagerWillBeRemoved();
+    manager.tree_->NotifyTreeManagerWillBeRemoved(manager.GetTreeID());
     GetTreeManagerMapInstance().erase(manager.GetTreeID());
     SetTree(std::move(manager.tree_));
   } else {
@@ -105,7 +105,7 @@
   }
 
   if (tree_) {
-    tree_->NotifyTreeManagerWillBeRemoved();
+    tree_->NotifyTreeManagerWillBeRemoved(GetTreeID());
     GetTreeManagerMapInstance().erase(GetTreeID());
   }
 
@@ -123,7 +123,7 @@
   if (!tree_)
     return {};
 
-  tree_->NotifyTreeManagerWillBeRemoved();
+  tree_->NotifyTreeManagerWillBeRemoved(GetTreeID());
   GetTreeManagerMapInstance().erase(GetTreeID());
   return std::move(tree_);
 }
diff --git a/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java b/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
index 05b7ffa5..4a7143c 100644
--- a/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
+++ b/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -71,6 +72,7 @@
      */
     @Test
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1413839")
     public void internalClipboardInvalidation() throws TimeoutException {
         // Write to the clipboard in native and ensure that is propagated to the platform clipboard.
         final String originalText = "foo";
diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc
index 96f5280..c8f49bd 100644
--- a/ui/color/ui_color_mixer.cc
+++ b/ui/color/ui_color_mixer.cc
@@ -40,10 +40,7 @@
       kColorSubtleEmphasisBackground};
   mixer[kColorButtonBackgroundProminentFocused] = {
       kColorButtonBackgroundProminent};
-  // TODO(crbug.com/1406633): Finalize button colors.
-  mixer[kColorButtonBackgroundTonal] = {dark_mode
-                                            ? SkColorSetRGB(0x00, 0x4A, 0x77)
-                                            : SkColorSetRGB(0xC2, 0xE7, 0xFF)};
+  mixer[kColorButtonBackgroundTonal] = {kColorSysPrimaryContainer};
   mixer[kColorButtonBackgroundTonalDisabled] = {kColorSubtleEmphasisBackground};
   mixer[kColorButtonBackgroundTonalFocused] = {kColorButtonBackgroundTonal};
   mixer[kColorButtonBorder] = {kColorMidground};
@@ -55,10 +52,7 @@
   mixer[kColorButtonForegroundDisabled] = {kColorDisabledForeground};
   mixer[kColorButtonForegroundProminent] =
       GetColorWithMaxContrast(kColorButtonBackgroundProminent);
-  // TODO(crbug.com/1406633): Finalize button colors.
-  mixer[kColorButtonForegroundTonal] = {dark_mode
-                                            ? SkColorSetRGB(0xC2, 0xE7, 0xFF)
-                                            : SkColorSetRGB(0x00, 0x1D, 0x35)};
+  mixer[kColorButtonForegroundTonal] = {kColorSysOnPrimaryContainer};
   mixer[kColorButtonForegroundUnchecked] = {kColorSecondaryForeground};
   mixer[kColorCustomFrameCaptionForeground] = {SK_ColorWHITE};
   mixer[kColorDebugBoundsOutline] = SetAlpha(SK_ColorRED, 0x30);
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index 0f18adc..37fcacce 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -820,7 +820,7 @@
                         // URLs.
                         // TODO(b/237216270): Restrict to the ODFS extension ID.
                         if (action.id ===
-                            constants.FSP_ACTION_HIDDEN_ODFS_URL) {
+                            constants.FSP_ACTION_HIDDEN_ONEDRIVE_URL) {
                           return;
                         }
                         actions[action.id] = new CustomAction(
diff --git a/ui/file_manager/file_manager/foreground/js/constants.js b/ui/file_manager/file_manager/foreground/js/constants.js
index fa20f61..a02850d 100644
--- a/ui/file_manager/file_manager/foreground/js/constants.js
+++ b/ui/file_manager/file_manager/foreground/js/constants.js
@@ -114,4 +114,4 @@
  * URLs.
  * @const {string}
  */
-constants.FSP_ACTION_HIDDEN_ODFS_URL = 'HIDDEN_ODFS_URL';
+constants.FSP_ACTION_HIDDEN_ONEDRIVE_URL = 'HIDDEN_ONEDRIVE_URL';
diff --git a/ui/touch_selection/OWNERS b/ui/touch_selection/OWNERS
deleted file mode 100644
index c65e542..0000000
--- a/ui/touch_selection/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mohsen@chromium.org
diff --git a/ui/views/accessibility/ax_tree_source_views.cc b/ui/views/accessibility/ax_tree_source_views.cc
index 31ef16bb..4b0d74f 100644
--- a/ui/views/accessibility/ax_tree_source_views.cc
+++ b/ui/views/accessibility/ax_tree_source_views.cc
@@ -35,10 +35,7 @@
   // In Views, we only support setting the selection within a single node,
   // not across multiple nodes like on the web.
   if (action.action == ax::mojom::Action::kSetSelection) {
-    if (action.anchor_node_id != action.focus_node_id) {
-      NOTREACHED();
-      return;
-    }
+    CHECK_EQ(action.anchor_node_id, action.focus_node_id);
     id = action.anchor_node_id;
   }
 
diff --git a/ui/views/accessibility/ax_virtual_view.cc b/ui/views/accessibility/ax_virtual_view.cc
index b18c0ec..41dfc00 100644
--- a/ui/views/accessibility/ax_virtual_view.cc
+++ b/ui/views/accessibility/ax_virtual_view.cc
@@ -130,12 +130,10 @@
   if (parent_view_)
     return parent_view_->RemoveVirtualChildView(this);
 
-  if (virtual_parent_view_)
-    return virtual_parent_view_->RemoveChildView(this);
-
   // This virtual view hasn't been added to a parent view yet.
-  NOTREACHED() << "Cannot remove from parent view if there is no parent.";
-  return {};
+  CHECK(virtual_parent_view_)
+      << "Cannot remove from parent view if there is no parent.";
+  return virtual_parent_view_->RemoveChildView(this);
 }
 
 std::unique_ptr<AXVirtualView> AXVirtualView::RemoveChildView(
@@ -296,14 +294,12 @@
     }
   }
 
-  NOTREACHED() << "|index| should be less than the child count.";
-  return nullptr;
+  NOTREACHED_NORETURN() << "|index| should be less than the child count.";
 }
 
 #if !BUILDFLAG(IS_MAC)
 gfx::NativeViewAccessible AXVirtualView::GetNSWindow() {
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 #endif
 
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 57349dfd..6719a3d 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -385,8 +385,8 @@
       }
     }
 
-    NOTREACHED() << "|index| should be less than the unignored child count.";
-    return nullptr;
+    NOTREACHED_NORETURN()
+        << "|index| should be less than the unignored child count.";
   }
 
   // Our widget might have child widgets. If this is a root view, include those
@@ -424,11 +424,9 @@
     }
   }
 
-  if (index < child_widgets_result.child_widgets.size())
-    return child_widgets[index]->GetRootView()->GetNativeViewAccessible();
-
-  NOTREACHED() << "|index| should be less than the unignored child count.";
-  return nullptr;
+  CHECK_LT(index, child_widgets_result.child_widgets.size())
+      << "|index| should be less than the unignored child count.";
+  return child_widgets[index]->GetRootView()->GetNativeViewAccessible();
 }
 
 bool ViewAXPlatformNodeDelegate::HasModalDialog() const {
diff --git a/ui/views/accessibility/views_ax_tree_manager.cc b/ui/views/accessibility/views_ax_tree_manager.cc
index 1c77f618..078d982 100644
--- a/ui/views/accessibility/views_ax_tree_manager.cc
+++ b/ui/views/accessibility/views_ax_tree_manager.cc
@@ -130,12 +130,13 @@
       continue;
 
     ui::AXTreeUpdate update;
+    // TODO(pbos): Consider rewriting this as a CHECK now that this is fatally
+    // aborting.
     if (!tree_serializer_.SerializeChanges(wrapper, &update)) {
       std::string error;
       ui::AXTreeSourceChecker<AXAuraObjWrapper*> checker(&tree_source_);
       checker.CheckAndGetErrorString(&error);
-      NOTREACHED() << error << '\n' << update.ToString();
-      return;
+      NOTREACHED_NORETURN() << error << '\n' << update.ToString();
     }
 
     updates.push_back(update);
@@ -150,10 +151,7 @@
     return;
 
   for (const ui::AXTreeUpdate& update : updates) {
-    if (!ax_tree_->Unserialize(update)) {
-      NOTREACHED() << ax_tree_->error();
-      return;
-    }
+    CHECK(ax_tree_->Unserialize(update)) << ax_tree_->error();
   }
 
   // Unserializing the updates into our AXTree should have prompted our
diff --git a/ui/views/animation/animation_sequence_block.cc b/ui/views/animation/animation_sequence_block.cc
index 2ea113c..15eba44 100644
--- a/ui/views/animation/animation_sequence_block.cc
+++ b/ui/views/animation/animation_sequence_block.cc
@@ -294,7 +294,7 @@
             duration);
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
     element->set_tween_type(pair.second.tween_type_);
     owner_->AddLayerAnimationElement(PassKey(), pair.first, start_, duration,
diff --git a/ui/views/animation/ink_drop_animation_ended_reason.cc b/ui/views/animation/ink_drop_animation_ended_reason.cc
index d2bac5d..7a8219f8 100644
--- a/ui/views/animation/ink_drop_animation_ended_reason.cc
+++ b/ui/views/animation/ink_drop_animation_ended_reason.cc
@@ -17,9 +17,7 @@
     case InkDropAnimationEndedReason::PRE_EMPTED:
       return "PRE_EMPTED";
   }
-  NOTREACHED()
-      << "Should never be reached but is necessary for some compilers.";
-  return std::string();
+  NOTREACHED_NORETURN();
 }
 
 }  // namespace views
diff --git a/ui/views/animation/ink_drop_host_unittest.cc b/ui/views/animation/ink_drop_host_unittest.cc
index 6b3db42..82e0e75 100644
--- a/ui/views/animation/ink_drop_host_unittest.cc
+++ b/ui/views/animation/ink_drop_host_unittest.cc
@@ -286,8 +286,7 @@
  public:
   BasicTestViewWithInkDrop() {
     InkDrop::Install(this, std::make_unique<InkDropHost>(this));
-    // Call SetBaseColor to avoid hitting a NOTREACHED() for fetching an
-    // undefined color.
+    // Call SetBaseColor to avoid fetching an undefined color.
     InkDrop::Get(this)->SetBaseColor(gfx::kPlaceholderColor);
   }
   BasicTestViewWithInkDrop(const BasicTestViewWithInkDrop&) = delete;
diff --git a/ui/views/animation/ink_drop_impl.cc b/ui/views/animation/ink_drop_impl.cc
index dc4eb28..1c290a2 100644
--- a/ui/views/animation/ink_drop_impl.cc
+++ b/ui/views/animation/ink_drop_impl.cc
@@ -528,9 +528,7 @@
       return std::make_unique<ShowHighlightOnRippleHiddenState>(
           this, base::TimeDelta());
   }
-  // Required for some compilers.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 std::unique_ptr<InkDropImpl::HighlightState>
@@ -548,8 +546,7 @@
           this, animation_duration);
   }
   // Required for some compilers.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 std::unique_ptr<InkDropImpl::HighlightState>
@@ -567,8 +564,7 @@
           this, animation_duration);
   }
   // Required for some compilers.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 InkDropImpl::InkDropImpl(InkDropHost* ink_drop_host,
diff --git a/ui/views/animation/ink_drop_state.cc b/ui/views/animation/ink_drop_state.cc
index 903e1ee..36bba93 100644
--- a/ui/views/animation/ink_drop_state.cc
+++ b/ui/views/animation/ink_drop_state.cc
@@ -28,9 +28,7 @@
     case InkDropState::DEACTIVATED:
       return std::string("DEACTIVATED");
   }
-  NOTREACHED()
-      << "Should never be reached but is necessary for some compilers.";
-  return std::string("UNKNOWN");
+  NOTREACHED_NORETURN();
 }
 
 }  // namespace views
diff --git a/ui/views/animation/slide_out_controller.cc b/ui/views/animation/slide_out_controller.cc
index dd8e539d..c4045ab 100644
--- a/ui/views/animation/slide_out_controller.cc
+++ b/ui/views/animation/slide_out_controller.cc
@@ -84,7 +84,7 @@
         gesture_amount_ = swipe_control_width_;
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
     delegate_->OnSlideStarted();
   } else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
diff --git a/ui/views/animation/square_ink_drop_ripple.cc b/ui/views/animation/square_ink_drop_ripple.cc
index b0afa28..227685f 100644
--- a/ui/views/animation/square_ink_drop_ripple.cc
+++ b/ui/views/animation/square_ink_drop_ripple.cc
@@ -222,8 +222,8 @@
     case VERTICAL_RECT:
       return "VERTICAL_RECT";
     case PAINTED_SHAPE_COUNT:
-      NOTREACHED() << "The PAINTED_SHAPE_COUNT value should never be used.";
-      return "PAINTED_SHAPE_COUNT";
+      NOTREACHED_NORETURN()
+          << "The PAINTED_SHAPE_COUNT value should never be used.";
   }
   return "UNKNOWN";
 }
@@ -563,8 +563,8 @@
       delegate = rect_layer_delegate_.get();
       break;
     case PAINTED_SHAPE_COUNT:
-      NOTREACHED() << "PAINTED_SHAPE_COUNT is not an actual shape type.";
-      break;
+      NOTREACHED_NORETURN()
+          << "PAINTED_SHAPE_COUNT is not an actual shape type.";
   }
 
   ui::Layer* layer = new ui::Layer();
diff --git a/ui/views/bubble/bubble_border_arrow_utils.cc b/ui/views/bubble/bubble_border_arrow_utils.cc
index 7848d82..0638df9a 100644
--- a/ui/views/bubble/bubble_border_arrow_utils.cc
+++ b/ui/views/bubble/bubble_border_arrow_utils.cc
@@ -46,8 +46,7 @@
       return anchor_rect.left_center();
 
     default:
-      NOTREACHED();
-      return gfx::Point();
+      NOTREACHED_NORETURN();
   }
 }
 
@@ -93,8 +92,7 @@
       return anchor_point - contents_bounds.right_center();
 
     default:
-      NOTREACHED();
-      return gfx::Vector2d();
+      NOTREACHED_NORETURN();
   }
 }
 
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 9f1b9b7..8616a2f 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -567,8 +567,7 @@
   switch (field->type(GetPassKey())) {
     case ui::DialogModelField::kButton:
       // TODO(pbos): Add support for buttons that are part of content area.
-      NOTREACHED();
-      return;
+      NOTREACHED_NORETURN();
     case ui::DialogModelField::kParagraph:
       AddOrUpdateParagraph(field->AsParagraph(GetPassKey()));
       break;
@@ -906,8 +905,7 @@
     if (info.field_view == view)
       return info;
   }
-  NOTREACHED();
-  return {};
+  NOTREACHED_NORETURN();
 }
 
 View* BubbleDialogModelHost::GetTargetView(
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc
index 92f676c2..d17b95a 100644
--- a/ui/views/controls/button/button.cc
+++ b/ui/views/controls/button/button.cc
@@ -151,7 +151,7 @@
     case ui::NativeTheme::kPressed:
       return Button::STATE_PRESSED;
     case ui::NativeTheme::kNumStates:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
   return Button::STATE_NORMAL;
 }
diff --git a/ui/views/controls/button/button_controller.cc b/ui/views/controls/button/button_controller.cc
index 18f21a0..b27d698 100644
--- a/ui/views/controls/button/button_controller.cc
+++ b/ui/views/controls/button/button_controller.cc
@@ -100,8 +100,7 @@
       return false;
   }
 
-  NOTREACHED();
-  return false;
+  NOTREACHED_NORETURN();
 }
 
 bool ButtonController::OnKeyReleased(const ui::KeyEvent& event) {
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index 98b0f831..749cb84bd 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -428,7 +428,7 @@
     case STATE_DISABLED:
       return ui::NativeTheme::kDisabled;
     case STATE_COUNT:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
   return ui::NativeTheme::kNormal;
 }
diff --git a/ui/views/controls/combobox/combobox_unittest.cc b/ui/views/controls/combobox/combobox_unittest.cc
index 34c0220..83db162 100644
--- a/ui/views/controls/combobox/combobox_unittest.cc
+++ b/ui/views/controls/combobox/combobox_unittest.cc
@@ -78,8 +78,7 @@
       if (separators_.find(index) == separators_.end())
         return index;
     }
-    NOTREACHED();
-    return 0;
+    NOTREACHED_NORETURN();
   }
 
   void SetSeparators(const std::set<size_t>& separators) {
diff --git a/ui/views/controls/combobox/empty_combobox_model.cc b/ui/views/controls/combobox/empty_combobox_model.cc
index 5597bb4..f34bd125 100644
--- a/ui/views/controls/combobox/empty_combobox_model.cc
+++ b/ui/views/controls/combobox/empty_combobox_model.cc
@@ -18,8 +18,7 @@
 }
 
 std::u16string EmptyComboboxModel::GetItemAt(size_t index) const {
-  NOTREACHED();
-  return std::u16string();
+  NOTREACHED_NORETURN();
 }
 
 absl::optional<size_t> EmptyComboboxModel::GetDefaultIndex() const {
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc
index cc8d096f..d3cfc17 100644
--- a/ui/views/controls/focus_ring.cc
+++ b/ui/views/controls/focus_ring.cc
@@ -274,11 +274,8 @@
     return SkRRect::MakeOval(gfx::RectFToSkRect(rect));
   }
 
-  if (path.isRRect(&rbounds))
-    return RingRectFromPathRect(rbounds);
-
-  NOTREACHED();
-  return SkRRect();
+  CHECK(path.isRRect(&rbounds));
+  return RingRectFromPathRect(rbounds);
 }
 
 void FocusRing::GetAccessibleNodeData(ui::AXNodeData* node_data) {
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 7f8df43..cc97944 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -1034,7 +1034,7 @@
 }
 
 void Label::SetTextBeingDragged(bool value) {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 int Label::GetViewHeight() const {
@@ -1062,8 +1062,7 @@
 }
 
 bool Label::PasteSelectionClipboard() {
-  NOTREACHED();
-  return false;
+  NOTREACHED_NORETURN();
 }
 
 void Label::UpdateSelectionClipboard() {
@@ -1101,7 +1100,7 @@
       UpdateSelectionClipboard();
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
 }
 
diff --git a/ui/views/controls/menu/menu_closure_animation_mac.mm b/ui/views/controls/menu/menu_closure_animation_mac.mm
index 0e33b00..7326c15 100644
--- a/ui/views/controls/menu/menu_closure_animation_mac.mm
+++ b/ui/views/controls/menu/menu_closure_animation_mac.mm
@@ -105,7 +105,7 @@
 
 void MenuClosureAnimationMac::AnimationCanceled(
     const gfx::Animation* animation) {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 64229eee..2309794 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -1846,11 +1846,8 @@
 
   delegate_->SiblingMenuCreated(alt_menu);
 
-  if (!button) {
-    // If the delegate returns a menu, they must also return a button.
-    NOTREACHED();
-    return false;
-  }
+  // If the delegate returns a menu, they must also return a button.
+  CHECK(button);
 
   // There is a sibling menu, update the button state, hide the current menu
   // and show the new one.
diff --git a/ui/views/controls/menu/menu_delegate.cc b/ui/views/controls/menu/menu_delegate.cc
index 5ddb15a..1526ce13 100644
--- a/ui/views/controls/menu/menu_delegate.cc
+++ b/ui/views/controls/menu/menu_delegate.cc
@@ -103,16 +103,16 @@
     MenuItemView* item,
     const ui::DropTargetEvent& event,
     DropPosition* position) {
-  NOTREACHED() << "If you override CanDrop, you need to override this too";
-  return ui::mojom::DragOperation::kNone;
+  NOTREACHED_NORETURN()
+      << "If you override CanDrop, you must override this too";
 }
 
 views::View::DropCallback MenuDelegate::GetDropCallback(
     MenuItemView* menu,
     DropPosition position,
     const ui::DropTargetEvent& event) {
-  NOTREACHED() << "If you override CanDrop, you need to override this too";
-  return base::NullCallback();
+  NOTREACHED_NORETURN()
+      << "If you override CanDrop, you must override this too";
 }
 
 bool MenuDelegate::CanDrag(MenuItemView* menu) {
@@ -120,12 +120,13 @@
 }
 
 void MenuDelegate::WriteDragData(MenuItemView* sender, OSExchangeData* data) {
-  NOTREACHED() << "If you override CanDrag, you must override this too.";
+  NOTREACHED_NORETURN()
+      << "If you override CanDrag, you must override this too.";
 }
 
 int MenuDelegate::GetDragOperations(MenuItemView* sender) {
-  NOTREACHED() << "If you override CanDrag, you must override this too.";
-  return 0;
+  NOTREACHED_NORETURN()
+      << "If you override CanDrag, you must override this too.";
 }
 
 bool MenuDelegate::ShouldCloseOnDragComplete() {
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc
index 944a82d..daf9fff 100644
--- a/ui/views/controls/menu/menu_model_adapter.cc
+++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -153,23 +153,15 @@
 void MenuModelAdapter::ExecuteCommand(int id) {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
-    model->ActivatedAt(index);
-    return;
-  }
-
-  NOTREACHED();
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  model->ActivatedAt(index);
 }
 
 void MenuModelAdapter::ExecuteCommand(int id, int mouse_event_flags) {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
-    model->ActivatedAt(index, mouse_event_flags);
-    return;
-  }
-
-  NOTREACHED();
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  model->ActivatedAt(index, mouse_event_flags);
 }
 
 bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source,
@@ -183,21 +175,15 @@
                                       ui::Accelerator* accelerator) const {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
-    return model->GetAcceleratorAt(index, accelerator);
-
-  NOTREACHED();
-  return false;
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  return model->GetAcceleratorAt(index, accelerator);
 }
 
 std::u16string MenuModelAdapter::GetLabel(int id) const {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
-    return model->GetLabelAt(index);
-
-  NOTREACHED();
-  return std::u16string();
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  return model->GetLabelAt(index);
 }
 
 const gfx::FontList* MenuModelAdapter::GetLabelFontList(int id) const {
@@ -216,55 +202,38 @@
 bool MenuModelAdapter::IsCommandEnabled(int id) const {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
-    return model->IsEnabledAt(index);
-
-  NOTREACHED();
-  return false;
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  return model->IsEnabledAt(index);
 }
 
 bool MenuModelAdapter::IsCommandVisible(int id) const {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
-    return model->IsVisibleAt(index);
-
-  NOTREACHED();
-  return false;
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  return model->IsVisibleAt(index);
 }
 
 bool MenuModelAdapter::IsItemChecked(int id) const {
   ui::MenuModel* model = menu_model_;
   size_t index = 0;
-  if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
-    return model->IsItemCheckedAt(index);
-
-  NOTREACHED();
-  return false;
+  CHECK(ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index));
+  return model->IsItemCheckedAt(index);
 }
 
 void MenuModelAdapter::WillShowMenu(MenuItemView* menu) {
   // Look up the menu model for this menu.
   const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
       menu_map_.find(menu);
-  if (map_iterator != menu_map_.end()) {
-    map_iterator->second->MenuWillShow();
-    return;
-  }
-
-  NOTREACHED();
+  CHECK(map_iterator != menu_map_.end());
+  map_iterator->second->MenuWillShow();
 }
 
 void MenuModelAdapter::WillHideMenu(MenuItemView* menu) {
   // Look up the menu model for this menu.
   const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
       menu_map_.find(menu);
-  if (map_iterator != menu_map_.end()) {
-    map_iterator->second->MenuWillClose();
-    return;
-  }
-
-  NOTREACHED();
+  CHECK(map_iterator != menu_map_.end());
+  map_iterator->second->MenuWillClose();
 }
 
 void MenuModelAdapter::OnMenuClosed(MenuItemView* menu) {
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index 1319c56..5f8fdc6 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -218,8 +218,9 @@
 
     ui::ElementTrackerMac::GetInstance()->NotifyMenuDoneShowing(menu);
 
-  } else if (run_types & MenuRunner::COMBOBOX) {
-    NSMenuItem* checked_item = FirstCheckedItem(menu_controller_);
+  } else {
+    CHECK(run_types & MenuRunner::COMBOBOX);
+    NSMenuItem* const checked_item = FirstCheckedItem(menu_controller_);
     base::scoped_nsobject<NSView> anchor_view(CreateMenuAnchorView(
         window, bounds, checked_item, menu.size.width, anchor));
     [menu setMinimumWidth:bounds.width() + kNativeCheckmarkWidth];
@@ -228,8 +229,6 @@
                             inView:anchor_view];
 
     [anchor_view removeFromSuperview];
-  } else {
-    NOTREACHED();
   }
 
   closing_event_time_ = ui::EventTimeForNow();
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index 844a9ed..72df09a 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -515,8 +515,7 @@
       more_content_bottom_thickness_ = thickness;
       break;
     default:
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
   }
 
   UpdateOverflowIndicatorVisibility(CurrentOffset());
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 51c8b75..318ef77 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -497,8 +497,7 @@
     case UiConfig::kRtlWithLayers:
       return "RTL_LAYERS";
   }
-  NOTREACHED();
-  return std::string();
+  NOTREACHED_NORETURN();
 }
 
 // Verifies the viewport is sized to fit the available space.
diff --git a/ui/views/controls/scrollbar/scroll_bar_button.cc b/ui/views/controls/scrollbar/scroll_bar_button.cc
index 7fd39c3..68d4d77 100644
--- a/ui/views/controls/scrollbar/scroll_bar_button.cc
+++ b/ui/views/controls/scrollbar/scroll_bar_button.cc
@@ -83,8 +83,7 @@
       return ui::NativeTheme::kScrollbarRightArrow;
   }
 
-  NOTREACHED();
-  return ui::NativeTheme::kScrollbarUpArrow;
+  NOTREACHED_NORETURN();
 }
 
 ui::NativeTheme::State ScrollBarButton::GetNativeThemeState() const {
@@ -101,8 +100,7 @@
       break;
   }
 
-  NOTREACHED();
-  return ui::NativeTheme::kNormal;
+  NOTREACHED_NORETURN();
 }
 
 void ScrollBarButton::RepeaterNotifyClick() {
diff --git a/ui/views/controls/scrollbar/scroll_bar_views.cc b/ui/views/controls/scrollbar/scroll_bar_views.cc
index 9693fcf..862122a 100644
--- a/ui/views/controls/scrollbar/scroll_bar_views.cc
+++ b/ui/views/controls/scrollbar/scroll_bar_views.cc
@@ -101,11 +101,8 @@
     case Button::STATE_NORMAL:
       return ui::NativeTheme::kNormal;
     case Button::STATE_COUNT:
-      break;
+      NOTREACHED_NORETURN();
   }
-
-  NOTREACHED();
-  return ui::NativeTheme::kNormal;
 }
 
 }  // namespace
diff --git a/ui/views/controls/slider_unittest.cc b/ui/views/controls/slider_unittest.cc
index 677e986..8375a29e 100644
--- a/ui/views/controls/slider_unittest.cc
+++ b/ui/views/controls/slider_unittest.cc
@@ -202,7 +202,7 @@
       slider->SetAllowedValues(&values_);
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
   gfx::Size size = slider->GetPreferredSize();
   slider->SetSize(size);
diff --git a/ui/views/controls/table/table_utils.cc b/ui/views/controls/table/table_utils.cc
index 126b9c1..673494b 100644
--- a/ui/views/controls/table/table_utils.cc
+++ b/ui/views/controls/table/table_utils.cc
@@ -107,8 +107,7 @@
     case ui::TableColumn::RIGHT:
       return gfx::Canvas::TEXT_ALIGN_RIGHT;
   }
-  NOTREACHED();
-  return gfx::Canvas::TEXT_ALIGN_LEFT;
+  NOTREACHED_NORETURN();
 }
 
 absl::optional<size_t> GetClosestVisibleColumnIndex(const TableView* table,
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index bacd5f35..2bd3615 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -1845,23 +1845,19 @@
   DCHECK_LT(row, GetRowCount());
   if (header_)
     ++row;
-  if (row < GetViewAccessibility().virtual_children().size()) {
-    const auto& ax_row = GetViewAccessibility().virtual_children()[row];
-    DCHECK(ax_row);
-    DCHECK_EQ(ax_row->GetData().role, ax::mojom::Role::kRow);
-    return ax_row.get();
-  }
-  NOTREACHED() << "|row| not found. Did you forget to call "
-                  "RebuildVirtualAccessibilityChildren()?";
-  return nullptr;
+  CHECK_LT(row, GetViewAccessibility().virtual_children().size())
+      << "|row| not found. Did you forget to call "
+         "RebuildVirtualAccessibilityChildren()?";
+
+  const auto& ax_row = GetViewAccessibility().virtual_children()[row];
+  DCHECK(ax_row);
+  DCHECK_EQ(ax_row->GetData().role, ax::mojom::Role::kRow);
+  return ax_row.get();
 }
 
 AXVirtualView* TableView::GetVirtualAccessibilityHeaderRow() {
-  if (!header_) {
-    NOTREACHED() << "|row| not found. Did you forget to call "
+  CHECK(header_) << "|row| not found. Did you forget to call "
                     "RebuildVirtualAccessibilityChildren()?";
-    return nullptr;
-  }
   // The header row is always the first virtual child.
   const auto& ax_row = GetViewAccessibility().virtual_children()[size_t{0}];
   DCHECK(ax_row);
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 98753af10..691fd6f8 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1770,8 +1770,7 @@
     case ui::TextEditCommand::INVALID_COMMAND:
       return false;
   }
-  NOTREACHED();
-  return false;
+  NOTREACHED_NORETURN();
 }
 
 void Textfield::SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) {
@@ -2135,8 +2134,7 @@
     case ui::TextEditCommand::SET_MARK:
     case ui::TextEditCommand::UNSELECT:
     case ui::TextEditCommand::INVALID_COMMAND:
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
   }
 
   return {changed, cursor_changed};
diff --git a/ui/views/controls/webview/unhandled_keyboard_event_handler.cc b/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
index 3645af6..e520615 100644
--- a/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
+++ b/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
@@ -17,10 +17,8 @@
 bool UnhandledKeyboardEventHandler::HandleKeyboardEvent(
     const content::NativeWebKeyboardEvent& event,
     FocusManager* focus_manager) {
-  if (!focus_manager) {
-    NOTREACHED();
-    return false;
-  }
+  CHECK(focus_manager);
+
   // Previous calls to TranslateMessage can generate Char events as well as
   // RawKeyDown events, even if the latter triggered an accelerator.  In these
   // cases, we discard the Char events.
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index a4e4703..af075e8 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -230,8 +230,7 @@
     case WebDialogDelegate::FrameKind::kDialog:
       return DialogDelegate::CreateDialogFrameView(widget);
     default:
-      NOTREACHED() << "Unknown frame kind type enum specified.";
-      return std::unique_ptr<NonClientFrameView>{};
+      NOTREACHED_NORETURN() << "Unknown frame kind type enum specified.";
   }
 }
 
diff --git a/ui/views/corewm/tooltip_controller.cc b/ui/views/corewm/tooltip_controller.cc
index 3ed8c373..b414937 100644
--- a/ui/views/corewm/tooltip_controller.cc
+++ b/ui/views/corewm/tooltip_controller.cc
@@ -124,10 +124,8 @@
       return screen_target;
     }
     default:
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
   }
-  return nullptr;
 }
 
 }  // namespace
diff --git a/ui/views/examples/examples_with_content_main.cc b/ui/views/examples/examples_with_content_main.cc
index 7d4edc7..5a77472 100644
--- a/ui/views/examples/examples_with_content_main.cc
+++ b/ui/views/examples/examples_with_content_main.cc
@@ -52,7 +52,7 @@
   // sandbox::InitLibcUrandomOverrides(). See http://crbug.com/374712.
   if (!browser_context) {
     browser_context->SaveSessionState();
-    NOTREACHED();
+    NOTREACHED_NORETURN();
   }
 }
 
diff --git a/ui/views/examples/tree_view_example.cc b/ui/views/examples/tree_view_example.cc
index 9d64a83..ea27079 100644
--- a/ui/views/examples/tree_view_example.cc
+++ b/ui/views/examples/tree_view_example.cc
@@ -218,7 +218,7 @@
       AddNewNode();
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
 }
 
diff --git a/ui/views/interaction/element_tracker_views.cc b/ui/views/interaction/element_tracker_views.cc
index b475bff7..5d4ab359 100644
--- a/ui/views/interaction/element_tracker_views.cc
+++ b/ui/views/interaction/element_tracker_views.cc
@@ -208,19 +208,16 @@
           data.element.get());
       data.element.reset();
     } else if (visible && old_context != data.context) {
-      if (update_reason == UpdateReason::kVisbilityFromRoot) {
-        // This can happen in some tests where a widget is closed before it
-        // actually becomes visible, or a parent widget is closed underneath us.
-        if (!view->GetWidget()->IsVisible()) {
-          ui::ElementTracker::GetFrameworkDelegate()->NotifyElementHidden(
-              data.element.get());
-          data.element.reset();
-        }
-      } else {
-        NOTREACHED()
-            << "We should always get a removed-from-widget notification before "
-               "an added-to-widget notification, the context should never "
-               "change while a view is visible.";
+      CHECK(update_reason == UpdateReason::kVisbilityFromRoot)
+          << "We should always get a removed-from-widget notification before "
+             "an added-to-widget notification, the context should never "
+             "change while a view is visible.";
+      // This can happen in some tests where a widget is closed before it
+      // actually becomes visible, or a parent widget is closed underneath us.
+      if (!view->GetWidget()->IsVisible()) {
+        ui::ElementTracker::GetFrameworkDelegate()->NotifyElementHidden(
+            data.element.get());
+        data.element.reset();
       }
     }
   }
diff --git a/ui/views/interaction/interaction_test_util_views.cc b/ui/views/interaction/interaction_test_util_views.cc
index 6edffea1..fcf1393 100644
--- a/ui/views/interaction/interaction_test_util_views.cc
+++ b/ui/views/interaction/interaction_test_util_views.cc
@@ -99,9 +99,7 @@
  private:
   // WidgetObserver:
   void OnWidgetDestroyed(Widget* widget) override {
-    widget_observation_.Reset();
-    run_loop_.Quit();
-    NOTREACHED() << "Widget destroyed before observation.";
+    NOTREACHED_NORETURN() << "Widget destroyed before observation.";
   }
   void OnWidgetActivationChanged(Widget* widget, bool active) override {
     if (!active) {
@@ -209,8 +207,7 @@
           LOG(ERROR) << "Unable to select dropdown menu item.";
           break;
         case ui::test::ActionResult::kNotAttempted:
-          NOTREACHED();
-          break;
+          NOTREACHED_NORETURN();
         case ui::test::ActionResult::kKnownIncompatible:
           LOG(WARNING)
               << "Select dropdown item not available on this platform with "
diff --git a/ui/views/layout/animating_layout_manager.cc b/ui/views/layout/animating_layout_manager.cc
index 32c5b365..1e2a309 100644
--- a/ui/views/layout/animating_layout_manager.cc
+++ b/ui/views/layout/animating_layout_manager.cc
@@ -500,8 +500,7 @@
     const SizeBounds& size_bounds) const {
   // This class directly overrides Layout() so GetProposedLayout() and
   // CalculateProposedLayout() are not called.
-  NOTREACHED();
-  return ProposedLayout();
+  NOTREACHED_NORETURN();
 }
 
 void AnimatingLayoutManager::OnInstalled(View* host) {
@@ -757,8 +756,7 @@
           child_layout.visible = false;
           break;
         case LayoutFadeType::kContinuingFade:
-          NOTREACHED();
-          continue;
+          NOTREACHED_NORETURN();
       }
     } else if (default_fade_mode_ == FadeInOutMode::kHide) {
       child_layout.child_view = fade_info.child_view;
@@ -770,8 +768,7 @@
 
       switch (default_fade_mode_) {
         case FadeInOutMode::kHide:
-          NOTREACHED();
-          break;
+          NOTREACHED_NORETURN();
         case FadeInOutMode::kScaleFromMinimum:
           child_layout = CalculateScaleFade(fade_info, scale_percent,
                                             /* scale_from_zero */ false);
@@ -1007,8 +1004,7 @@
         new_bounds.set_origin_main(trailing_reference_point - new_size);
         break;
       case LayoutFadeType::kContinuingFade:
-        NOTREACHED();
-        break;
+        NOTREACHED_NORETURN();
     }
     new_bounds.set_size_main(new_size);
     child_layout.bounds = Denormalize(orientation(), new_bounds);
@@ -1043,8 +1039,7 @@
       fully_faded_layout = &target_layout_;
       break;
     case LayoutFadeType::kContinuingFade:
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
   }
 
   if (slide_from_leading) {
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc
index ddab6c0..1d0c1c7 100644
--- a/ui/views/layout/box_layout.cc
+++ b/ui/views/layout/box_layout.cc
@@ -198,8 +198,7 @@
           size = total_main_axis_size;
           break;
         default:
-          NOTREACHED();
-          break;
+          NOTREACHED_NORETURN();
       }
     }
     gfx::Rect new_child_area(child_area);
diff --git a/ui/views/layout/layout_provider.cc b/ui/views/layout/layout_provider.cc
index 349bce94..8b958eb 100644
--- a/ui/views/layout/layout_provider.cc
+++ b/ui/views/layout/layout_provider.cc
@@ -68,8 +68,7 @@
     case InsetsMetric::INSETS_LABEL_BUTTON:
       return gfx::Insets::VH(5, 6);
   }
-  NOTREACHED();
-  return gfx::Insets();
+  NOTREACHED_NORETURN();
 }
 
 int LayoutProvider::GetDistanceMetric(int metric) const {
@@ -122,11 +121,9 @@
       return 16;
     case VIEWS_DISTANCE_END:
     case VIEWS_DISTANCE_MAX:
-      NOTREACHED();
-      return 0;
+      NOTREACHED_NORETURN();
   }
-  NOTREACHED();
-  return 0;
+  NOTREACHED_NORETURN();
 }
 
 const TypographyProvider& LayoutProvider::GetTypographyProvider() const {
diff --git a/ui/views/layout/table_layout.cc b/ui/views/layout/table_layout.cc
index ae6dda41..cf147c6 100644
--- a/ui/views/layout/table_layout.cc
+++ b/ui/views/layout/table_layout.cc
@@ -144,7 +144,7 @@
         *location = *location + available_size - *size;
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
   }
 }
@@ -449,11 +449,9 @@
         break;
       col = 0;
     }
-    if (row == rows_.size()) {
-      NOTREACHED() << "There're not enough cells for layout. Did you forget to "
-                      "call AddRows()?";
-      break;
-    }
+    CHECK_LT(row, rows_.size())
+        << "There're not enough cells for layout. Did you forget to "
+           "call AddRows()?";
 
     // Construct a ViewState for this `child`.
     const gfx::Size* span = child->GetProperty(kTableColAndRowSpanKey);
diff --git a/ui/views/mouse_watcher.cc b/ui/views/mouse_watcher.cc
index a074b53..1c255cefa 100644
--- a/ui/views/mouse_watcher.cc
+++ b/ui/views/mouse_watcher.cc
@@ -53,8 +53,7 @@
         HandleMouseEvent(EventType::kPress);
         break;
       default:
-        NOTREACHED();
-        break;
+        NOTREACHED_NORETURN();
     }
   }
 
diff --git a/ui/views/selection_controller.cc b/ui/views/selection_controller.cc
index a36cbd5..61ba0ce 100644
--- a/ui/views/selection_controller.cc
+++ b/ui/views/selection_controller.cc
@@ -70,7 +70,7 @@
         SelectAll();
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
   }
 
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm
index e7be1cc2..c9b9903 100644
--- a/ui/views/test/event_generator_delegate_mac.mm
+++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -114,8 +114,7 @@
     case ui::ET_SCROLL_FLING_START:
       return NSEventTypeSwipe;
     default:
-      NOTREACHED();
-      return NSEventTypeApplicationDefined;
+      NOTREACHED_NORETURN();
   }
 }
 
@@ -183,15 +182,13 @@
       // for the generator to handle entered/exited separately. It's the
       // responsibility of views::internal::RootView to convert the moved events
       // into entered and exited events for the individual views.
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
     case NSEventTypeSwipe:
       // NSEventTypeSwipe events can't be generated using public interfaces on
       // NSEvent, so this will need to be handled at a higher level.
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
 }
 
@@ -479,7 +476,7 @@
 }
 
 void EventGeneratorDelegateMac::OnTouchEvent(ui::TouchEvent* event) {
-  NOTREACHED() << "Touchscreen events not supported on Chrome Mac.";
+  NOTREACHED_NORETURN() << "Touchscreen events not supported on Chrome Mac.";
 }
 
 void EventGeneratorDelegateMac::OnScrollEvent(ui::ScrollEvent* event) {
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index 6884f500..7929750 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -186,8 +186,7 @@
   return new test::TestPlatformNativeWidget<NativeWidgetAura>(delegate, true,
                                                               nullptr);
 #else
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 #endif
 }
 
diff --git a/ui/views/test/widget_test_aura.cc b/ui/views/test/widget_test_aura.cc
index 10ad006..4fec98408 100644
--- a/ui/views/test/widget_test_aura.cc
+++ b/ui/views/test/widget_test_aura.cc
@@ -125,9 +125,9 @@
 // of lacros-chrome is complete.
 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   return widget->GetNativeWindow()->delegate()->GetMinimumSize();
+#else
+  NOTREACHED_NORETURN();
 #endif
-  NOTREACHED();
-  return gfx::Size();
 }
 
 // static
diff --git a/ui/views/touchui/OWNERS b/ui/views/touchui/OWNERS
deleted file mode 100644
index c65e542..0000000
--- a/ui/views/touchui/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mohsen@chromium.org
diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc
index 7281f69..6df3c8a 100644
--- a/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/ui/views/touchui/touch_selection_controller_impl.cc
@@ -111,8 +111,8 @@
     case gfx::SelectionBound::RIGHT:
       return GetRightHandleImage();
     default:
-      NOTREACHED() << "Invalid touch handle bound type: " << bound_type;
-      return nullptr;
+      NOTREACHED_NORETURN()
+          << "Invalid touch handle bound type: " << bound_type;
   }
 }
 
@@ -141,8 +141,7 @@
       widget_left = bound.edge_start_rounded().x() - widget_width / 2;
       break;
     default:
-      NOTREACHED() << "Undefined bound type.";
-      break;
+      NOTREACHED_NORETURN() << "Undefined bound type.";
   }
   return gfx::Rect(widget_left, bound.edge_start_rounded().y(), widget_width,
                    widget_height);
diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index 77d3b78..cf570121 100644
--- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -668,13 +668,13 @@
 
  private:
   // Overridden from ui::TouchEditable.
-  void MoveCaret(const gfx::Point& position) override { NOTREACHED(); }
+  void MoveCaret(const gfx::Point& position) override { NOTREACHED_NORETURN(); }
   void MoveRangeSelectionExtent(const gfx::Point& extent) override {
-    NOTREACHED();
+    NOTREACHED_NORETURN();
   }
   void SelectBetweenCoordinates(const gfx::Point& base,
                                 const gfx::Point& extent) override {
-    NOTREACHED();
+    NOTREACHED_NORETURN();
   }
   void GetSelectionEndPoints(gfx::SelectionBound* anchor,
                              gfx::SelectionBound* focus) override {
@@ -695,20 +695,20 @@
       screen_position_client->ConvertPointFromScreen(window_, point);
   }
   bool DrawsHandles() override { return false; }
-  void OpenContextMenu(const gfx::Point& anchor) override { NOTREACHED(); }
-  void DestroyTouchSelection() override { NOTREACHED(); }
+  void OpenContextMenu(const gfx::Point& anchor) override {
+    NOTREACHED_NORETURN();
+  }
+  void DestroyTouchSelection() override { NOTREACHED_NORETURN(); }
 
   // Overridden from ui::SimpleMenuModel::Delegate.
   bool IsCommandIdChecked(int command_id) const override {
-    NOTREACHED();
-    return false;
+    NOTREACHED_NORETURN();
   }
   bool IsCommandIdEnabled(int command_id) const override {
-    NOTREACHED();
-    return false;
+    NOTREACHED_NORETURN();
   }
   void ExecuteCommand(int command_id, int event_flags) override {
-    NOTREACHED();
+    NOTREACHED_NORETURN();
   }
 
   raw_ptr<aura::Window> window_;
diff --git a/ui/views/view.cc b/ui/views/view.cc
index fa4bcc83c..332e15a 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -1532,7 +1532,7 @@
 void View::OnScrollEvent(ui::ScrollEvent* event) {}
 
 void View::OnTouchEvent(ui::TouchEvent* event) {
-  NOTREACHED() << "Views should not receive touch events.";
+  NOTREACHED_NORETURN() << "Views should not receive touch events.";
 }
 
 void View::OnGestureEvent(ui::GestureEvent* event) {}
@@ -1616,16 +1616,10 @@
 }
 
 void View::RemoveAccelerator(const ui::Accelerator& accelerator) {
-  if (!accelerators_) {
-    NOTREACHED() << "Removing non-existing accelerator";
-    return;
-  }
+  CHECK(accelerators_) << "Removing non-existent accelerator";
 
   auto i(base::ranges::find(*accelerators_, accelerator));
-  if (i == accelerators_->end()) {
-    NOTREACHED() << "Removing non-existing accelerator";
-    return;
-  }
+  CHECK(i != accelerators_->end()) << "Removing non-existent accelerator";
 
   auto index = static_cast<size_t>(i - accelerators_->begin());
   accelerators_->erase(i);
@@ -3204,13 +3198,7 @@
   }
 
   accelerator_focus_manager_ = GetFocusManager();
-  if (!accelerator_focus_manager_) {
-    // Some crash reports seem to show that we may get cases where we have no
-    // focus manager (see bug #1291225).  This should never be the case, just
-    // making sure we don't crash.
-    NOTREACHED();
-    return;
-  }
+  CHECK(accelerator_focus_manager_);
   for (std::vector<ui::Accelerator>::const_iterator i =
            accelerators_->begin() +
            static_cast<ptrdiff_t>(registered_accelerator_count_);
diff --git a/ui/views/view_targeter.cc b/ui/views/view_targeter.cc
index 6f0589a..f92a1bb 100644
--- a/ui/views/view_targeter.cc
+++ b/ui/views/view_targeter.cc
@@ -29,7 +29,7 @@
 
 ui::EventTarget* ViewTargeter::FindTargetForEvent(ui::EventTarget* root,
                                                   ui::Event* event) {
-  View* view = static_cast<View*>(root);
+  View* const view = static_cast<View*>(root);
 
   if (event->IsKeyEvent())
     return FindTargetForKeyEvent(view, *event->AsKeyEvent());
@@ -37,15 +37,13 @@
   if (event->IsScrollEvent())
     return FindTargetForScrollEvent(view, *event->AsScrollEvent());
 
-  if (event->IsGestureEvent()) {
-    ui::GestureEvent* gesture = event->AsGestureEvent();
-    View* gesture_target = FindTargetForGestureEvent(view, *gesture);
-    root->ConvertEventToTarget(gesture_target, gesture);
-    return gesture_target;
-  }
+  CHECK(event->IsGestureEvent())
+      << "ViewTargeter does not yet support this event type.";
 
-  NOTREACHED() << "ViewTargeter does not yet support this event type.";
-  return nullptr;
+  ui::GestureEvent* gesture = event->AsGestureEvent();
+  View* gesture_target = FindTargetForGestureEvent(view, *gesture);
+  root->ConvertEventToTarget(gesture_target, gesture);
+  return gesture_target;
 }
 
 ui::EventTarget* ViewTargeter::FindNextBestTarget(
@@ -84,15 +82,13 @@
   //                   a RootViewTargeter). Provide a default implementation
   //                   here if we need to be able to perform gesture targeting
   //                   starting at an arbitrary node in a Views tree.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 ui::EventTarget* ViewTargeter::FindNextBestTargetForGestureEvent(
     ui::EventTarget* previous_target,
     const ui::GestureEvent& gesture) {
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index f875d90..612299b4 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -94,7 +94,7 @@
 
 void DesktopNativeCursorManager::InitCursorSizeObserver(
     wm::NativeCursorManagerDelegate* delegate) {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 113fcb9..1b890d3b 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -105,8 +105,7 @@
     default:
       return ui::PlatformWindowType::kPopup;
   }
-  NOTREACHED();
-  return ui::PlatformWindowType::kPopup;
+  NOTREACHED_NORETURN();
 }
 
 ui::PlatformWindowShadowType GetPlatformWindowShadowType(
@@ -119,8 +118,7 @@
     case Widget::InitParams::ShadowType::kDrop:
       return ui::PlatformWindowShadowType::kDrop;
   }
-  NOTREACHED();
-  return ui::PlatformWindowShadowType::kNone;
+  NOTREACHED_NORETURN();
 }
 
 ui::PlatformWindowInitProperties ConvertWidgetInitParamsToInitProperties(
@@ -473,8 +471,7 @@
 
 bool DesktopWindowTreeHostPlatform::IsStackedAbove(aura::Window* window) {
   // TODO(https://crbug.com/1363218) Implement Window layer check
-  NOTREACHED();
-  return false;
+  NOTREACHED_NORETURN();
 }
 
 void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
@@ -956,13 +953,14 @@
     const gfx::Point& screen_in_pixels) const {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   // lacros should not use this.
-  NOTREACHED();
-#endif
+  NOTREACHED_NORETURN();
+#else
   // TODO(crbug.com/1318279): DIP should use gfx::PointF. Fix this as
   // a part of cleanup work(crbug.com/1318279).
   gfx::Point local_dip(screen_in_pixels);
   ConvertScreenInPixelsToDIP(&local_dip);
   return gfx::PointF(local_dip);
+#endif
 }
 
 void DesktopWindowTreeHostPlatform::OnWorkspaceChanged() {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc
index 3699d8b..719438a 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_impl_interactive_uitest.cc
@@ -296,14 +296,12 @@
                                      const gfx::Point& click_location,
                                      int flags) {
     int flag = 0;
-    if (flags & ui::EF_LEFT_MOUSE_BUTTON)
+    if (flags & ui::EF_LEFT_MOUSE_BUTTON) {
       flag = ui::EF_LEFT_MOUSE_BUTTON;
-    else if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
-      flag = ui::EF_RIGHT_MOUSE_BUTTON;
-
-    if (!flag) {
-      NOTREACHED()
+    } else {
+      CHECK(flags & ui::EF_RIGHT_MOUSE_BUTTON)
           << "Other mouse clicks are not supported yet. Add the new one.";
+      flag = ui::EF_RIGHT_MOUSE_BUTTON;
     }
     return new ui::MouseEvent(event_type, click_location, click_location,
                               base::TimeTicks::Now(), flags, flag);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 6491f6b..3c51cfee 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -65,8 +65,7 @@
           Wait();
         break;
       default:
-        NOTREACHED() << "unknown value";
-        break;
+        NOTREACHED_NORETURN() << "unknown value";
     }
   }
 
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 964f1c3..d1a934d2 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -536,15 +536,14 @@
     return;
   }
 
-  if (ns_window_host_->application_host() == sibling_host->application_host()) {
-    // Check if |native_view|'s NativeWidgetMacNSWindowHost corresponds to the
-    // same process as |this|.
-    GetNSWindowMojo()->StackAbove(sibling_host->bridged_native_widget_id());
-    return;
-  }
-
-  NOTREACHED() << "|native_view|'s NativeWidgetMacNSWindowHost isn't same "
-                  "process |this|";
+  CHECK_EQ(ns_window_host_->application_host(),
+           sibling_host->application_host())
+      << "|native_view|'s NativeWidgetMacNSWindowHost isn't same "
+         "process |this|";
+  // Check if |native_view|'s NativeWidgetMacNSWindowHost corresponds to the
+  // same process as |this|.
+  GetNSWindowMojo()->StackAbove(sibling_host->bridged_native_widget_id());
+  return;
 }
 
 void NativeWidgetMac::StackAtTop() {
@@ -603,8 +602,7 @@
       NOTIMPLEMENTED();
       break;
     case ui::SHOW_STATE_END:
-      NOTREACHED();
-      break;
+      NOTREACHED_NORETURN();
   }
   auto window_state = WindowVisibilityState::kShowAndActivateWindow;
   if (show_state == ui::SHOW_STATE_INACTIVE) {
@@ -1126,11 +1124,8 @@
                                              gfx::NativeView new_parent) {
   DCHECK_NE(child, new_parent);
   DCHECK([new_parent.GetNativeNSView() window]);
-  if (!new_parent ||
-      [child.GetNativeNSView() superview] == new_parent.GetNativeNSView()) {
-    NOTREACHED();
-    return;
-  }
+  CHECK(new_parent);
+  CHECK_NE([child.GetNativeNSView() superview], new_parent.GetNativeNSView());
 
   NativeWidgetMacNSWindowHost* child_window_host =
       NativeWidgetMacNSWindowHost::GetFromNativeView(child);
diff --git a/ui/views/widget/sublevel_manager_mac_unittest.mm b/ui/views/widget/sublevel_manager_mac_unittest.mm
index 2e34c2f..1734d2a4 100644
--- a/ui/views/widget/sublevel_manager_mac_unittest.mm
+++ b/ui/views/widget/sublevel_manager_mac_unittest.mm
@@ -75,7 +75,7 @@
         test_name += "Activatable";
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
     return test_name;
   }
diff --git a/ui/views/widget/sublevel_manager_unittest.cc b/ui/views/widget/sublevel_manager_unittest.cc
index 41e1c5d..bff3d20e 100644
--- a/ui/views/widget/sublevel_manager_unittest.cc
+++ b/ui/views/widget/sublevel_manager_unittest.cc
@@ -97,7 +97,7 @@
         test_name += "Activatable";
         break;
       default:
-        NOTREACHED();
+        NOTREACHED_NORETURN();
     }
     return test_name;
   }
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 13d32438..1e80a2a 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -1926,15 +1926,13 @@
 FocusTraversable* Widget::GetFocusTraversableParent() {
   // We are a proxy to the root view, so we should be bypassed when traversing
   // up and as a result this should not be called.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 View* Widget::GetFocusTraversableParentView() {
   // We are a proxy to the root view, so we should be bypassed when traversing
   // up and as a result this should not be called.
-  NOTREACHED();
-  return nullptr;
+  NOTREACHED_NORETURN();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/widget/widget_aura_utils.cc b/ui/views/widget/widget_aura_utils.cc
index 365c8ef..dfeee980 100644
--- a/ui/views/widget/widget_aura_utils.cc
+++ b/ui/views/widget/widget_aura_utils.cc
@@ -25,8 +25,7 @@
     case Widget::InitParams::TYPE_TOOLTIP:
       return aura::client::WINDOW_TYPE_TOOLTIP;
     default:
-      NOTREACHED() << "Unhandled widget type " << type;
-      return aura::client::WINDOW_TYPE_UNKNOWN;
+      NOTREACHED_NORETURN() << "Unhandled widget type " << type;
   }
 }
 
diff --git a/ui/views/widget/widget_hwnd_utils.cc b/ui/views/widget/widget_hwnd_utils.cc
index b162f426..3b9b00b7 100644
--- a/ui/views/widget/widget_hwnd_utils.cc
+++ b/ui/views/widget/widget_hwnd_utils.cc
@@ -114,7 +114,7 @@
       *style |= WS_POPUP;
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
 }
 
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 24cc2ff3..f25b11d 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -278,8 +278,7 @@
     case WMSZ_BOTTOMRIGHT:
       return gfx::ResizeEdge::kBottomRight;
     default:
-      NOTREACHED();
-      return gfx::ResizeEdge::kBottomRight;
+      NOTREACHED_NORETURN();
   }
 }
 
@@ -3437,12 +3436,12 @@
   // window, so use the weak ptr to check if destruction occurred or not.
   base::WeakPtr<HWNDMessageHandler> ref(msg_handler_weak_factory_.GetWeakPtr());
   if (event) {
-    if (event->IsTouchEvent())
+    if (event->IsTouchEvent()) {
       delegate_->HandleTouchEvent(event->AsTouchEvent());
-    else if (event->IsMouseEvent())
+    } else {
+      CHECK(event->IsMouseEvent());
       delegate_->HandleMouseEvent(event->AsMouseEvent());
-    else
-      NOTREACHED();
+    }
 
     last_touch_or_pen_message_time_ = ::GetMessageTime();
     is_pen_active_in_client_area_ = true;
diff --git a/ui/views/win/pen_event_processor.cc b/ui/views/win/pen_event_processor.cc
index 7d6ec155..dd0fa6b 100644
--- a/ui/views/win/pen_event_processor.cc
+++ b/ui/views/win/pen_event_processor.cc
@@ -158,7 +158,7 @@
       id_generator_->ReleaseNumber(pointer_id);
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
   std::unique_ptr<ui::Event> event = std::make_unique<ui::MouseEvent>(
       event_type, point, point, ui::EventTimeForNow(),
@@ -196,7 +196,7 @@
       event_type = ui::ET_TOUCH_MOVED;
       break;
     default:
-      NOTREACHED();
+      NOTREACHED_NORETURN();
   }
 
   const base::TimeTicks event_time = ui::EventTimeForNow();
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index fca150024..dfd41ce 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -135,13 +135,10 @@
 
   if (button == ui::DIALOG_BUTTON_OK)
     return l10n_util::GetStringUTF16(IDS_APP_OK);
-  if (button == ui::DIALOG_BUTTON_CANCEL) {
-    if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
-      return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
-    return l10n_util::GetStringUTF16(IDS_APP_CLOSE);
-  }
-  NOTREACHED();
-  return std::u16string();
+  CHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL);
+  return GetDialogButtons() & ui::DIALOG_BUTTON_OK
+             ? l10n_util::GetStringUTF16(IDS_APP_CANCEL)
+             : l10n_util::GetStringUTF16(IDS_APP_CLOSE);
 }
 
 bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const {
@@ -180,11 +177,8 @@
   if (default_button == ui::DIALOG_BUTTON_NONE)
     return nullptr;
 
-  if ((default_button & GetDialogButtons()) == 0) {
-    // The default button is a button we don't have.
-    NOTREACHED();
-    return nullptr;
-  }
+  // The default button should be a button we have.
+  CHECK(default_button & GetDialogButtons());
 
   if (default_button & ui::DIALOG_BUTTON_OK)
     return dcv->ok_button();
diff --git a/ui/views/window/non_client_view.cc b/ui/views/window/non_client_view.cc
index ac55b96..5f39961 100644
--- a/ui/views/window/non_client_view.cc
+++ b/ui/views/window/non_client_view.cc
@@ -52,25 +52,26 @@
 
   int component;
   if (point_in_top) {
-    if (point_in_left)
+    if (point_in_left) {
       component = HTTOPLEFT;
-    else if (point_in_right)
+    } else if (point_in_right) {
       component = HTTOPRIGHT;
-    else
+    } else {
       component = HTTOP;
+    }
   } else if (point_in_bottom) {
-    if (point_in_left)
+    if (point_in_left) {
       component = HTBOTTOMLEFT;
-    else if (point_in_right)
+    } else if (point_in_right) {
       component = HTBOTTOMRIGHT;
-    else
+    } else {
       component = HTBOTTOM;
+    }
   } else if (point_in_left) {
     component = HTLEFT;
-  } else if (point_in_right) {
-    component = HTRIGHT;
   } else {
-    NOTREACHED();
+    CHECK(point_in_right);
+    component = HTRIGHT;
   }
 
   // If the window can't be resized, there are no resize boundaries, just