diff --git a/AUTHORS b/AUTHORS
index 4e44a11..55dc38c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -367,6 +367,7 @@
 Diego Fernández Santos <agujaydedal@gmail.com>
 Diego Ferreiro Val <elfogris@gmail.com>
 Dillon Sellars <dill.sellars@gmail.com>
+Dingming Liu <liudingming@bytedance.com>
 Divya Bansal <divya.bansal@samsung.com>
 Dmitry Shachnev <mitya57@gmail.com>
 Dmitry Sokolov <dimanne@gmail.com>
diff --git a/DEPS b/DEPS
index 5370a3d..eb1d2ea7 100644
--- a/DEPS
+++ b/DEPS
@@ -276,11 +276,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '574ed45332eea47966af2212641b55e7aa9d7030',
+  'src_internal_revision': '98f86ef6116bb6582bf385d8ffd1efb255f50c5c',
   # 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': 'a15d02f7757e95b700aea3f53e7ee8c3305bae1c',
+  'skia_revision': 'a38c4ae0287a1d6d4a57db85b8b52c0d43965deb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -288,7 +288,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2849e8f11e55ee14df94af8d471e9149448c8f4a',
+  'angle_revision': '81a41e4f10f960a290d89147c7a152fcd48f09a4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -300,7 +300,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'be21ef7012f0812bb1c0c8fc226979fa6c301e8d',
+  'boringssl_revision': 'cf6dc5d38385e4ff6faf9bf0883a67c2f511076b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -348,7 +348,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '415e0f1c10d3de8ba78aff15ca6dfe71f0b04d9e',
+  'catapult_revision': '9b526439504cb5f2465696b807faa8c5459bdd63',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
@@ -404,7 +404,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ink
   # and whatever else without interference from each other.
-  'ink_revision': 'd21aa587baa20f9db3dba2007e314f1c29351d10',
+  'ink_revision': 'e5673a4ff2d82f29b22f7bec114161cbc1ff8cf8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ink_stroke_modeler
   # and whatever else without interference from each other.
@@ -496,11 +496,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    'ca233e8056f91e3f1b2cb3d17efa88b3ae6fb15d',
+  'llvm_libc_revision':    '2222607a3ea3d5f65338d3b36a4cc5fb563169ab',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '175bf00303d0747baa158072cf7a2755ab1fbe88',
+  'libcxx_revision':       'ec4ac17a44a46b162c28d38f313f157f76236a6c',
 
   # GN CIPD package version.
   'gn_version': 'git_revision:c97a86a72105f3328a540f5a5ab17d11989ab7dd',
@@ -1273,7 +1273,7 @@
   },
 
   'src/chrome/test/data/autofill/captured_sites/artifacts': {
-    'url': Var('chrome_git') + '/chrome/test/captured_sites/autofill.git' + '@' + '4fe29ba42dfd45c824c4623ecb5335bd82d6bad0',
+    'url': Var('chrome_git') + '/chrome/test/captured_sites/autofill.git' + '@' + '8c66a34eccf070d66903db5db487bc1de597e7c6',
     'condition': 'checkout_chromium_autofill_test_dependencies',
   },
 
@@ -1304,12 +1304,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '9a87c3392f476429eccefd7ed2a1689dfc378c9d',
+    'c21490b893c1a3efa293da12c73480149478ce73',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '7026ffa285a6bf16008b0bf927d0bf63985e89ae',
+    'url': Var('chromium_git') + '/website.git' + '@' + '1229734e08d74bf1d5ce69051ed70d2b392d356c',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -2163,7 +2163,7 @@
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '26d9f667170dc75e8d759a997bb61c64dec42dda',
 
   'src/third_party/libwebp/src':
-    Var('chromium_git') + '/webm/libwebp.git' + '@' +  '845d5476a866141ba35ac133f856fa62f0b7445f',
+    Var('chromium_git') + '/webm/libwebp.git' + '@' +  '2af6c034ac871c967e04c8c9f8bf2dbc2e271b18',
 
   'src/third_party/libyuv':
     Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '86b09b24506650f226e5f270275a01f8e7498f62',
@@ -4431,7 +4431,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'be08527a88307c18e6c8e1d60d4edad905ce57da',
+        'ad25fb362531d62c3c06cbf57e18b3ce5a016473',
       'condition': 'checkout_src_internal',
   },
 
@@ -4497,7 +4497,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'ed7bda3f92a8d250ee6463bff9d730d01cf23bda',
+        '156f0000208f3f45680ec110953276b784deec94',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 6e12601..f0b743a 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -1015,6 +1015,9 @@
         Flag.baseFeature(
                 "SelectParserRelaxation",
                 "Enables new HTML parser behavior for the <select> element."),
+        Flag.baseFeature(
+                 "CSSReadingFlow",
+                 "Enables new CSS reading-flow property for focus navigation in visual order."),
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
     };
diff --git a/ash/accelerators/accelerator_alias_converter.cc b/ash/accelerators/accelerator_alias_converter.cc
index da6e1a24..98e2cde 100644
--- a/ash/accelerators/accelerator_alias_converter.cc
+++ b/ash/accelerators/accelerator_alias_converter.cc
@@ -26,6 +26,7 @@
 #include "ui/events/ash/keyboard_layout_util.h"
 #include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
 #include "ui/events/ash/mojom/six_pack_shortcut_modifier.mojom-shared.h"
+#include "ui/events/ash/top_row_action_keys.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/keyboard_device.h"
@@ -141,6 +142,7 @@
     case ui::TopRowActionKey::kPrivacyScreenToggle:
     case ui::TopRowActionKey::kAllApplications:
     case ui::TopRowActionKey::kAccessibility:
+    case ui::TopRowActionKey::kDoNotDisturb:
       return false;
     case ui::TopRowActionKey::kDictation:
     case ui::TopRowActionKey::kFullscreen:
diff --git a/ash/accelerators/accelerator_commands.cc b/ash/accelerators/accelerator_commands.cc
index 8aa2d62..55739ec 100644
--- a/ash/accelerators/accelerator_commands.cc
+++ b/ash/accelerators/accelerator_commands.cc
@@ -117,6 +117,7 @@
 #include "ui/display/screen.h"
 #include "ui/display/util/display_util.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/message_center/message_center.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/window_animations.h"
@@ -1448,6 +1449,14 @@
       is_plain_text_paste);
 }
 
+void ToggleDoNotDisturb() {
+  message_center::MessageCenter* message_center =
+      message_center::MessageCenter::Get();
+  CHECK(message_center);
+  const bool is_quiet_mode = message_center->IsQuietMode();
+  message_center->SetQuietMode(!is_quiet_mode);
+}
+
 void ToggleQuickInsert(base::TimeTicks accelerator_timestamp) {
   const bool outside_user_session =
       !Shell::Get()->session_controller()->IsActiveUserSessionStarted();
diff --git a/ash/accelerators/accelerator_commands.h b/ash/accelerators/accelerator_commands.h
index 0502760..dab1e74 100644
--- a/ash/accelerators/accelerator_commands.h
+++ b/ash/accelerators/accelerator_commands.h
@@ -324,6 +324,9 @@
 // Toggles the clipboard history.
 ASH_EXPORT void ToggleClipboardHistory(bool is_plain_text_paste);
 
+// Toggles do not disturb functionality.
+ASH_EXPORT void ToggleDoNotDisturb();
+
 // Toggles Quick Insert.
 // `accelerator_timestamp` is the timestamp associated with the accelerator that
 // triggered Quick Insert.
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 27c0158..ca477f09 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -977,6 +977,8 @@
           *capslock_state_machine_, notification_controller_.get());
     case AcceleratorAction::kToggleClipboardHistory:
       return true;
+    case AcceleratorAction::kToggleDoNotDisturb:
+      return features::IsDoNotDisturbShortcutEnabled();
     case AcceleratorAction::kEnableSelectToSpeak:
       return true;
     case AcceleratorAction::kEnableOrToggleDictation:
@@ -1549,6 +1551,9 @@
     case AcceleratorAction::kToggleClipboardHistory:
       accelerators::ToggleClipboardHistory(/*is_plain_text_paste=*/false);
       break;
+    case AcceleratorAction::kToggleDoNotDisturb:
+      accelerators::ToggleDoNotDisturb();
+      break;
     case AcceleratorAction::kEnableSelectToSpeak:
       accelerators::EnableSelectToSpeak();
       break;
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 4972fe9..27c529c 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1608,11 +1608,6 @@
 }
 
 TEST_F(AcceleratorControllerTest, ToggleMultitaskMenu) {
-  // Accelerators behind a flag should also be accompanied by the
-  // `kShortcutCustomization` to support dynamic accelerator registration.
-  base::test::ScopedFeatureList scoped_feature_list(
-      ::features::kShortcutCustomization);
-
   // Simulate fake user login to ensure pref registration is done correctly.
   SimulateUserLogin("fakeuser");
   // Enabling `kShortcutCustomization` will start letting
@@ -2637,6 +2632,20 @@
   EXPECT_EQ(1, client.next_ime_count_);
 }
 
+TEST_F(AcceleratorControllerTest, ToggleDoNotDisturbKey) {
+  base::test::ScopedFeatureList feature_list(features::kDoNotDisturbShortcut);
+
+  ASSERT_FALSE(message_center()->IsQuietMode());
+
+  // Toggle do not disturb on.
+  accelerators::ToggleDoNotDisturb();
+  ASSERT_TRUE(message_center()->IsQuietMode());
+
+  // Toggle do not disturb off.
+  accelerators::ToggleDoNotDisturb();
+  ASSERT_FALSE(message_center()->IsQuietMode());
+}
+
 class SystemShortcutBehaviorTest : public AcceleratorControllerTest {
   void SetUp() override {
     AcceleratorControllerTest::SetUp();
@@ -2874,9 +2883,6 @@
   };
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kImprovedKeyboardShortcuts);
-
     // Setup our own |InputMethodManager| to test that the accelerator
     // controller respects ArePositionalShortcutsUsedByCurrentInputMethod value
     // from the |InputMethodManager|.
@@ -2900,9 +2906,6 @@
  protected:
   raw_ptr<TestInputMethodManager, DanglingUntriaged> input_method_manager_ =
       nullptr;  // Not owned.
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(AcceleratorControllerImprovedKeyboardShortcutsTest, InputMethodChanged) {
@@ -2941,9 +2944,6 @@
   };
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kImprovedKeyboardShortcuts);
-
     // Setup the mock input method to capture the calls to
     // |CancelCompositionAfterAccelerator|. Ownersship is passed to
     // ui::SetUpInputMethodForTesting().
@@ -2955,9 +2955,6 @@
  protected:
   raw_ptr<AcceleratorMockInputMethod, DanglingUntriaged> mock_input_ =
       nullptr;  // Not owned.
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // In some layouts positional accelerators can be on dead/compose keys. To
@@ -2982,37 +2979,6 @@
   EXPECT_EQ(1u, mock_input_->cancel_composition_call_count);
 }
 
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-class AcceleratorControllerDeprecatedTest : public AcceleratorControllerTest {
- public:
-  AcceleratorControllerDeprecatedTest() = default;
-  ~AcceleratorControllerDeprecatedTest() override = default;
-
-  void SetUp() override {
-    scoped_feature_list_.InitAndDisableFeature(
-        ::features::kImprovedKeyboardShortcuts);
-    AcceleratorControllerTest::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-TEST_F(AcceleratorControllerDeprecatedTest, DeskShortcuts_Old) {
-  // The shortcuts are Search+Shift+[MINUS|PLUS], but due to event
-  // rewriting they became Shift+[F11|F12]. So only the rewritten shortcut
-  // works but the "real" shortcut doesn't.
-  EXPECT_TRUE(controller_->IsRegistered(
-      ui::Accelerator(ui::VKEY_F12, ui::EF_SHIFT_DOWN)));
-  EXPECT_TRUE(controller_->IsRegistered(
-      ui::Accelerator(ui::VKEY_F11, ui::EF_SHIFT_DOWN)));
-  EXPECT_FALSE(controller_->IsRegistered(ui::Accelerator(
-      ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN)));
-  EXPECT_FALSE(controller_->IsRegistered(ui::Accelerator(
-      ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN)));
-}
-
 // defines a class to test the behavior of deprecated accelerators.
 class DeprecatedAcceleratorTester : public AcceleratorControllerTest {
  public:
@@ -3082,9 +3048,6 @@
 }
 
 TEST_F(DeprecatedAcceleratorTester, NoNotificationIfReplacementMissing) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(::features::kShortcutCustomization);
-
   // Remove the replacements for all deprecated accelerators.
   Shell::Get()->ash_accelerator_configuration()->RemoveAccelerator(
       AcceleratorAction::kShowShortcutViewer,
@@ -3192,9 +3155,6 @@
     // Create user session and simulate its login.
     SimulateUserLogin(kUserEmail);
   }
-
- protected:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 // TODO (afakhry): Remove this class after refactoring MagnificationManager.
diff --git a/ash/accelerators/accelerator_lookup_unittest.cc b/ash/accelerators/accelerator_lookup_unittest.cc
index 8334ac00..ecd2f26 100644
--- a/ash/accelerators/accelerator_lookup_unittest.cc
+++ b/ash/accelerators/accelerator_lookup_unittest.cc
@@ -13,10 +13,8 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/memory/raw_ptr.h"
-#include "base/test/scoped_feature_list.h"
 #include "device/udev_linux/fake_udev_loader.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/devices/device_data_manager_test_api.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/keyboard_device.h"
@@ -98,8 +96,6 @@
   ~AcceleratorLookupTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kShortcutCustomization);
     AshTestBase::SetUp();
     config_ = Shell::Get()->ash_accelerator_configuration();
     accelerator_lookup_ = Shell::Get()->accelerator_lookup();
@@ -112,7 +108,6 @@
   }
 
  protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
   raw_ptr<AshAcceleratorConfiguration> config_;
   raw_ptr<AcceleratorLookup> accelerator_lookup_;
 };
diff --git a/ash/accelerators/accelerator_prefs.cc b/ash/accelerators/accelerator_prefs.cc
index f1838a2b..7194efb3 100644
--- a/ash/accelerators/accelerator_prefs.cc
+++ b/ash/accelerators/accelerator_prefs.cc
@@ -101,9 +101,7 @@
   if (IsUserEnterpriseManaged() && IsCustomizationPolicySet()) {
     return IsCustomizationAllowedByPolicy();
   }
-
-  // If user is not managed or the policy is unset, check the flag.
-  return ::features::IsShortcutCustomizationEnabled();
+  return true;
 }
 
 }  // namespace ash
diff --git a/ash/accelerators/accelerator_prefs_unittest.cc b/ash/accelerators/accelerator_prefs_unittest.cc
index 937f1785..ac8041ba 100644
--- a/ash/accelerators/accelerator_prefs_unittest.cc
+++ b/ash/accelerators/accelerator_prefs_unittest.cc
@@ -6,7 +6,6 @@
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "base/test/scoped_feature_list.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,13 +32,8 @@
   ~AcceleratorPrefsTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kShortcutCustomization);
     AshTestBase::SetUp();
   }
-
- protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(AcceleratorPrefsTest, PrefsAreRegisitered) {
diff --git a/ash/accelerators/ash_accelerator_configuration.cc b/ash/accelerators/ash_accelerator_configuration.cc
index 6afe8a8..24040452 100644
--- a/ash/accelerators/ash_accelerator_configuration.cc
+++ b/ash/accelerators/ash_accelerator_configuration.cc
@@ -146,6 +146,11 @@
                           ash::kTilingWindowResizeAcceleratorData);
   }
 
+  if (ash::features::IsDoNotDisturbShortcutEnabled()) {
+    AppendAcceleratorData(accelerators,
+                          ash::kToggleDoNotDisturbAcceleratorData);
+  }
+
   // Debug accelerators.
   if (ash::debug::DebugAcceleratorsEnabled()) {
     AppendAcceleratorData(accelerators, ash::kDebugAcceleratorData);
diff --git a/ash/accelerators/ash_accelerator_configuration_unittest.cc b/ash/accelerators/ash_accelerator_configuration_unittest.cc
index a3e1f7c..f79917a 100644
--- a/ash/accelerators/ash_accelerator_configuration_unittest.cc
+++ b/ash/accelerators/ash_accelerator_configuration_unittest.cc
@@ -160,8 +160,6 @@
   ~AshAcceleratorConfigurationTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kShortcutCustomization);
     AshTestBase::SetUp();
     config_ = std::make_unique<AshAcceleratorConfiguration>();
     config_->AddObserver(&observer_);
@@ -2595,8 +2593,7 @@
 TEST_F(AshAcceleratorConfigurationTest, PrefsResetWithFlag) {
   scoped_feature_list_.Reset();
   scoped_feature_list_.InitWithFeatures(
-      /*enabled_features=*/{::features::kShortcutCustomization,
-                            features::kResetShortcutCustomizations},
+      /*enabled_features=*/{features::kResetShortcutCustomizations},
       /*disabled_features=*/{});
   SimulateNewUserFirstLogin(kFakeUserEmail);
   const AcceleratorData test_data[] = {
diff --git a/ash/accelerators/keyboard_code_util.cc b/ash/accelerators/keyboard_code_util.cc
index 5b5751fb..3d6e4ad3 100644
--- a/ash/accelerators/keyboard_code_util.cc
+++ b/ash/accelerators/keyboard_code_util.cc
@@ -143,6 +143,8 @@
       return &ash::kKsvSnapshotIcon;
     case ui::VKEY_QUICK_INSERT:
       return &ash::kQuickInsertIcon;
+    case ui::VKEY_DO_NOT_DISTURB:
+      return &ash::kKsDoNotDisturbIcon;
     default:
       return nullptr;
   }
diff --git a/ash/accelerators/shortcut_input_handler.cc b/ash/accelerators/shortcut_input_handler.cc
index 22995a8a..d7bc4fe 100644
--- a/ash/accelerators/shortcut_input_handler.cc
+++ b/ash/accelerators/shortcut_input_handler.cc
@@ -63,10 +63,9 @@
 
 void ShortcutInputHandler::Initialize() {
   CHECK(Shell::Get());
-  if (!features::IsPeripheralCustomizationEnabled() &&
-      !::features::IsShortcutCustomizationEnabled()) {
+  if (!features::IsPeripheralCustomizationEnabled()) {
     LOG(ERROR) << "ShortcutInputHandler can only be initialized if "
-               << "shortcut or peripherals customization flags are enabled.";
+               << "peripherals customization flag is enabled.";
     return;
   }
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index d046bd0..e4c2899c 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -4235,6 +4235,9 @@
       <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_OPEN_ACCESSIBILITY_SETTINGS" desc="Label for accelerator action - Open accessibility quick settings.">
         Open accessibility options
       </message>
+      <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_DO_NOT_DISTURB" desc="Label for accelerator action - Turn on/off do not disturb.">
+        Turn on/off do not disturb
+      </message>
 
       <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_FOCUS_CAMERA_PREVIEW" translateable="false" desc="Label for accelerator action - Focus on the camera preview.">
         Focus on the camera preview
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_DO_NOT_DISTURB.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_DO_NOT_DISTURB.png.sha1
new file mode 100644
index 0000000..35c0cc1
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_DO_NOT_DISTURB.png.sha1
@@ -0,0 +1 @@
+f33c945aae38123383e4c27187c8dd7eed74165d
\ No newline at end of file
diff --git a/ash/clipboard/clipboard_history_controller_unittest.cc b/ash/clipboard/clipboard_history_controller_unittest.cc
index 0aba383c..c8471da 100644
--- a/ash/clipboard/clipboard_history_controller_unittest.cc
+++ b/ash/clipboard/clipboard_history_controller_unittest.cc
@@ -338,16 +338,9 @@
                     {user_manager::UserType::kChild, true},
                     {user_manager::UserType::kWebKioskApp, false}};
 
-  UserSession session;
-  session.session_id = 1u;
-  session.user_info.account_id = AccountId::FromUserEmail("user1@test.com");
-  session.user_info.display_name = "User 1";
-  session.user_info.display_email = "user1@test.com";
-
   for (const auto& test_case : kTestCases) {
-    // Switch to the target user mode.
-    session.user_info.type = test_case.user_type;
-    Shell::Get()->session_controller()->UpdateUserSession(session);
+    ClearLogin();
+    SimulateUserLogin("user1@test.com", test_case.user_type);
 
     // Write a new item into the clipboard buffer.
     {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index c30ea437..bcbda05 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -527,6 +527,11 @@
              "DisplayPerformanceMode",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enable the do not disturb shortcut.
+BASE_FEATURE(kDoNotDisturbShortcut,
+             "DoNotDisturbShortcut",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Adds a desk button to the shelf that the user can use to navigate between
 // desks.
 BASE_FEATURE(kDeskButton, "DeskButton", base::FEATURE_ENABLED_BY_DEFAULT);
@@ -3485,6 +3490,10 @@
   return base::FeatureList::IsEnabled(kDisplayAlignAssist);
 }
 
+bool IsDoNotDisturbShortcutEnabled() {
+  return base::FeatureList::IsEnabled(kDoNotDisturbShortcut);
+}
+
 bool IsDriveFsMirroringEnabled() {
   return base::FeatureList::IsEnabled(kDriveFsMirroring);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index c3aac94e..cb88a12 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -198,6 +198,7 @@
 BASE_DECLARE_FEATURE(kDisconnectWiFiOnEthernetConnected);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDisplayAlignAssist);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDisplayPerformanceMode);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDoNotDisturbShortcut);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFs);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kDriveFsMirroring);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -1077,6 +1078,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPeripheralCustomizationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPeripheralsLoggingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDisplayAlignmentAssistanceEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDoNotDisturbShortcutEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDozeModePowerSchedulerEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDriveFsMirroringEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) int GetDriveFsBulkPinningQueueSize();
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index fc336ee..d8603912e 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -127,6 +127,14 @@
     if (!changed_metrics_.try_emplace(display.id(), changed_metrics).second) {
       changed_metrics_[display.id()] |= changed_metrics;
     }
+    // A new display may be re-configured during the configuration by shell.
+    auto iter = std::find_if(added_displays_.begin(), added_displays_.end(),
+                             [display](const display::Display& d) {
+                               return d.id() == display.id();
+                             });
+    if (iter != added_displays_.end()) {
+      *iter = display;
+    }
   }
 
   // display::DisplayManager::Observer:
@@ -3751,15 +3759,23 @@
   EXPECT_FALSE(display_manager()->IsInSoftwareMirrorMode());
 }
 
-TEST_F(DisplayManagerTest, DisplayPrefsAndKioskMode) {
+namespace {
+
+class NoSessionDisplayManagerTest : public DisplayManagerTest {
+ public:
+  NoSessionDisplayManagerTest() { set_start_session(false); }
+  NoSessionDisplayManagerTest(const NoSessionDisplayManagerTest&) = delete;
+  NoSessionDisplayManagerTest& operator=(const NoSessionDisplayManagerTest&) =
+      delete;
+  ~NoSessionDisplayManagerTest() override = default;
+};
+
+}  // namespace
+
+TEST_F(NoSessionDisplayManagerTest, DisplayPrefsAndKioskMode) {
   // Login in as kiosk app.
-  UserSession session;
-  session.session_id = 1u;
-  session.user_info.type = user_manager::UserType::kKioskApp;
-  session.user_info.account_id = AccountId::FromUserEmail("user1@test.com");
-  session.user_info.display_name = "User 1";
-  session.user_info.display_email = "user1@test.com";
-  Shell::Get()->session_controller()->UpdateUserSession(std::move(session));
+  SimulateKioskMode(user_manager::UserType::kKioskApp);
+
   EXPECT_EQ(LoginStatus::KIOSK_APP,
             Shell::Get()->session_controller()->login_status());
   UpdateDisplay("400x300,800x700");
diff --git a/ash/display/resolution_notification_controller_unittest.cc b/ash/display/resolution_notification_controller_unittest.cc
index 75b8b4f..707768b 100644
--- a/ash/display/resolution_notification_controller_unittest.cc
+++ b/ash/display/resolution_notification_controller_unittest.cc
@@ -459,15 +459,24 @@
   EXPECT_EQ(60.0f, mode.refresh_rate());
 }
 
-TEST_P(ResolutionNotificationControllerTest, NoTimeoutInKioskMode) {
+namespace {
+class NoSessionResolutionNotificationControllerTest
+    : public ResolutionNotificationControllerTest {
+ public:
+  NoSessionResolutionNotificationControllerTest() { set_start_session(false); }
+  NoSessionResolutionNotificationControllerTest(
+      const NoSessionResolutionNotificationControllerTest&) = delete;
+  NoSessionResolutionNotificationControllerTest& operator=(
+      const NoSessionResolutionNotificationControllerTest&) = delete;
+  ~NoSessionResolutionNotificationControllerTest() override = default;
+};
+
+}  // namespace
+
+TEST_P(NoSessionResolutionNotificationControllerTest, NoTimeoutInKioskMode) {
   // Login in as kiosk app.
-  UserSession session;
-  session.session_id = 1u;
-  session.user_info.type = user_manager::UserType::kKioskApp;
-  session.user_info.account_id = AccountId::FromUserEmail("user1@test.com");
-  session.user_info.display_name = "User 1";
-  session.user_info.display_email = "user1@test.com";
-  Shell::Get()->session_controller()->UpdateUserSession(std::move(session));
+  SimulateKioskMode(user_manager::UserType::kKioskApp);
+
   EXPECT_EQ(LoginStatus::KIOSK_APP,
             Shell::Get()->session_controller()->login_status());
 
@@ -479,15 +488,10 @@
                                 /*new_is_native=*/false);
 }
 
-TEST_P(ResolutionNotificationControllerTest, NoDialogInKioskMode) {
+TEST_P(NoSessionResolutionNotificationControllerTest, NoDialogInKioskMode) {
   // Login in as kiosk app.
-  UserSession session;
-  session.session_id = 1u;
-  session.user_info.type = user_manager::UserType::kKioskApp;
-  session.user_info.account_id = AccountId::FromUserEmail("user1@test.com");
-  session.user_info.display_name = "User 1";
-  session.user_info.display_email = "user1@test.com";
-  Shell::Get()->session_controller()->UpdateUserSession(std::move(session));
+  SimulateKioskMode(user_manager::UserType::kKioskApp);
+
   EXPECT_EQ(LoginStatus::KIOSK_APP,
             Shell::Get()->session_controller()->login_status());
 
@@ -513,5 +517,8 @@
 INSTANTIATE_TEST_SUITE_P(All,
                          ResolutionNotificationControllerTest,
                          ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(All,
+                         NoSessionResolutionNotificationControllerTest,
+                         ::testing::Bool());
 
 }  // namespace ash
diff --git a/ash/events/event_rewriter_controller_impl.cc b/ash/events/event_rewriter_controller_impl.cc
index a165b05c6..50459d7 100644
--- a/ash/events/event_rewriter_controller_impl.cc
+++ b/ash/events/event_rewriter_controller_impl.cc
@@ -109,14 +109,11 @@
 
   std::unique_ptr<PeripheralCustomizationEventRewriter>
       peripheral_customization_event_rewriter;
-  if (features::IsPeripheralCustomizationEnabled() ||
-      ::features::IsShortcutCustomizationEnabled()) {
-    peripheral_customization_event_rewriter =
-        std::make_unique<PeripheralCustomizationEventRewriter>(
-            Shell::Get()->input_device_settings_controller());
-    peripheral_customization_event_rewriter_ =
-        peripheral_customization_event_rewriter.get();
-  }
+  peripheral_customization_event_rewriter =
+      std::make_unique<PeripheralCustomizationEventRewriter>(
+          Shell::Get()->input_device_settings_controller());
+  peripheral_customization_event_rewriter_ =
+      peripheral_customization_event_rewriter.get();
 
   std::unique_ptr<PrerewrittenEventForwarder> prerewritten_event_forwarder =
       std::make_unique<PrerewrittenEventForwarder>();
@@ -167,10 +164,7 @@
         Shell::Get()->keyboard_capability(),
         ash::input_method::InputMethodManager::Get()->GetImeKeyboard()));
   }
-  if (features::IsPeripheralCustomizationEnabled() ||
-      ::features::IsShortcutCustomizationEnabled()) {
-    AddEventRewriter(std::move(peripheral_customization_event_rewriter));
-  }
+  AddEventRewriter(std::move(peripheral_customization_event_rewriter));
   AddEventRewriter(std::move(prerewritten_event_forwarder));
   // Accessibility rewriter is applied between modifier event rewriters and
   // EventRewriterAsh. Specifically, Search modifier is captured by the
diff --git a/ash/events/peripheral_customization_event_rewriter.cc b/ash/events/peripheral_customization_event_rewriter.cc
index 68ac3d87..ba7421e 100644
--- a/ash/events/peripheral_customization_event_rewriter.cc
+++ b/ash/events/peripheral_customization_event_rewriter.cc
@@ -1365,9 +1365,6 @@
 ui::EventDispatchDetails PeripheralCustomizationEventRewriter::RewriteEvent(
     const ui::Event& event,
     const Continuation continuation) {
-  DCHECK(features::IsPeripheralCustomizationEnabled() ||
-         ::features::IsShortcutCustomizationEnabled());
-
   if (event.IsMouseWheelEvent()) {
     return RewriteMouseWheelEvent(*event.AsMouseWheelEvent(), continuation);
   }
diff --git a/ash/events/prerewritten_event_forwarder_unittest.cc b/ash/events/prerewritten_event_forwarder_unittest.cc
index aaacf5f..39c9405 100644
--- a/ash/events/prerewritten_event_forwarder_unittest.cc
+++ b/ash/events/prerewritten_event_forwarder_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "ash/test/ash_test_base.h"
-#include "base/test/scoped_feature_list.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/event.h"
 #include "ui/events/test/test_event_rewriter_continuation.h"
@@ -88,8 +87,6 @@
   // testing::Test:
   void SetUp() override {
     AshTestBase::SetUp();
-    scoped_feature_list_.InitWithFeatures({features::kShortcutCustomization},
-                                          {});
     observer_ = std::make_unique<TestKeyObserver>();
     rewriter_ = std::make_unique<PrerewrittenEventForwarder>();
     rewriter_->AddObserver(observer_.get());
@@ -99,14 +96,12 @@
     rewriter_->RemoveObserver(observer_.get());
     rewriter_.reset();
     observer_.reset();
-    scoped_feature_list_.Reset();
     AshTestBase::TearDown();
   }
 
  protected:
   std::unique_ptr<TestKeyObserver> observer_;
   std::unique_ptr<PrerewrittenEventForwarder> rewriter_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(PrerewrittenEventForwarderTest, InitializationTest) {
diff --git a/ash/glanceables/tasks/glanceables_task_view.cc b/ash/glanceables/tasks/glanceables_task_view.cc
index 56b3b78d..ffd70bad 100644
--- a/ash/glanceables/tasks/glanceables_task_view.cc
+++ b/ash/glanceables/tasks/glanceables_task_view.cc
@@ -237,6 +237,14 @@
 
   bool checked() const { return checked_; }
 
+ protected:
+  // views::Button:
+  void UpdateAccessibleCheckedState() override {
+    GetViewAccessibility().SetCheckedState(
+        checked_ ? ax::mojom::CheckedState::kTrue
+                 : ax::mojom::CheckedState::kFalse);
+  }
+
  private:
   void UpdateImage() {
     SetImageModel(views::Button::STATE_NORMAL,
@@ -252,12 +260,6 @@
     UpdateAccessibleDefaultActionVerb();
   }
 
-  void UpdateAccessibleCheckedState() {
-    GetViewAccessibility().SetCheckedState(
-        checked_ ? ax::mojom::CheckedState::kTrue
-                 : ax::mojom::CheckedState::kFalse);
-  }
-
   bool checked_ = false;
 };
 
diff --git a/ash/public/cpp/accelerator_actions.h b/ash/public/cpp/accelerator_actions.h
index b1c38c9..d51d841 100644
--- a/ash/public/cpp/accelerator_actions.h
+++ b/ash/public/cpp/accelerator_actions.h
@@ -172,6 +172,7 @@
   ACCELERATOR_ACTION_ENTRY(ToggleMouseKeys)                            \
   ACCELERATOR_ACTION_ENTRY(ResizePipWindow)                            \
   ACCELERATOR_ACTION_ENTRY(ToggleGeminiApp)                            \
+  ACCELERATOR_ACTION_ENTRY(ToggleDoNotDisturb)                         \
   /* Debug actions are kept at an offset.*/                            \
   /* This offset should be kept consistent with the enum*/             \
   /* `AcceleratorAction` in*/                                          \
diff --git a/ash/public/cpp/accelerator_actions_unittest.cc b/ash/public/cpp/accelerator_actions_unittest.cc
index a8f2c1a..698754b 100644
--- a/ash/public/cpp/accelerator_actions_unittest.cc
+++ b/ash/public/cpp/accelerator_actions_unittest.cc
@@ -18,12 +18,12 @@
 namespace {
 
 // The total number of accelerator actions.
-constexpr int kAcceleratorActionsTotalNum = 168;
+constexpr int kAcceleratorActionsTotalNum = 169;
 // The toal number of debug accelerators, these will not be used for hashing.
 constexpr int kDebugAcceleratorActionsNum = 28;
 // The hash of accelerator actions. Please update this when adding a new
 // accelerator action.
-constexpr char kAcceleratorActionsHash[] = "bee5c18782483909ca5d43579d44442f";
+constexpr char kAcceleratorActionsHash[] = "c959943640043de5e44136e3154e30d2";
 
 // Define the mapping between an AcceleratorAction and its string name.
 // Example:
diff --git a/ash/public/cpp/accelerators.cc b/ash/public/cpp/accelerators.cc
index b49b705..8d339d6 100644
--- a/ash/public/cpp/accelerators.cc
+++ b/ash/public/cpp/accelerators.cc
@@ -9,6 +9,7 @@
 #include "base/no_destructor.h"
 #include "media/base/media_switches.h"
 #include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
 
 namespace ash {
 
@@ -59,6 +60,7 @@
     case ui::VKEY_F13:  // Lock button on some chromebooks emits F13.
     case ui::VKEY_PRIVACY_SCREEN_TOGGLE:
     case ui::VKEY_SETTINGS:
+    case ui::VKEY_DO_NOT_DISTURB:
       return true;
     case ui::VKEY_MEDIA_NEXT_TRACK:
     case ui::VKEY_MEDIA_PAUSE:
diff --git a/ash/public/cpp/accelerators.h b/ash/public/cpp/accelerators.h
index b79df1c4..166dbc21 100644
--- a/ash/public/cpp/accelerators.h
+++ b/ash/public/cpp/accelerators.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
 
 namespace ui {
 class Accelerator;
@@ -446,6 +447,15 @@
 ASH_PUBLIC_EXPORT inline constexpr size_t kGeminiAcceleratorDataLength =
     std::size(kGeminiAcceleratorData);
 
+ASH_PUBLIC_EXPORT inline constexpr AcceleratorData
+    kToggleDoNotDisturbAcceleratorData[] = {
+        {true, ui::VKEY_DO_NOT_DISTURB, ui::EF_NONE,
+         AcceleratorAction::kToggleDoNotDisturb},
+};
+ASH_PUBLIC_EXPORT inline constexpr size_t
+    kToggleDoNotDisturbAcceleratorDataLength =
+        std::size(kToggleDoNotDisturbAcceleratorData);
+
 // The public-facing interface for accelerator handling, which is Ash's duty to
 // implement.
 class ASH_PUBLIC_EXPORT AcceleratorController {
diff --git a/ash/public/cpp/accelerators_util.cc b/ash/public/cpp/accelerators_util.cc
index 266d453..00d731a 100644
--- a/ash/public/cpp/accelerators_util.cc
+++ b/ash/public/cpp/accelerators_util.cc
@@ -123,6 +123,7 @@
           {ui::KeyboardCode::VKEY_CAPITAL, u"caps lock"},
           {ui::KeyboardCode::VKEY_ACCESSIBILITY, u"Accessibility"},
           {ui::KeyboardCode::VKEY_QUICK_INSERT, u"QuickInsert"},
+          {ui::KeyboardCode::VKEY_DO_NOT_DISTURB, u"DoNotDisturb"},
       }));
   return *key_display_map;
 }
diff --git a/ash/public/cpp/app_list/app_list_types.cc b/ash/public/cpp/app_list/app_list_types.cc
index a263959..1e13fbe 100644
--- a/ash/public/cpp/app_list/app_list_types.cc
+++ b/ash/public/cpp/app_list/app_list_types.cc
@@ -526,6 +526,8 @@
       return &kKsContextMenuIcon;
     case kKeyboardShortcutKeyboardQuickInsert:
       return &kQuickInsertIcon;
+    case kKeyboardShortcutDoNotDisturb:
+      return &kKsDoNotDisturbIcon;
     default:
       return nullptr;
   }
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h
index 35b7331..cabb2380 100644
--- a/ash/public/cpp/app_list/app_list_types.h
+++ b/ash/public/cpp/app_list/app_list_types.h
@@ -688,6 +688,7 @@
     kKeyboardShortcutBrowserHome,
     kKeyboardShortcutMediaLaunchMail,
     kKeyboardShortcutContextMenu,
+    kKeyboardShortcutDoNotDisturb,
   };
 
   // Only used for SearchResultTextItemType kString
diff --git a/ash/public/mojom/BUILD.gn b/ash/public/mojom/BUILD.gn
index b8e22dd0..bf39f5a 100644
--- a/ash/public/mojom/BUILD.gn
+++ b/ash/public/mojom/BUILD.gn
@@ -10,7 +10,10 @@
 mojom("mojom") {
   disable_variants = true
 
-  sources = [ "assistant_volume_control.mojom" ]
+  sources = [
+    "assistant_volume_control.mojom",
+    "wallpaper.mojom",
+  ]
 
   public_deps = [
     ":accelerator_actions",
diff --git a/ash/public/mojom/accelerator_actions.mojom b/ash/public/mojom/accelerator_actions.mojom
index 4b4ef55..e5f937b5 100644
--- a/ash/public/mojom/accelerator_actions.mojom
+++ b/ash/public/mojom/accelerator_actions.mojom
@@ -146,6 +146,7 @@
   kToggleMouseKeys,
   kResizePipWindow,
   kToggleGeminiApp,
+  kToggleDoNotDisturb,
   // The following are DEBUG actions with an offset. This is to keep the enum
   // in sync with `AcceleratorActions` in ash/public/cpp/accelerator_actions.h.
   kDebugClearUseKMeansPref = 9000,
diff --git a/ash/public/mojom/accelerator_actions_mojom_traits.cc b/ash/public/mojom/accelerator_actions_mojom_traits.cc
index ed5f77f..ee26b877 100644
--- a/ash/public/mojom/accelerator_actions_mojom_traits.cc
+++ b/ash/public/mojom/accelerator_actions_mojom_traits.cc
@@ -295,6 +295,8 @@
       return mojom_accelerator_action::kResizePipWindow;
     case ash::AcceleratorAction::kToggleGeminiApp:
       return mojom_accelerator_action::kToggleGeminiApp;
+    case ash::kToggleDoNotDisturb:
+      return mojom_accelerator_action::kToggleDoNotDisturb;
     case ash::AcceleratorAction::kDebugClearUseKMeansPref:
       return mojom_accelerator_action::kDebugClearUseKMeansPref;
     case ash::AcceleratorAction::kDebugKeyboardBacklightToggle:
@@ -780,6 +782,9 @@
     case mojom_accelerator_action::kToggleGeminiApp:
       *out = ash::AcceleratorAction::kToggleGeminiApp;
       return true;
+    case mojom_accelerator_action::kToggleDoNotDisturb:
+      *out = ash::AcceleratorAction::kToggleDoNotDisturb;
+      return true;
     case mojom_accelerator_action::kDebugClearUseKMeansPref:
       *out = ash::AcceleratorAction::kDebugClearUseKMeansPref;
       return true;
diff --git a/ash/public/mojom/accelerator_keys.mojom b/ash/public/mojom/accelerator_keys.mojom
index 2f0878d..fd3d35e 100644
--- a/ash/public/mojom/accelerator_keys.mojom
+++ b/ash/public/mojom/accelerator_keys.mojom
@@ -188,6 +188,7 @@
   kFunction = 0xFF,
   kQuickInsert = 0x100,
   kAccessibility = 0x101,
+  kDoNotDisturb = 0x102,
   kUnknown = 0,
 
   // POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
diff --git a/ash/public/mojom/accelerator_keys_mojom_traits.cc b/ash/public/mojom/accelerator_keys_mojom_traits.cc
index 83c97eb8..29400b6 100644
--- a/ash/public/mojom/accelerator_keys_mojom_traits.cc
+++ b/ash/public/mojom/accelerator_keys_mojom_traits.cc
@@ -413,6 +413,8 @@
       return mojom_vkey::kQuickInsert;
     case ui::VKEY_ACCESSIBILITY:
       return mojom_vkey::kAccessibility;
+    case ui::VKEY_DO_NOT_DISTURB:
+      return mojom_vkey::kDoNotDisturb;
     case ui::VKEY_BUTTON_0:
       return mojom_vkey::kButton0;
     case ui::VKEY_BUTTON_1:
@@ -1048,6 +1050,9 @@
     case ash::mojom::VKey::kAccessibility:
       *out = ui::KeyboardCode::VKEY_ACCESSIBILITY;
       return true;
+    case ash::mojom::VKey::kDoNotDisturb:
+      *out = ui::KeyboardCode::VKEY_DO_NOT_DISTURB;
+      return true;
     case ash::mojom::VKey::kFunction:
       *out = ui::KeyboardCode::VKEY_FUNCTION;
       return true;
diff --git a/ash/public/mojom/accelerator_keys_mojom_traits_unittest.cc b/ash/public/mojom/accelerator_keys_mojom_traits_unittest.cc
index c2fc4cb6..6601d403 100644
--- a/ash/public/mojom/accelerator_keys_mojom_traits_unittest.cc
+++ b/ash/public/mojom/accelerator_keys_mojom_traits_unittest.cc
@@ -58,7 +58,8 @@
        {mojom_vkey::kF14, ui::KeyboardCode::VKEY_F14},
        {mojom_vkey::kPrivacyScreenToggle,
         ui::KeyboardCode::VKEY_PRIVACY_SCREEN_TOGGLE},
-       {mojom_vkey::kAccessibility, ui::KeyboardCode::VKEY_ACCESSIBILITY}});
+       {mojom_vkey::kAccessibility, ui::KeyboardCode::VKEY_ACCESSIBILITY},
+       {mojom_vkey::kDoNotDisturb, ui::KeyboardCode::VKEY_DO_NOT_DISTURB}});
 
   TestKeyboardCodeToMojo(enums);
   TestMojoToKeyboardCode(enums);
diff --git a/ash/public/mojom/input_device_settings.mojom b/ash/public/mojom/input_device_settings.mojom
index 62bc47c0..1a844ae 100644
--- a/ash/public/mojom/input_device_settings.mojom
+++ b/ash/public/mojom/input_device_settings.mojom
@@ -117,6 +117,7 @@
   kDictation,
   kPrivacyScreenToggle,
   kAccessibility,
+  kDoNotDisturb,
 };
 
 // Specifies the current charging state of a battery-powered device.
diff --git a/chromeos/crosapi/mojom/wallpaper.mojom b/ash/public/mojom/wallpaper.mojom
similarity index 94%
rename from chromeos/crosapi/mojom/wallpaper.mojom
rename to ash/public/mojom/wallpaper.mojom
index 9a558cf..5e9bf60 100644
--- a/chromeos/crosapi/mojom/wallpaper.mojom
+++ b/ash/public/mojom/wallpaper.mojom
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module crosapi.mojom;
+module ash.mojom;
 
 [Extensible]
 enum WallpaperLayout {
-  kNone = 0,
+  [Default] kNone = 0,
   kStretch = 1,
   kCenter = 2,
   kCenterCropped = 3,
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 71f00c1..f9973dd 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -195,6 +195,7 @@
     "ks_calculator.icon",
     "ks_context_menu.icon",
     "ks_dictation.icon",
+    "ks_do_not_disturb.icon",
     "ks_emoji_picker.icon",
     "ks_input_mode_change.icon",
     "ks_keyboard_brightness_down.icon",
diff --git a/ash/resources/vector_icons/ks_do_not_disturb.icon b/ash/resources/vector_icons/ks_do_not_disturb.icon
new file mode 100644
index 0000000..36baab6
--- /dev/null
+++ b/ash/resources/vector_icons/ks_do_not_disturb.icon
@@ -0,0 +1,40 @@
+// Copyright 2024 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,
+FILL_RULE_NONZERO,
+MOVE_TO, 6, 10.88f,
+R_H_LINE_TO, 8,
+R_V_LINE_TO, -1.75f,
+H_LINE_TO, 6,
+R_V_LINE_TO, 1.75f,
+CLOSE,
+R_MOVE_TO, 4, 7.29f,
+R_ARC_TO, 8.21f, 8.21f, 0, 0, 1, -3.19f, -0.62f,
+R_ARC_TO, 8.59f, 8.59f, 0, 0, 1, -2.6f, -1.75f,
+R_ARC_TO, 8.59f, 8.59f, 0, 0, 1, -1.75f, -2.6f,
+ARC_TO, 8.2f, 8.2f, 0, 0, 1, 1.83f, 10,
+R_CUBIC_TO, 0, -1.14f, 0.21f, -2.2f, 0.63f, -3.19f,
+R_ARC_TO, 8.33f, 8.33f, 0, 0, 1, 1.75f, -2.58f,
+R_ARC_TO, 8.11f, 8.11f, 0, 0, 1, 2.6f, -1.75f,
+R_CUBIC_TO, 1, -0.43f, 2.06f, -0.65f, 3.19f, -0.65f,
+R_CUBIC_TO, 1.14f, 0, 2.2f, 0.22f, 3.19f, 0.65f,
+R_ARC_TO, 7.88f, 7.88f, 0, 0, 1, 2.58f, 1.75f,
+R_ARC_TO, 7.82f, 7.82f, 0, 0, 1, 1.75f, 2.6f,
+R_CUBIC_TO, 0.43f, 0.99f, 0.65f, 2.04f, 0.65f, 3.17f,
+R_ARC_TO, 7.97f, 7.97f, 0, 0, 1, -0.65f, 3.19f,
+R_CUBIC_TO, -0.42f, 0.99f, -1, 1.85f, -1.75f, 2.6f,
+R_ARC_TO, 8.26f, 8.26f, 0, 0, 1, -2.6f, 1.75f,
+R_ARC_TO, 8.05f, 8.05f, 0, 0, 1, -3.17f, 0.63f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+R_CUBIC_TO, 1.79f, 0, 3.31f, -0.62f, 4.56f, -1.87f,
+R_CUBIC_TO, 1.25f, -1.25f, 1.87f, -2.77f, 1.87f, -4.56f,
+R_CUBIC_TO, 0, -1.79f, -0.62f, -3.31f, -1.87f, -4.56f,
+R_CUBIC_TO, -1.25f, -1.25f, -2.77f, -1.87f, -4.56f, -1.87f,
+R_CUBIC_TO, -1.79f, 0, -3.31f, 0.63f, -4.56f, 1.88f,
+R_CUBIC_TO, -1.25f, 1.25f, -1.87f, 2.77f, -1.87f, 4.56f,
+R_CUBIC_TO, 0, 1.79f, 0.63f, 3.31f, 1.88f, 4.56f,
+R_CUBIC_TO, 1.25f, 1.25f, 2.77f, 1.87f, 4.56f, 1.87f,
+CLOSE
diff --git a/ash/shell.cc b/ash/shell.cc
index 7c1bd01..17df1fd 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -798,8 +798,7 @@
   }
   RemovePreTargetHandler(system_gesture_filter_.get());
   RemoveAccessibilityEventHandler(mouse_cursor_filter_.get());
-  if (features::IsPeripheralCustomizationEnabled() ||
-      ::features::IsShortcutCustomizationEnabled()) {
+  if (features::IsPeripheralCustomizationEnabled()) {
     RemovePreTargetHandler(shortcut_input_handler_.get());
   }
   RemovePreTargetHandler(modality_filter_.get());
@@ -1659,8 +1658,7 @@
   modality_filter_ = std::make_unique<SystemModalContainerEventFilter>(this);
   AddPreTargetHandler(modality_filter_.get());
 
-  if (features::IsPeripheralCustomizationEnabled() ||
-      ::features::IsShortcutCustomizationEnabled()) {
+  if (features::IsPeripheralCustomizationEnabled()) {
     shortcut_input_handler_ = std::make_unique<ShortcutInputHandler>();
     AddPreTargetHandler(shortcut_input_handler_.get());
   }
diff --git a/ash/system/diagnostics/mojom/BUILD.gn b/ash/system/diagnostics/mojom/BUILD.gn
index 58a570f3..25b79372 100644
--- a/ash/system/diagnostics/mojom/BUILD.gn
+++ b/ash/system/diagnostics/mojom/BUILD.gn
@@ -12,6 +12,7 @@
 
   webui_module_path = "/ash/webui/diagnostics_ui"
 
-  # Generate WebUI bindings in JavaScript rather than TypeScript.
-  generate_webui_js_bindings = true
+  # Non-CQ target //chromeos/services/chromebox_for_meetings has a transitive
+  # dependency on this file, and relies on the deprecated legacy bindings.
+  generate_legacy_js_bindings = true
 }
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 23c431f..ea1fb99 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
@@ -69,6 +69,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/ash/keyboard_capability.h"
+#include "ui/events/ash/top_row_action_keys.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/keyboard_device.h"
 #include "ui/events/devices/touchpad_device.h"
@@ -134,6 +135,8 @@
       return mojom::TopRowActionKey::kDictation;
     case ui::TopRowActionKey::kAccessibility:
       return mojom::TopRowActionKey::kAccessibility;
+    case ui::TopRowActionKey::kDoNotDisturb:
+      return mojom::TopRowActionKey::kDoNotDisturb;
     case ui::TopRowActionKey::kUnknown:
     case ui::TopRowActionKey::kNone:
       return mojom::TopRowActionKey::kNone;
diff --git a/ash/system/time/calendar_list_model_unittest.cc b/ash/system/time/calendar_list_model_unittest.cc
index 868d1e0..95ccbdcd 100644
--- a/ash/system/time/calendar_list_model_unittest.cc
+++ b/ash/system/time/calendar_list_model_unittest.cc
@@ -138,7 +138,7 @@
     AshTestBase::SetUp();
 
     // Register a mock `CalendarClient` to the `CalendarController`.
-    const std::string email = "test1@google.com";
+    const std::string email = "user1@test.com";
     AccountId account_id = AccountId::FromUserEmail(email);
     Shell::Get()->calendar_controller()->SetActiveUserAccountIdForTesting(
         account_id);
@@ -165,19 +165,11 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  void UpdateSession(uint32_t session_id,
-                     const std::string& email,
-                     bool is_child = false) {
-    UserSession session;
-    session.session_id = session_id;
-    session.user_info.type = is_child ? user_manager::UserType::kChild
-                                      : user_manager::UserType::kRegular;
-    session.user_info.account_id = AccountId::FromUserEmail(email);
-    session.user_info.display_name = email;
-    session.user_info.display_email = email;
-    session.user_info.is_new_profile = false;
-
-    SessionController::Get()->UpdateUserSession(session);
+  AccountId SimulateLogin(const std::string& email, bool is_child = false) {
+    auto account_id = AccountId::FromUserEmail(email);
+    SimulateUserLogin(account_id, is_child ? user_manager::UserType::kChild
+                                           : user_manager::UserType::kRegular);
+    return account_id;
   }
 
   CalendarListModel* calendar_list_model() {
@@ -327,11 +319,9 @@
 
 TEST_F(CalendarListModelTest, ActiveUserChange) {
   // Set up two users, user1 is the active user.
-  UpdateSession(1u, "user1@test.com");
-  UpdateSession(2u, "user2@test.com");
-  std::vector<uint32_t> order = {1u, 2u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
+  auto account_id1 = SimulateLogin("user1@test.com");
+  auto account_id2 = SimulateLogin("user2@test.com");
+  SwitchActiveUser(account_id1);
 
   // Set up list of calendars as the mock response.
   client()->SetCalendarList(CreateMockCalendarList());
@@ -346,8 +336,7 @@
   EXPECT_EQ(3u, calendar_list.size());
 
   // Make user2 the active user, and the cached calendars should be cleared.
-  order = {2u, 1u};
-  SessionController::Get()->SetUserSessionOrder(order);
+  SwitchActiveUser(account_id2);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(calendar_list_model()->get_is_cached());
   calendar_list = calendar_list_model()->GetCachedCalendarList();
@@ -356,11 +345,9 @@
 
 TEST_F(CalendarListModelTest, ActiveChildUserChange) {
   // Set up two child users, user1 is the active user.
-  UpdateSession(1u, "user1@test.com", /*is_child=*/true);
-  UpdateSession(2u, "user2@test.com", /*is_child=*/true);
-  std::vector<uint32_t> order = {1u, 2u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
+  auto account_id1 = SimulateLogin("user1@test.com", /*is_child=*/true);
+  auto account_id2 = SimulateLogin("user2@test.com", /*is_child=*/true);
+  SwitchActiveUser(account_id1);
 
   // Set up list of calendars as the mock response.
   client()->SetCalendarList(CreateMockCalendarList());
@@ -375,8 +362,7 @@
   EXPECT_EQ(3u, calendar_list.size());
 
   // Make user2 the active user, and the cached calendars should be cleared.
-  order = {2u, 1u};
-  SessionController::Get()->SetUserSessionOrder(order);
+  SwitchActiveUser(account_id2);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(calendar_list_model()->get_is_cached());
   calendar_list = calendar_list_model()->GetCachedCalendarList();
diff --git a/ash/system/time/calendar_model_unittest.cc b/ash/system/time/calendar_model_unittest.cc
index 8858989..39119b11 100644
--- a/ash/system/time/calendar_model_unittest.cc
+++ b/ash/system/time/calendar_model_unittest.cc
@@ -163,11 +163,12 @@
 }
 
 class CalendarModelTest
-    : public AshTestBase,
+    : public NoSessionAshTestBase,
       public testing::WithParamInterface</*multi_calendar_enabled=*/bool> {
  public:
   CalendarModelTest()
-      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+      : NoSessionAshTestBase(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
     scoped_feature_list_.InitWithFeatureState(
         ash::features::kMultiCalendarSupport, IsMultiCalendarEnabled());
   }
@@ -177,13 +178,12 @@
   ~CalendarModelTest() override = default;
 
   void SetUp() override {
-    AshTestBase::SetUp();
+    NoSessionAshTestBase::SetUp();
 
     // Register a mock `CalendarClient` to the `CalendarController`.
     const std::string email = "user1@email.com";
-    AccountId account_id = AccountId::FromUserEmail(email);
-    Shell::Get()->calendar_controller()->SetActiveUserAccountIdForTesting(
-        account_id);
+    auto account_id = AccountId::FromUserEmail(email);
+    SimulateUserLogin(account_id);
     calendar_model_ = std::make_unique<CalendarModel>();
     calendar_client_ =
         std::make_unique<calendar_test_utils::CalendarClientTestImpl>();
@@ -202,7 +202,7 @@
     calendar_model_.reset();
     scoped_feature_list_.Reset();
 
-    AshTestBase::TearDown();
+    NoSessionAshTestBase::TearDown();
   }
 
   bool IsMultiCalendarEnabled() { return GetParam(); }
@@ -297,19 +297,13 @@
     return true;
   }
 
-  void UpdateSession(uint32_t session_id,
-                     const std::string& email,
-                     bool is_child = false) {
-    UserSession session;
-    session.session_id = session_id;
-    session.user_info.type = is_child ? user_manager::UserType::kChild
-                                      : user_manager::UserType::kRegular;
-    session.user_info.account_id = AccountId::FromUserEmail(email);
-    session.user_info.display_name = email;
-    session.user_info.display_email = email;
-    session.user_info.is_new_profile = false;
-
-    SessionController::Get()->UpdateUserSession(session);
+  AccountId SimulateLogin(const std::string& email, bool is_child = false) {
+    auto account_id = AccountId::FromUserEmail(email);
+    SimulateUserLogin(account_id, is_child ? user_manager::UserType::kChild
+                                           : user_manager::UserType::kRegular);
+    Shell::Get()->calendar_controller()->RegisterClientForUser(
+        account_id, calendar_client_.get());
+    return account_id;
   }
 
   void TestMultiDayEvent(SingleDayEventList events,
@@ -907,7 +901,6 @@
   SessionInfo session_info;
   session_info.state = session_manager::SessionState::LOCKED;
   SessionController::Get()->SetSessionInfo(session_info);
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
   EXPECT_TRUE(events.empty());
 }
@@ -916,18 +909,17 @@
   // Sets the timezone to "GMT".
   ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
 
+  // Set up two users, user1 is the active user.
+  auto account_id1 = SimulateLogin("user1@test.com");
+  auto account_id2 = SimulateLogin("user2@test.com");
+  SwitchActiveUser(account_id1);
+  // Switching a user clears the cache. Fetch calendars again.
   if (IsMultiCalendarEnabled()) {
+    FetchCalendars();
     EXPECT_TRUE(calendar_list_model()->get_is_cached());
     EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
   }
 
-  // Set up two users, user1 is the active user.
-  UpdateSession(1u, "user1@test.com");
-  UpdateSession(2u, "user2@test.com");
-  std::vector<uint32_t> order = {1u, 2u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
-
   // Current date is just `kStartTime0`.
   SetTodayFromStr(kStartTime0);
   std::set<base::Time> months =
@@ -956,9 +948,8 @@
   EXPECT_TRUE(events.size() == 1);
 
   // Make user2 the active user, and we should clear the cached events.
-  order = {2u, 1u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
+  SwitchActiveUser(account_id2);
+
   EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
   EXPECT_TRUE(events.empty());
   EXPECT_TRUE(event_months().empty());
@@ -968,18 +959,18 @@
   // Sets the timezone to "GMT".
   ash::system::ScopedTimezoneSettings timezone_settings(u"GMT");
 
+  // Set up two users, user1 is the active user.
+  auto account_id1 = SimulateLogin("user1@test.com", /*is_child*/ true);
+  auto account_id2 = SimulateLogin("user2@test.com", /*is_child*/ true);
+  SwitchActiveUser(account_id1);
+
   if (IsMultiCalendarEnabled()) {
+    // Switching a user clears the cache. Fetch calendars again.
+    FetchCalendars();
     EXPECT_TRUE(calendar_list_model()->get_is_cached());
     EXPECT_EQ(1u, calendar_list_model()->GetCachedCalendarList().size());
   }
 
-  // Set up two users, user1 is the active user.
-  UpdateSession(1u, "user1@test.com", /*is_child*/ true);
-  UpdateSession(2u, "user2@test.com", /*is_child*/ true);
-  std::vector<uint32_t> order = {1u, 2u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
-
   // Current date is just `kStartTime0`.
   SetTodayFromStr(kStartTime0);
   std::set<base::Time> months =
@@ -1008,9 +999,8 @@
   EXPECT_TRUE(events.size() == 1);
 
   // Make user2 the active user, and we should clear the cached events.
-  order = {2u, 1u};
-  SessionController::Get()->SetUserSessionOrder(order);
-  base::RunLoop().RunUntilIdle();
+  SwitchActiveUser(account_id2);
+
   EXPECT_EQ(0, EventsNumberOfDay(kStartTime0, &events));
   EXPECT_TRUE(events.empty());
   EXPECT_TRUE(event_months().empty());
diff --git a/ash/webui/common/backend/accelerator_fetcher.cc b/ash/webui/common/backend/accelerator_fetcher.cc
index 0280082..ed2e280 100644
--- a/ash/webui/common/backend/accelerator_fetcher.cc
+++ b/ash/webui/common/backend/accelerator_fetcher.cc
@@ -45,10 +45,6 @@
 }  // namespace
 
 AcceleratorFetcher::AcceleratorFetcher() {
-  if (!::features::IsShortcutCustomizationEnabled()) {
-    return;
-  }
-
   if (Shell::HasInstance()) {
     Shell::Get()
         ->accelerator_controller()
@@ -61,10 +57,6 @@
 }
 
 AcceleratorFetcher::~AcceleratorFetcher() {
-  if (!::features::IsShortcutCustomizationEnabled()) {
-    return;
-  }
-
   if (Shell::HasInstance()) {
     Shell::Get()
         ->accelerator_controller()
@@ -75,7 +67,6 @@
 
 void AcceleratorFetcher::BindInterface(
     mojo::PendingReceiver<common::mojom::AcceleratorFetcher> receiver) {
-  CHECK(::features::IsShortcutCustomizationEnabled());
   if (accelerator_fetcher_receiver_.is_bound()) {
     accelerator_fetcher_receiver_.reset();
   }
diff --git a/ash/webui/common/backend/accelerator_fetcher_unittest.cc b/ash/webui/common/backend/accelerator_fetcher_unittest.cc
index ef22f6e2..8a25a64 100644
--- a/ash/webui/common/backend/accelerator_fetcher_unittest.cc
+++ b/ash/webui/common/backend/accelerator_fetcher_unittest.cc
@@ -79,8 +79,7 @@
  public:
   AcceleratorFetcherTest() {
     scoped_feature_list_.InitWithFeatures({features::kPeripheralCustomization,
-                                           features::kInputDeviceSettingsSplit,
-                                           ::features::kShortcutCustomization},
+                                           features::kInputDeviceSettingsSplit},
                                           {});
   }
 
diff --git a/ash/webui/common/backend/shortcut_input_provider.cc b/ash/webui/common/backend/shortcut_input_provider.cc
index 518e1c5..6a3ef5a2 100644
--- a/ash/webui/common/backend/shortcut_input_provider.cc
+++ b/ash/webui/common/backend/shortcut_input_provider.cc
@@ -46,7 +46,6 @@
 void ShortcutInputProvider::BindInterface(
     mojo::PendingReceiver<common::mojom::ShortcutInputProvider> receiver) {
   CHECK(features::IsPeripheralCustomizationEnabled() ||
-        ::features::IsShortcutCustomizationEnabled() ||
         ::features::IsAccessibilityFaceGazeEnabled());
   if (shortcut_input_receiver_.is_bound()) {
     shortcut_input_receiver_.reset();
diff --git a/ash/webui/common/resources/shortcut_input_ui/icons.html b/ash/webui/common/resources/shortcut_input_ui/icons.html
index 857b28f..c0cbd0c 100644
--- a/ash/webui/common/resources/shortcut_input_ui/icons.html
+++ b/ash/webui/common/resources/shortcut_input_ui/icons.html
@@ -46,6 +46,9 @@
           </clipPath>
         </defs>
       </g>
+      <g id="do-not-disturb" viewbox="0 0 20 20">
+        <path d="M6 10.875h8v-1.75H6v1.75Zm4 7.292a8.205 8.205 0 0 1-3.188-.625 8.59 8.59 0 0 1-2.604-1.75 8.589 8.589 0 0 1-1.75-2.604A8.204 8.204 0 0 1 1.833 10c0-1.139.209-2.201.625-3.188a8.327 8.327 0 0 1 1.75-2.583 8.112 8.112 0 0 1 2.604-1.75c1-.43 2.063-.646 3.188-.646 1.139 0 2.201.216 3.188.646a7.88 7.88 0 0 1 2.583 1.75 7.82 7.82 0 0 1 1.75 2.604c.43.986.646 2.042.646 3.167a7.974 7.974 0 0 1-.646 3.188c-.417.986-1 1.854-1.75 2.604a8.262 8.262 0 0 1-2.604 1.75 8.053 8.053 0 0 1-3.167.625Zm0-1.73c1.792 0 3.313-.625 4.563-1.875 1.25-1.25 1.874-2.77 1.874-4.562 0-1.792-.625-3.313-1.875-4.563-1.25-1.25-2.77-1.875-4.562-1.875-1.792 0-3.313.626-4.563 1.876-1.25 1.25-1.875 2.77-1.875 4.562 0 1.792.626 3.313 1.876 4.563 1.25 1.25 2.77 1.874 4.562 1.874Z"></path>
+      </g>
       <g id="display-brightness-down" viewbox="0 0 20 20">
         <path fill-rule="evenodd"
           d="M9.99982 4.13281L11.7889 5.87499H14.1285V8.15322L15.7799 9.76139L14.1285 11.5036V13.7818H11.7889L9.99982 15.39L8.34836 13.7818H6.00878V11.5036L4.21973 9.76139L6.00878 8.15322V5.87499H8.34836L9.99982 4.13281ZM9.99982 6.41105L8.89883 7.48315H7.66025V8.68928L6.5593 9.76139L7.66025 10.9675V12.0396H8.89883L9.99982 13.2457L11.2384 12.0396H12.3394V10.9675L13.5779 9.76139L12.3394 8.68928V7.48315H11.2384L9.99982 6.41105Z">
diff --git a/ash/webui/common/resources/shortcut_input_ui/shortcut_utils.ts b/ash/webui/common/resources/shortcut_input_ui/shortcut_utils.ts
index 986de5e..6544bb2 100644
--- a/ash/webui/common/resources/shortcut_input_ui/shortcut_utils.ts
+++ b/ash/webui/common/resources/shortcut_input_ui/shortcut_utils.ts
@@ -93,6 +93,7 @@
   'BrowserRefresh': 'refresh',
   'BrowserSearch': 'browser-search',
   'ContextMenu': 'menu',
+  'DoNotDisturb': 'do-not-disturb',
   'EmojiPicker': 'emoji-picker',
   'EnableOrToggleDictation': 'dictation-toggle',
   'KeyboardBacklightToggle': 'keyboard-brightness-toggle',
diff --git a/ash/webui/common/shortcut_input_key_strings.cc b/ash/webui/common/shortcut_input_key_strings.cc
index 9b6f5a3..9fa57107 100644
--- a/ash/webui/common/shortcut_input_key_strings.cc
+++ b/ash/webui/common/shortcut_input_key_strings.cc
@@ -44,6 +44,8 @@
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_SEARCH},
       {"iconLabelContextMenu",
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_CONTEXT_MENU},
+      {"iconLabelDoNotDisturb",
+       IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB},
       {"iconLabelEnableOrToggleDictation",
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ENABLE_OR_TOGGLE_DICTATION},
       {"iconLabelEmojiPicker",
diff --git a/ash/webui/diagnostics_ui/backend/input/input_data_provider_keyboard.cc b/ash/webui/diagnostics_ui/backend/input/input_data_provider_keyboard.cc
index 081a93a..e93d16b 100644
--- a/ash/webui/diagnostics_ui/backend/input/input_data_provider_keyboard.cc
+++ b/ash/webui/diagnostics_ui/backend/input/input_data_provider_keyboard.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 "ui/events/ash/top_row_action_keys.h"
 #ifdef UNSAFE_BUFFERS_BUILD
 // TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
 #pragma allow_unsafe_buffers
@@ -251,6 +252,7 @@
     case ui::TopRowActionKey::kEmojiPicker:
     case ui::TopRowActionKey::kDictation:
     case ui::TopRowActionKey::kAccessibility:
+    case ui::TopRowActionKey::kDoNotDisturb:
     case ui::TopRowActionKey::kUnknown:
       return mojom::TopRowKey::kUnknown;
     case ui::TopRowActionKey::kNone:
diff --git a/ash/webui/diagnostics_ui/mojom/BUILD.gn b/ash/webui/diagnostics_ui/mojom/BUILD.gn
index e60e01d..b5ecc33 100644
--- a/ash/webui/diagnostics_ui/mojom/BUILD.gn
+++ b/ash/webui/diagnostics_ui/mojom/BUILD.gn
@@ -17,9 +17,6 @@
 
   webui_module_path = "/ash/webui/diagnostics_ui"
 
-  # Generate WebUI bindings in JavaScript instead of TypeScript.
-  generate_webui_js_bindings = true
-
   public_deps = [
     "//ash/system/diagnostics/mojom",
     "//mojo/public/mojom/base",
diff --git a/ash/webui/diagnostics_ui/resources/BUILD.gn b/ash/webui/diagnostics_ui/resources/BUILD.gn
index 69885ed..f274b02 100644
--- a/ash/webui/diagnostics_ui/resources/BUILD.gn
+++ b/ash/webui/diagnostics_ui/resources/BUILD.gn
@@ -69,17 +69,16 @@
   ]
 
   mojo_files = [
-    "$root_gen_dir/mojom-webui/ash/system/diagnostics/mojom/input.mojom-webui.js",
-    "$root_gen_dir/mojom-webui/ash/webui/diagnostics_ui/mojom/input_data_provider.mojom-webui.js",
-    "$root_gen_dir/mojom-webui/ash/webui/diagnostics_ui/mojom/network_health_provider.mojom-webui.js",
-    "$root_gen_dir/mojom-webui/ash/webui/diagnostics_ui/mojom/system_data_provider.mojom-webui.js",
-    "$root_gen_dir/mojom-webui/ash/webui/diagnostics_ui/mojom/system_routine_controller.mojom-webui.js",
+    "$root_gen_dir/ash/system/diagnostics/mojom/input.mojom-webui.ts",
+    "$root_gen_dir/ash/webui/diagnostics_ui/mojom/input_data_provider.mojom-webui.ts",
+    "$root_gen_dir/ash/webui/diagnostics_ui/mojom/network_health_provider.mojom-webui.ts",
+    "$root_gen_dir/ash/webui/diagnostics_ui/mojom/system_data_provider.mojom-webui.ts",
+    "$root_gen_dir/ash/webui/diagnostics_ui/mojom/system_routine_controller.mojom-webui.ts",
   ]
 
   mojo_files_deps = [
-    "../mojom:mojom_webui_js",
-    "//ash/system/diagnostics/mojom:mojom_webui_js",
-    "//ash/webui/diagnostics_ui/mojom:mojom_webui_js",
+    "//ash/system/diagnostics/mojom:mojom_ts__generator",
+    "//ash/webui/diagnostics_ui/mojom:mojom_ts__generator",
   ]
   ts_composite = true
   ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
diff --git a/ash/webui/diagnostics_ui/resources/cellular_info.ts b/ash/webui/diagnostics_ui/resources/cellular_info.ts
index ded81020..6634ba0 100644
--- a/ash/webui/diagnostics_ui/resources/cellular_info.ts
+++ b/ash/webui/diagnostics_ui/resources/cellular_info.ts
@@ -94,7 +94,6 @@
       case RoamingState.kHome:
         return this.i18n('networkRoamingStateHome');
     }
-    assertNotReached();
   }
 
   protected computeSimLockedText(): string {
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_network_icon.ts b/ash/webui/diagnostics_ui/resources/diagnostics_network_icon.ts
index 667a4cb2..c937b7a 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_network_icon.ts
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_network_icon.ts
@@ -84,7 +84,6 @@
     case NetworkState.kDisabled:
       return ConnectionStateType.kNotConnected;
   }
-  assertNotReached();
 }
 
 function convertNetworkTypeToCrosNetworkType(type: NetworkType):
@@ -197,7 +196,6 @@
     case SecurityType.kWpaPsk:
       return CrosSecurityType.kWpaPsk;
   }
-  assertNotReached();
 }
 
 /**
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_types.ts b/ash/webui/diagnostics_ui/resources/diagnostics_types.ts
index 840ac62..531c6eab7 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_types.ts
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_types.ts
@@ -61,19 +61,16 @@
   touchDevices: TouchDeviceInfo[];
 }
 
-// Union properties should be optional but TypeScript is not able to infer
-// that from the autogenerated closure annotations.
-export type WiFiNetwork = Omit<Network, 'typeProperties'|'ipConfig'>&{
-  typeProperties?: {wifi?: WiFiStateProperties},
-  ipConfig?: IPConfigProperties,
+// Specifying subtypes for convenience for different possible fields in
+// |typeProperties|.
+export type WiFiNetwork = Omit<Network, 'typeProperties'>&{
+  typeProperties: {wifi?: WiFiStateProperties} | null,
 };
 
-export type CellularNetwork = Omit<Network, 'typeProperties'|'ipConfig'>&{
-  typeProperties?: {cellular?: CellularStateProperties},
-  ipConfig?: IPConfigProperties,
+export type CellularNetwork = Omit<Network, 'typeProperties'>&{
+  typeProperties: {cellular?: CellularStateProperties} | null,
 };
 
-export type EthernetNetwork = Omit<Network, 'typeProperties'|'ipConfig'>&{
-  typeProperties?: {ethernet?: EthernetStateProperties},
-  ipConfig?: IPConfigProperties,
+export type EthernetNetwork = Omit<Network, 'typeProperties'>&{
+  typeProperties: {ethernet?: EthernetStateProperties} | null,
 };
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_utils.ts b/ash/webui/diagnostics_ui/resources/diagnostics_utils.ts
index 66e01c81..a09db2c3 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_utils.ts
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_utils.ts
@@ -79,7 +79,6 @@
     case NetworkState.kDisabled:
       return loadTimeData.getString('networkStateDisabledText');
   }
-  assertNotReached();
 }
 
 export function getLockType(lockType: LockType): string {
@@ -93,7 +92,6 @@
     case LockType.kNone:
       return '';
   }
-  assertNotReached();
 }
 
 /**
diff --git a/ash/webui/diagnostics_ui/resources/fake_data.ts b/ash/webui/diagnostics_ui/resources/fake_data.ts
index e852b22..539addf 100644
--- a/ash/webui/diagnostics_ui/resources/fake_data.ts
+++ b/ash/webui/diagnostics_ui/resources/fake_data.ts
@@ -345,7 +345,7 @@
     ipAddress: '192.168.86.197',
     gateway: '192.168.86.1',
     routingPrefix: 24,
-    nameServers: undefined,
+    nameServers: null,
   },
 };
 
@@ -444,9 +444,11 @@
 export const fakeDisconnectedWifiNetwork: WiFiNetwork = {
   state: NetworkState.kNotConnected,
   type: NetworkType.kWiFi,
+  typeProperties: null,
   observerGuid: 'wifiDisconnectedGuid',
   name: '',
   macAddress: '84:C5:A6:30:3F:31',
+  ipConfig: null,
 };
 
 export const fakePortalWifiNetwork: WiFiNetwork = {
@@ -494,9 +496,11 @@
 export const fakeConnectingEthernetNetwork: EthernetNetwork = {
   state: NetworkState.kConnecting,
   type: NetworkType.kEthernet,
+  typeProperties: null,
   observerGuid: 'ethernetGuid',
   name: 'ethernetName',
   macAddress: '81:C5:A6:30:3F:33',
+  ipConfig: null,
 };
 
 export const fakeDisconnectedEthernetNetwork: EthernetNetwork = {
@@ -510,6 +514,7 @@
   observerGuid: 'ethernetDisconnectedGuid',
   name: 'ethernetName',
   macAddress: '81:C5:A6:30:3F:32',
+  ipConfig: null,
 };
 
 export const fakeCellularNetwork: CellularNetwork = {
@@ -533,7 +538,7 @@
   ipConfig: {
     ipAddress: '192.168.86.197',
     gateway: '',
-    nameServers: undefined,
+    nameServers: null,
     routingPrefix: 0,
   },
 };
@@ -567,20 +572,21 @@
 export const fakeCellularDisabledNetwork: CellularNetwork = {
   state: NetworkState.kDisabled,
   type: NetworkType.kCellular,
+  typeProperties: null,
   observerGuid: 'cellularDisabledGuid',
   name: 'cellularName',
   macAddress: '85:C5:A6:30:3F:31',
-  ipConfig: undefined,
+  ipConfig: null,
 };
 
 export const fakeCellularDisconnectedNetwork: CellularNetwork = {
   state: NetworkState.kNotConnected,
   type: NetworkType.kCellular,
-  typeProperties: undefined,
+  typeProperties: null,
   observerGuid: 'cellularDisconnectedGuid',
   name: 'cellularName',
   macAddress: '85:C5:A6:30:3F:31',
-  ipConfig: undefined,
+  ipConfig: null,
 };
 
 export const fakeKeyboards: KeyboardInfo[] = [
diff --git a/ash/webui/diagnostics_ui/resources/input_card.ts b/ash/webui/diagnostics_ui/resources/input_card.ts
index dab3aed..43142d3 100644
--- a/ash/webui/diagnostics_ui/resources/input_card.ts
+++ b/ash/webui/diagnostics_ui/resources/input_card.ts
@@ -98,7 +98,8 @@
    * (e.g. "Bluetooth keyboard", "Internal touchpad").
    */
   private getDeviceDescription(device: KeyboardInfo|TouchDeviceInfo): string {
-    if (device.connectionType === ConnectionType.kUnknown) {
+    if (device.connectionType === ConnectionType.kUnknown ||
+        device.connectionType === ConnectionType.kUnmappedEnumField) {
       return '';
     }
     const connectionTypeString = {
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.ts b/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
index 8d4591c..065de64 100644
--- a/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
+++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.ts
@@ -142,7 +142,7 @@
        * The keyboard being tested, or null if none is being tested at the
        * moment.
        */
-      keyboard: KeyboardInfo,
+      keyboard: {type: Object},
 
       shouldDisplayDiagram: {
         type: Boolean,
@@ -232,6 +232,7 @@
       return null;
     }
     return {
+      [MechanicalLayout.kUnmappedEnumField]: null,
       [MechanicalLayout.kUnknown]: null,
       [MechanicalLayout.kAnsi]: DiagramMechanicalLayout.ANSI,
       [MechanicalLayout.kIso]: DiagramMechanicalLayout.ISO,
@@ -245,6 +246,7 @@
       return null;
     }
     return {
+      [PhysicalLayout.kUnmappedEnumField]: null,
       [PhysicalLayout.kUnknown]: null,
       [PhysicalLayout.kChromeOS]: DiagramPhysicalLayout.CHROME_OS,
       [PhysicalLayout.kChromeOSDellEnterpriseWilco]:
@@ -260,6 +262,7 @@
       return null;
     }
     return {
+      [TopRightKey.kUnmappedEnumField]: null,
       [TopRightKey.kUnknown]: null,
       [TopRightKey.kPower]: DiagramTopRightKey.POWER,
       [TopRightKey.kLock]: DiagramTopRightKey.LOCK,
diff --git a/ash/webui/eche_app_ui/eche_app_manager_unittest.cc b/ash/webui/eche_app_ui/eche_app_manager_unittest.cc
index 3b86dc6..e76faa5 100644
--- a/ash/webui/eche_app_ui/eche_app_manager_unittest.cc
+++ b/ash/webui/eche_app_ui/eche_app_manager_unittest.cc
@@ -29,6 +29,7 @@
 #include "components/prefs/testing_pref_service.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "device/bluetooth/dbus/fake_bluetooth_debug_manager_client.h"
+#include "google_apis/gaia/gaia_id.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -146,7 +147,7 @@
         SystemInfo::Builder()
             .SetDeviceName(kFakeDeviceName)
             .SetBoardName(kFakeBoardName)
-            .SetGaiaId(kFakeGaiaId)
+            .SetGaiaId(GaiaId(kFakeGaiaId))
             .SetDeviceType(kFakeDeviceType)
             .Build(),
         fake_phone_hub_manager_.get(), fake_device_sync_client_.get(),
diff --git a/ash/webui/eche_app_ui/system_info_provider_unittest.cc b/ash/webui/eche_app_ui/system_info_provider_unittest.cc
index b9db10c..bf478cd 100644
--- a/ash/webui/eche_app_ui/system_info_provider_unittest.cc
+++ b/ash/webui/eche_app_ui/system_info_provider_unittest.cc
@@ -213,7 +213,7 @@
         std::make_unique<SystemInfoProvider>(SystemInfo::Builder()
                                                  .SetDeviceName(kFakeDeviceName)
                                                  .SetBoardName(kFakeBoardName)
-                                                 .SetGaiaId(kFakeGaiaId)
+                                                 .SetGaiaId(GaiaId(kFakeGaiaId))
                                                  .SetDeviceType(kFakeDeviceType)
                                                  .SetOsVersion(kFakeOsVersion)
                                                  .SetChannel(kFakeChannel)
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
index 5738389..6f8a796f 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -455,6 +455,8 @@
     case kTilingWindowResizeUp:
     case kTilingWindowResizeDown:
       return !features::IsTilingWindowResizeEnabled();
+    case kToggleDoNotDisturb:
+      return !features::IsDoNotDisturbShortcutEnabled();
     case kToggleMouseKeys:
       return !::features::IsAccessibilityMouseKeysEnabled();
     case kToggleGeminiApp:
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
index 80085e17..2024946 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -39,7 +39,6 @@
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "chromeos/ash/components/test/ash_test_suite.h"
 #include "device/udev_linux/fake_udev_loader.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -51,7 +50,6 @@
 #include "ui/base/ime/ash/mock_input_method_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/ash/keyboard_capability.h"
 #include "ui/events/devices/device_data_manager_test_api.h"
 #include "ui/events/devices/input_device.h"
@@ -362,10 +360,6 @@
 
   // AshTestBase:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        {::features::kImprovedKeyboardShortcuts,
-         ::features::kShortcutCustomization},
-        {});
     input_method_manager_ = new TestInputMethodManager();
     input_method::InputMethodManager::Initialize(input_method_manager_);
 
@@ -475,7 +469,6 @@
 
   std::unique_ptr<AcceleratorConfigurationProvider> provider_;
   NonConfigurableActionsMap non_configurable_actions_map_;
-  base::test::ScopedFeatureList scoped_feature_list_;
   // Test global singleton. Delete is handled by InputMethodManager::Shutdown().
   raw_ptr<TestInputMethodManager, DanglingUntriaged> input_method_manager_;
   std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
index 59d25c2c..54206659 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
@@ -3,9 +3,12 @@
 // found in the LICENSE file.
 
 #include "ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h"
+
 #include <string>
 
+#include "ash/public/cpp/accelerator_actions.h"
 #include "ash/public/cpp/accelerators_util.h"
+#include "ash/public/mojom/accelerator_info.mojom-shared.h"
 #include "ash/public/mojom/accelerator_info.mojom.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/check_op.h"
@@ -560,6 +563,14 @@
             mojom::AcceleratorSubcategory::kGeneralControls,
             /*locked=*/false, mojom::AcceleratorLayoutStyle::kDefault,
             mojom::AcceleratorSource::kAsh)},
+       {AcceleratorAction::kToggleDoNotDisturb,
+        AcceleratorLayoutDetails(
+            AcceleratorAction::kToggleDoNotDisturb,
+            IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_DO_NOT_DISTURB,
+            mojom::AcceleratorCategory::kGeneral,
+            mojom::AcceleratorSubcategory::kGeneralControls, /*locked=*/false,
+            mojom::AcceleratorLayoutStyle::kDefault,
+            mojom::AcceleratorSource::kAsh)},
        {AcceleratorAction::kOpenFileManager,
         AcceleratorLayoutDetails(
             AcceleratorAction::kOpenFileManager,
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h
index 1a1d6fd..ebfce15 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h
@@ -295,6 +295,7 @@
     AcceleratorAction::kSwitchToNextUser,
     AcceleratorAction::kSwitchToPreviousUser,
     AcceleratorAction::kStartAssistant,
+    AcceleratorAction::kToggleDoNotDisturb,
 
     // General > Apps
     AcceleratorAction::kOpenFileManager,
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcut_utils.ts b/ash/webui/shortcut_customization_ui/resources/js/shortcut_utils.ts
index a286868..31ef004 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/shortcut_utils.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/shortcut_utils.ts
@@ -57,6 +57,7 @@
   'BrowserRefresh': 'refresh',
   'BrowserSearch': 'browser-search',
   'ContextMenu': 'menu',
+  'DoNotDisturb': 'do-not-disturb',
   'EmojiPicker': 'emoji-picker',
   'EnableOrToggleDictation': 'dictation-toggle',
   'KeyboardBacklightToggle': 'keyboard-brightness-toggle',
diff --git a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
index bd3d217..0fde20ee 100644
--- a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
+++ b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
@@ -191,6 +191,8 @@
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_BROWSER_SEARCH},
       {"iconLabelContextMenu",
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_CONTEXT_MENU},
+      {"iconLabelDoNotDisturb",
+       IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB},
       {"iconLabelEnableSelectToSpeak",
        IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ENABLE_SELECT_TO_SPEAK},
       {"iconLabelEnableOrToggleDictation",
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index 78425c4..ef21cf2 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -174,6 +174,18 @@
   return perf_counter_now.QuadPart;
 }
 
+#if !defined(ARCH_CPU_ARM64)
+// Returns the performance frequency.
+int64_t QPFRaw() {
+  LARGE_INTEGER perf_counter_frequency = {};
+  // According to the MSDN documentation for QueryPerformanceFrequency(), this
+  // will never fail on systems that run XP or later.
+  // https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency
+  ::QueryPerformanceFrequency(&perf_counter_frequency);
+  return perf_counter_frequency.QuadPart;
+}
+#endif
+
 bool SafeConvertToWord(int in, WORD* out) {
   CheckedNumeric<WORD> result = in;
   *out = result.ValueOrDefault(std::numeric_limits<WORD>::max());
@@ -791,6 +803,7 @@
 
   static const uint64_t tsc_initial = __rdtsc();
   static const int64_t perf_counter_initial = QPCNowRaw();
+  static const int64_t perf_counter_frequency = QPFRaw();
 
   // Make a another reading of the TSC and the performance counter every time
   // that this function is called.
@@ -806,15 +819,10 @@
   //   accurate the computed TSC frequency will be. The 50 ms value was
   //   chosen because local benchmarks show that it allows us to get a
   //   stddev of less than 1 tick/us between multiple runs.
-  // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
-  //   this will never fail on systems that run XP or later.
-  //   https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
-  LARGE_INTEGER perf_counter_frequency = {};
-  ::QueryPerformanceFrequency(&perf_counter_frequency);
   DCHECK_GE(perf_counter_now, perf_counter_initial);
   const int64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
   const double elapsed_time_seconds =
-      perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
+      perf_counter_ticks / static_cast<double>(perf_counter_frequency);
 
   constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
   if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
index 33af639..205d082cd 100644
--- a/base/time/time_win_unittest.cc
+++ b/base/time/time_win_unittest.cc
@@ -187,14 +187,21 @@
 }
 
 TEST(TimeTicks, QueryPerformanceFrequency) {
-  // Test some basic assumptions that we expect about QPC.
+  // Test some basic assumptions that we expect about QPF.
 
   LARGE_INTEGER frequency;
-  BOOL rv = QueryPerformanceFrequency(&frequency);
+  BOOL rv;
+  rv = QueryPerformanceFrequency(&frequency);
   EXPECT_EQ(TRUE, rv);
   EXPECT_GT(frequency.QuadPart, 1000000);  // Expect at least 1MHz
   printf("QueryPerformanceFrequency is %5.2fMHz\n",
          frequency.QuadPart / 1000000.0);
+
+  LARGE_INTEGER frequency_next;
+  rv = QueryPerformanceFrequency(&frequency_next);
+  EXPECT_EQ(TRUE, rv);
+  // Expect that the frequency doesn't change.
+  EXPECT_EQ(frequency_next.QuadPart, frequency.QuadPart);
 }
 
 TEST(TimeTicks, TimerPerformance) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 33a232ed..ebfaf63 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1996,6 +1996,11 @@
         # TODO(crbug.com/376641662): Fix and re-enable.
         cflags += [ "-Wno-nontrivial-memcall" ]
       }
+
+      if (is_castos) {
+        # TODO(crbug.com/383016423): Re-enable.
+        cflags += [ "-Wno-unused-private-field" ]
+      }
     }
 
     # Some builders, such as Cronet, use a different version of Clang than
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index 3b0e9702..8b82af0 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision var in //DEPS.
-  libcxx_revision = "175bf00303d0747baa158072cf7a2755ab1fbe88"
+  libcxx_revision = "ec4ac17a44a46b162c28d38f313f157f76236a6c"
 }
diff --git a/cc/tiles/image_controller.cc b/cc/tiles/image_controller.cc
index 40049fc..a3bac315 100644
--- a/cc/tiles/image_controller.cc
+++ b/cc/tiles/image_controller.cc
@@ -30,6 +30,12 @@
       notify_external_dependent_(std::move(notify_external_dependent)) {
   worker_state_ = std::make_unique<WorkerState>(std::move(origin_task_runner),
                                                 weak_ptr_factory_.GetWeakPtr());
+  // base::Unretained is safe because `worker_state_` is guaranteed to be
+  // deleted from a task posted to `worker_task_runner_` after any scheduled
+  // invocation of worker_task_ is finished (see ~ImageController).
+  worker_task_ = base::BindRepeating(
+      &ImageController::ProcessNextImageDecodeOnWorkerThread,
+      base::Unretained(worker_state_.get()));
 }
 
 ImageController::~ImageController() {
@@ -63,14 +69,13 @@
 
     // If a worker task is running, post a task and wait for its completion to
     // "flush" the queue.
-    if (worker_state_->task_state == WorkerTaskState::kRunningTask) {
+    while (worker_state_->task_state == WorkerTaskState::kRunningTask) {
       base::AutoUnlock release(worker_state_->lock);
       CompletionEvent completion_event;
       worker_task_runner_->PostTask(
           FROM_HERE, base::BindOnce(&CompletionEvent::Signal,
                                     base::Unretained(&completion_event)));
       completion_event.Wait();
-      CHECK_NE(worker_state_->task_state, WorkerTaskState::kRunningTask);
     }
 
     // Now, begin cleanup.
@@ -168,6 +173,46 @@
   return HasReadyToRunTask();
 }
 
+void ImageController::FlushDecodeTasksForTesting() {
+  TileTask::Vector external_dependents;
+  std::vector<base::OnceClosure> callbacks;
+  {
+    base::AutoLock hold(worker_state_->lock);
+    // If a worker task is running, post a task and wait for its completion to
+    // "flush" the queue.
+    while (worker_state_->task_state != WorkerTaskState::kNoTask) {
+      base::AutoUnlock release(worker_state_->lock);
+      CompletionEvent completion_event;
+      worker_task_runner_->PostTask(
+          FROM_HERE, base::BindOnce(&CompletionEvent::Signal,
+                                    base::Unretained(&completion_event)));
+      completion_event.Wait();
+    }
+    while (HasReadyToRunTask()) {
+      ImageController::ProcessNextImageDecodeWithLock(worker_state_.get());
+    }
+    for (auto& request_to_complete :
+         worker_state_->requests_needing_completion) {
+      ImageDecodeRequest& request = request_to_complete.second;
+      ImageDecodeResult result = CompleteTaskForRequest(request);
+      if (request.task && request.task->external_dependent()) {
+        external_dependents.emplace_back(
+            std::move(request.task->external_dependent()));
+      }
+      callbacks.emplace_back(
+          base::BindOnce(std::move(request.callback), request.id, result));
+    }
+    worker_state_->requests_needing_completion.clear();
+  }
+  for (auto& dependent : external_dependents) {
+    dependent->ExternalDependencyCompleted();
+    notify_external_dependent_.Run(dependent);
+  }
+  for (auto& callback : callbacks) {
+    std::move(callback).Run();
+  }
+}
+
 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
   DCHECK(!cache_ || !cache);
 
@@ -283,10 +328,9 @@
       /*can_do_hardware_accelerated_decode=*/false);
   if (is_image_lazy) {
     if (!cache_) {
-      // This should only happen in tests
-      worker_state_->origin_task_runner->PostTask(
-          FROM_HERE,
-          base::BindOnce(std::move(callback), id, ImageDecodeResult::FAILURE));
+      orphaned_decode_requests_.emplace_back(
+          id, draw_image, std::move(callback), /*task=*/nullptr,
+          /*need_unref=*/false, /*has_external_dependency=*/false);
       return id;
     }
     result = cache_->GetOutOfRasterDecodeTaskForImageAndRef(
@@ -345,11 +389,16 @@
 
   base::AutoLock hold(worker_state->lock);
   DCHECK_EQ(worker_state->task_state, WorkerTaskState::kQueuedTask);
-  worker_state->task_state = WorkerTaskState::kRunningTask;
+  ImageController::ProcessNextImageDecodeWithLock(worker_state);
+  worker_state->task_state = WorkerTaskState::kNoTask;
+}
+
+void ImageController::ProcessNextImageDecodeWithLock(
+    WorkerState* worker_state) {
+  worker_state->lock.AssertAcquired();
 
   // If we don't have any work, abort.
   if (worker_state->image_decode_queue.empty()) {
-    worker_state->task_state = WorkerTaskState::kNoTask;
     return;
   }
 
@@ -363,11 +412,8 @@
     decode_it++;
   }
   if (decode_it == worker_state->image_decode_queue.end()) {
-    worker_state->task_state = WorkerTaskState::kNoTask;
     return;
   }
-  scoped_refptr<TileTask> decode_task = decode_it->second.task;
-  ImageDecodeRequestId decode_id = decode_it->second.id;
 
   // Notify that the task will need completion. Note that there are two cases
   // where we process this. First, we might complete this task as a response to
@@ -376,6 +422,8 @@
   // after running, or the thread was already joined which means the task ran).
   // This means that we can put the decode into |requests_needing_completion_|
   // here before actually running the task.
+  scoped_refptr<TileTask> decode_task = decode_it->second.task;
+  ImageDecodeRequestId decode_id = decode_it->second.id;
   worker_state->requests_needing_completion[decode_id] =
       std::move(decode_it->second);
 
@@ -391,6 +439,8 @@
     decode_task->state().DidSchedule();
     decode_task->state().DidStart();
     {
+      base::AutoReset<WorkerTaskState> reset_state(
+          &worker_state->task_state, WorkerTaskState::kRunningTask);
       base::AutoUnlock release(worker_state->lock);
       decode_task->RunOnWorkerThread();
     }
@@ -400,14 +450,11 @@
   worker_state->origin_task_runner->PostTask(
       FROM_HERE, base::BindOnce(&ImageController::ImageDecodeCompleted,
                                 worker_state->weak_ptr, decode_id));
-
-  DCHECK_EQ(worker_state->task_state, WorkerTaskState::kRunningTask);
-  worker_state->task_state = WorkerTaskState::kNoTask;
 }
 
 void ImageController::ImageDecodeCompleted(ImageDecodeRequestId id) {
   ImageDecodedCallback callback;
-  ImageDecodeResult result = ImageDecodeResult::SUCCESS;
+  ImageDecodeResult result;
   scoped_refptr<TileTask> external_dependent;
   {
     base::AutoLock hold(worker_state_->lock);
@@ -418,31 +465,8 @@
       return;
     id = request_it->first;
     ImageDecodeRequest& request = request_it->second;
-
-    // First, Determine the status of the decode. This has to happen here, since
-    // we conditionally move from the draw image below.
-    // Also note that if we don't need an unref for a lazy decoded images, it
-    // implies that we never attempted the decode. Some of the reasons for this
-    // would be that the image is of an empty size, or if the image doesn't fit
-    // into memory. In all cases, this implies that the decode was a failure.
-    if (!request.draw_image.paint_image().IsLazyGenerated())
-      result = ImageDecodeResult::DECODE_NOT_REQUIRED;
-    else if (!request.need_unref)
-      result = ImageDecodeResult::FAILURE;
-    else
-      result = ImageDecodeResult::SUCCESS;
-
-    // If we need to unref this decode, then we have to put it into the locked
-    // images vector.
-    if (request.need_unref)
-      requested_locked_images_[id] = std::move(request.draw_image);
-
-    // If we have a task that isn't completed yet, we need to complete it.
+    result = CompleteTaskForRequest(request);
     if (request.task) {
-      if (!request.task->HasCompleted()) {
-        request.task->OnTaskCompleted();
-        request.task->DidComplete();
-      }
       external_dependent = std::move(request.task->external_dependent());
     }
 
@@ -463,6 +487,40 @@
   std::move(callback).Run(id, result);
 }
 
+ImageController::ImageDecodeResult ImageController::CompleteTaskForRequest(
+    ImageDecodeRequest& request) {
+  worker_state_->lock.AssertAcquired();
+  // First, Determine the status of the decode. This has to happen here, since
+  // we conditionally move from the draw image below.
+  // Also note that if we don't need an unref for a lazy decoded images, it
+  // implies that we never attempted the decode. Some of the reasons for this
+  // would be that the image is of an empty size, or if the image doesn't fit
+  // into memory. In all cases, this implies that the decode was a failure.
+  ImageDecodeResult result;
+  if (!request.draw_image.paint_image().IsLazyGenerated()) {
+    result = ImageDecodeResult::DECODE_NOT_REQUIRED;
+  } else if (!request.need_unref) {
+    result = ImageDecodeResult::FAILURE;
+  } else {
+    result = ImageDecodeResult::SUCCESS;
+  }
+
+  // If we need to unref this decode, then we have to put it into the locked
+  // images vector.
+  if (request.need_unref) {
+    requested_locked_images_[request.id] = std::move(request.draw_image);
+  }
+
+  // If we have a task that isn't completed yet, we need to complete it.
+  if (request.task) {
+    if (!request.task->HasCompleted()) {
+      request.task->OnTaskCompleted();
+      request.task->DidComplete();
+    }
+  }
+  return result;
+}
+
 void ImageController::GenerateTasksForOrphanedRequests() {
   base::AutoLock hold(worker_state_->lock);
   DCHECK_EQ(0u, worker_state_->image_decode_queue.size());
@@ -479,6 +537,8 @@
                                                          request.draw_image);
       request.need_unref = result.need_unref;
       request.task = result.task;
+      request.has_external_dependency =
+          result.task && !result.task->dependencies().empty();
     }
     worker_state_->image_decode_queue[request.id] = std::move(request);
   }
@@ -491,13 +551,7 @@
   if (worker_state_->task_state == WorkerTaskState::kNoTask &&
       HasReadyToRunTask()) {
     worker_state_->task_state = WorkerTaskState::kQueuedTask;
-    // base::Unretained is safe because `worker_state_` is guaranteed to be
-    // deleted from a task posted to `worker_task_runner_` after this (see
-    // ~ImageController).
-    worker_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&ImageController::ProcessNextImageDecodeOnWorkerThread,
-                       base::Unretained(worker_state_.get())));
+    worker_task_runner_->PostTask(FROM_HERE, worker_task_);
   }
 }
 
diff --git a/cc/tiles/image_controller.h b/cc/tiles/image_controller.h
index 55a572e..544205b 100644
--- a/cc/tiles/image_controller.h
+++ b/cc/tiles/image_controller.h
@@ -90,6 +90,8 @@
 
   bool HasReadyToRunTaskForTesting() const;
 
+  void FlushDecodeTasksForTesting();
+
   ImageDecodeCache* cache() const { return cache_; }
 
  protected:
@@ -147,8 +149,10 @@
   bool HasReadyToRunTask() const;
 
   static void ProcessNextImageDecodeOnWorkerThread(WorkerState* worker_state);
+  static void ProcessNextImageDecodeWithLock(WorkerState* worker_state);
 
   void ImageDecodeCompleted(ImageDecodeRequestId id);
+  ImageDecodeResult CompleteTaskForRequest(ImageDecodeRequest& request);
   void GenerateTasksForOrphanedRequests();
 
   void ScheduleImageDecodeOnWorkerIfNeeded()
@@ -164,6 +168,7 @@
   size_t image_cache_max_limit_bytes_ = 0u;
 
   std::unique_ptr<WorkerState> worker_state_;
+  base::RepeatingClosure worker_task_;
 
   const base::RepeatingCallback<void(scoped_refptr<TileTask>)>
       notify_external_dependent_;
diff --git a/cc/tiles/image_controller_unittest.cc b/cc/tiles/image_controller_unittest.cc
index 2e3c3a7..c37e895 100644
--- a/cc/tiles/image_controller_unittest.cc
+++ b/cc/tiles/image_controller_unittest.cc
@@ -497,6 +497,22 @@
   EXPECT_EQ(0, cache()->number_of_refs());
 }
 
+TEST_F(ImageControllerTest, DecodeRequestedBeforeCacheIsSet) {
+  scoped_refptr<SimpleTask> task(new SimpleTask);
+  cache()->SetTaskToUse(task);
+  controller()->SetImageDecodeCache(nullptr);
+  base::RunLoop run_loop;
+  DecodeClient decode_client;
+  controller()->QueueImageDecode(
+      image(),
+      base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client),
+                     run_loop.QuitClosure()));
+  controller()->SetImageDecodeCache(cache());
+  RunOrTimeout(&run_loop);
+  EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
+            decode_client.result());
+}
+
 TEST_F(ImageControllerTest, DispatchesDecodeCallbacksAfterCacheReset) {
   scoped_refptr<SimpleTask> task(new SimpleTask);
   cache()->SetTaskToUse(task);
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 48380d6..2167c694 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -1645,6 +1645,10 @@
   }
 }
 
+void TileManager::FlushImageControllerTasksForTesting() {
+  image_controller_.FlushDecodeTasksForTesting();  // IN-TEST
+}
+
 std::unique_ptr<Tile> TileManager::CreateTile(const Tile::CreateInfo& info,
                                               int layer_id,
                                               int source_frame_number,
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 6ec3b7b..41d9ea59 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -303,6 +303,8 @@
     return has_scheduled_tile_tasks_;
   }
 
+  void FlushImageControllerTasksForTesting();
+
   void OnRasterTaskCompleted(Tile::Id tile_id,
                              ResourcePool::InUsePoolResource resource,
                              bool was_canceled);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index bdb6faad..2fe2061 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3464,6 +3464,7 @@
 void LayerTreeHostImpl::SynchronouslyInitializeAllTiles() {
   // Only valid for the single-threaded non-scheduled/synchronous case
   // using the zero copy raster worker pool.
+  tile_manager_.FlushImageControllerTasksForTesting();  // IN-TEST
   single_thread_synchronous_task_graph_runner_->RunUntilIdle();
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 45f2179..7c17b4ac 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=133
 MINOR=0
-BUILD=6909
+BUILD=6910
 PATCH=0
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 1bcf93e..834eb48 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -234,6 +234,7 @@
   "junit/src/org/chromium/chrome/browser/findinpage/FindToolbarManagerTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/ChildAccountStatusSupplierTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunAppRestrictionInfoTest.java",
+  "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFilterTouchUnitTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java",
   "junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index 9140dc9..fd33800 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -667,19 +667,24 @@
                                             for (ScrollListener listener : mScrollListeners) {
                                                 listener.onScrolled(dx, dy);
                                             }
-                                            final boolean restored =
-                                                    mCoordinator
-                                                                    .getHybridListRenderer()
-                                                                    .getListLayoutHelper()
-                                                                    .findFirstVisibleItemPosition()
-                                                            >= mPositionToRestore;
-                                            if (mPositionToRestore != RecyclerView.NO_POSITION
+
+                                            // Null if the stream has not been binded yet.
+                                            if (mCoordinator.getHybridListRenderer() != null
+                                                    && mPositionToRestore
+                                                            != RecyclerView.NO_POSITION
                                                     && mGetRestoringStateSupplier.get()
-                                                            == RestoringState.WAITING_TO_RESTORE
-                                                    && restored) {
-                                                mGetRestoringStateSupplier.set(
-                                                        RestoringState.RESTORED);
-                                                mPositionToRestore = RecyclerView.NO_POSITION;
+                                                            == RestoringState.WAITING_TO_RESTORE) {
+                                                final boolean restored =
+                                                        mCoordinator
+                                                                        .getHybridListRenderer()
+                                                                        .getListLayoutHelper()
+                                                                        .findFirstVisibleItemPosition()
+                                                                >= mPositionToRestore;
+                                                if (restored) {
+                                                    mGetRestoringStateSupplier.set(
+                                                            RestoringState.RESTORED);
+                                                    mPositionToRestore = RecyclerView.NO_POSITION;
+                                                }
                                             }
                                         });
                     }
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 b3c210b..0249226 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -590,11 +590,6 @@
                                         : null);
         mBackPressManager.setFallbackOnBackPressed(
                 () -> {
-                    if (BackPressManager.correctTabNavigationOnFallback()) {
-                        if (getToolbarManager() != null && getToolbarManager().back()) {
-                            return;
-                        }
-                    }
                     minimizeAppAndCloseTabOnBackPress(getActivityTab());
                 });
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 27e3504..011a7a64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -621,7 +621,8 @@
 
             mBottomContainer.initialize(
                     getBrowserControlsManager(),
-                    getWindowAndroid().getApplicationBottomInsetSupplier());
+                    getWindowAndroid().getApplicationBottomInsetSupplier(),
+                    getEdgeToEdgeSupplier());
 
             ShareDelegate shareDelegate =
                     new ShareDelegateImpl(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifier.java
index feb90cf..c985ef8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifier.java
@@ -16,6 +16,7 @@
 
 import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
 import androidx.browser.auth.AuthTabIntent;
 import androidx.browser.auth.ExperimentalAuthTab;
 import androidx.browser.customtabs.CustomTabsService;
@@ -23,6 +24,7 @@
 import org.chromium.base.CallbackController;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
@@ -53,6 +55,7 @@
     private final Activity mActivity;
     private final ActivityLifecycleDispatcher mLifecycleDispatcher;
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
+    private final CustomTabActivityTabProvider mTabProvider;
     private final String mRedirectHost;
     private final String mRedirectPath;
 
@@ -78,41 +81,58 @@
             CustomTabActivityTabProvider customTabActivityTabProvider) {
         mLifecycleDispatcher = lifecycleDispatcher;
         mIntentDataProvider = intentDataProvider;
+        mTabProvider = customTabActivityTabProvider;
         mActivity = activity;
         mRedirectHost = mIntentDataProvider.getAuthRedirectHost();
         mRedirectPath = mIntentDataProvider.getAuthRedirectPath();
         mLifecycleDispatcher.register(this);
 
-        // TODO(b/358167556): Do this in a background to avoid potential ANR from system IPC call.
-        mVerifiedByAndroid =
-                android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S
-                        && isApprovedDomain(mRedirectHost);
-        mStatus = mVerifiedByAndroid ? VerificationStatus.SUCCESS : VerificationStatus.PENDING;
-        mActivityResult = AuthTabIntent.RESULT_OK;
+        mStatus = VerificationStatus.PENDING;
+        mVerifiedByAndroid = false;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            new AsyncTask<Boolean>() {
+                @Override
+                protected Boolean doInBackground() {
+                    return isApprovedDomain(mRedirectHost);
+                }
 
-        if (shouldRunOriginVerifier()) {
+                @Override
+                protected void onPostExecute(Boolean result) {
+                    mVerifiedByAndroid = result;
+                    if (result) mStatus = VerificationStatus.SUCCESS;
+                }
+            }.executeWithTaskTraits(TaskTraits.UI_DEFAULT);
+        }
+        mActivityResult = AuthTabIntent.RESULT_OK;
+        maybeInitOriginVerifier();
+    }
+
+    private boolean maybeInitOriginVerifier() {
+        if (!shouldRunOriginVerifier()) return false;
+
+        if (mOriginVerifier == null) {
             WebContents webContents =
-                    customTabActivityTabProvider.getTab() != null
-                            ? customTabActivityTabProvider.getTab().getWebContents()
-                            : null;
+                    mTabProvider.getTab() != null ? mTabProvider.getTab().getWebContents() : null;
             mOriginVerifier =
                     ChromeOriginVerifierFactory.create(
                             mIntentDataProvider.getClientPackageName(),
                             CustomTabsService.RELATION_HANDLE_ALL_URLS,
                             webContents);
         }
+        return true;
     }
 
-    private boolean shouldRunOriginVerifier() {
+    @VisibleForTesting
+    boolean shouldRunOriginVerifier() {
         return !(mVerifiedByAndroid || mRedirectHost == null || mRedirectPath == null);
     }
 
     @Override
     public void onFinishNativeInitialization() {
-        if (!shouldRunOriginVerifier()) return;
-
         if (sDelayVerificationForTesting) return;
 
+        if (!maybeInitOriginVerifier()) return;
+
         // Start verification against the redirect URL
         Uri redirectUri =
                 new Uri.Builder()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java
index 4f770a6..dbd51b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java
@@ -358,14 +358,6 @@
         }
 
         if (memberRole == MemberRole.OWNER) {
-            int insertionIndex = getMenuItemIndex(itemList, R.id.manage_sharing);
-            itemList.add(
-                    insertionIndex,
-                    BrowserUiListMenuUtils.buildMenuListItem(
-                            R.string.ungroup_tab_group_menu_item,
-                            R.id.ungroup_tab,
-                            R.drawable.ic_ungroup_tabs_24dp,
-                            /* enabled= */ true));
             itemList.add(getDivider());
             itemList.add(
                     BrowserUiListMenuUtils.buildMenuListItem(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index d7207d1..a5fd2cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -35,7 +35,6 @@
 import org.chromium.chrome.browser.KeyboardShortcuts;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
-import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browserservices.InstalledWebappDataRegister;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabProfileType;
@@ -876,11 +875,6 @@
     }
 
     protected boolean handleBackPressed() {
-        if (BackPressManager.correctTabNavigationOnFallback()) {
-            if (getToolbarManager() != null && getToolbarManager().back()) {
-                return true;
-            }
-        }
         return getCustomTabActivityNavigationController().navigateOnBack();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
index 7e84dd6..5a23955 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -30,7 +30,6 @@
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.back_press.MinimizeAppAndCloseTabBackPressHandler;
 import org.chromium.chrome.browser.back_press.MinimizeAppAndCloseTabBackPressHandler.MinimizeAppAndCloseTabType;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
@@ -232,11 +231,6 @@
                         != 0;
         RecordUserAction.record("CustomTabs.SystemBack");
         if (mTabProvider.getTab() == null) return false;
-        if (BackPressManager.correctTabNavigationOnFallback()) {
-            if (mTabProvider.getTab().canGoBack()) {
-                return false;
-            }
-        }
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_BEFORE_UNLOAD)
                 && mTabController.onlyOneTabRemaining()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index 583d8fbf5..6a83fde 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -4,17 +4,22 @@
 
 package org.chromium.chrome.browser.firstrun;
 
+import static androidx.annotation.VisibleForTesting.PRIVATE;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.graphics.Color;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.view.MotionEvent;
 import android.view.View;
 
 import androidx.annotation.CallSuper;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
 import androidx.viewpager2.widget.ViewPager2;
 
@@ -30,6 +35,7 @@
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.metrics.UmaUtils;
+import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.signin.SigninCheckerProvider;
@@ -174,6 +180,19 @@
 
     private static boolean sIsAnimationDisabled;
 
+    /** Prevents Tapjacking on T-. See crbug.com/1430867 */
+    private static final boolean sPreventTouches =
+            Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU;
+
+    /**
+     * The last MotionEvent object blocked due to the activity being in paused state. We're
+     * interested in MotionEvent#ACTION_DOWN which is likely the very first event received when
+     * multi-window mode is entered. We inject this one after the activity is resumed (or it regains
+     * the focus) in order to recover the corresponding user gesture which otherwise would have gone
+     * missing.
+     */
+    private MotionEvent mBlockedEvent;
+
     private boolean mPostNativeAndPolicyPagesCreated;
 
     /** Use {@link Promise#isFulfilled()} to verify whether the native has been initialized. */
@@ -554,6 +573,38 @@
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (sPreventTouches && shouldPreventTouch(ev)) {
+            // Discard the events which may be trickling down from an overlay activity above.
+            return true;
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @VisibleForTesting(otherwise = PRIVATE)
+    boolean shouldPreventTouch(MotionEvent ev) {
+        if (ApplicationStatus.getStateForActivity(this) == ActivityState.RESUMED) return false;
+        mBlockedEvent = ev;
+        return true;
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        // No need to do the following from Q and onward where multi-resume state is supported
+        // in split screen mode.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return;
+
+        if (hasFocus
+                && mBlockedEvent != null
+                && MultiWindowUtils.getInstance().isInMultiWindowMode(this)) {
+            mBlockedEvent.setAction(MotionEvent.ACTION_DOWN);
+            super.dispatchTouchEvent(mBlockedEvent); // Inject the blocked event
+            mBlockedEvent = null;
+        }
+    }
+
+    @Override
     public int getSecondaryActivity() {
         return SecondaryActivity.FIRST_RUN;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyController.java
index 7f8afd9e..417a3797 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyController.java
@@ -13,6 +13,8 @@
 
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
 import org.chromium.base.version_info.Channel;
 import org.chromium.base.version_info.VersionConstants;
 import org.chromium.build.BuildConfig;
@@ -38,12 +40,14 @@
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.ui.modelutil.PropertyModel;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 /** Class that controls and manages when and if surveys should be shown. */
 public class PrivacySandboxSurveyController {
     private enum PrivacySandboxSurveyType {
+        UNKNOWN,
         CCT_EEA_ACCEPTED,
         CCT_EEA_DECLINED,
         CCT_EEA_CONTROL,
@@ -136,6 +140,58 @@
                 profile);
     }
 
+    private boolean shouldLaunchAdsCctSurvey(String appId) {
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY)) {
+            // TODO(crbug.com/379930582): Emit a histogram detailing that the feature was disabled.
+            return false;
+        }
+        String paramAdsNoticeAppId =
+                ChromeFeatureList.getFieldTrialParamByFeature(
+                        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY, "app-id");
+        if (!paramAdsNoticeAppId.isEmpty() && !paramAdsNoticeAppId.equals(appId)) {
+            // TODO(crbug.com/379930582): Emit a histogram detailing an app-id mismatch.
+            return false;
+        }
+        return true;
+    }
+
+    // Schedules the launch of an Ads CCT Treatment survey.
+    // Should only be invoked after the closure of either the EEA or ROW notice.
+    public void scheduleAdsCctTreatmentSurveyLaunch(String appId) {
+        if (!shouldLaunchAdsCctSurvey(appId)) {
+            return;
+        }
+        PostTask.postDelayedTask(
+                TaskTraits.UI_DEFAULT,
+                () -> maybeLaunchAdsCctTreatmentSurvey(),
+                /*20 seconds*/ 20000);
+    }
+
+    // Determines the appropriate survey to launch based on the user interaction with either the EEA
+    // consent or the ROW notice and launches the survey.
+    private void maybeLaunchAdsCctTreatmentSurvey() {
+        PrivacySandboxSurveyType surveyType = PrivacySandboxSurveyType.UNKNOWN;
+        PrefService prefs = UserPrefs.get(mProfile);
+        // Check if the EEA consent was shown.
+        if (prefs.getBoolean(Pref.PRIVACY_SANDBOX_M1_CONSENT_DECISION_MADE)) {
+            if (prefs.getBoolean(Pref.PRIVACY_SANDBOX_M1_TOPICS_ENABLED)) {
+                surveyType = PrivacySandboxSurveyType.CCT_EEA_ACCEPTED;
+            } else {
+                surveyType = PrivacySandboxSurveyType.CCT_EEA_DECLINED;
+            }
+            // Check if the ROW notice was acknowledged.
+        } else if (prefs.getBoolean(Pref.PRIVACY_SANDBOX_M1_ROW_NOTICE_ACKNOWLEDGED)) {
+            surveyType = PrivacySandboxSurveyType.CCT_ROW_ACKNOWLEDGED;
+        }
+
+        if (surveyType == PrivacySandboxSurveyType.UNKNOWN) {
+            // TODO(crbug.com/379930582): Emit a histogram detailing that somehow the client did not
+            // interact with a consent/notice.
+            return;
+        }
+        showSurvey(surveyType);
+    }
+
     private SurveyClient constructSurveyClient(PrivacySandboxSurveyType survey) {
         SurveyConfig surveyConfig = SurveyConfig.get(sSurveyTriggers.get(survey));
         if (surveyConfig == null) {
@@ -165,17 +221,16 @@
                 mActivity.getResources(), mMessage);
     }
 
-    private void maybeLaunchSurvey(PrivacySandboxSurveyType survey) {
-        SurveyClient surveyClient = constructSurveyClient(survey);
+    private void showSurvey(PrivacySandboxSurveyType surveyType) {
+        SurveyClient surveyClient = constructSurveyClient(surveyType);
         if (surveyClient == null) {
             return;
         }
-
         surveyClient.showSurvey(
                 mActivity,
                 mActivityLifecycleDispatcher,
-                getSentimentSurveyPsb(),
-                getSentimentSurveyPsd());
+                populateSurveyPsb(surveyType),
+                populateSurveyPsd(surveyType));
     }
 
     private void createTabObserver(ActivityTabProvider activityTabProvider) {
@@ -188,7 +243,7 @@
                         }
                         if (UrlUtilities.isNtpUrl(tab.getUrl())) {
                             if (mHasSeenNtp) {
-                                maybeLaunchSurvey(PrivacySandboxSurveyType.SENTIMENT_SURVEY);
+                                showSurvey(PrivacySandboxSurveyType.SENTIMENT_SURVEY);
                             }
                             mHasSeenNtp = true;
                         }
@@ -196,6 +251,20 @@
                 };
     }
 
+    private Map<String, Boolean> populateSurveyPsb(PrivacySandboxSurveyType surveyType) {
+        if (surveyType == PrivacySandboxSurveyType.SENTIMENT_SURVEY) {
+            return getSentimentSurveyPsb();
+        }
+        return Collections.emptyMap();
+    }
+
+    private Map<String, String> populateSurveyPsd(PrivacySandboxSurveyType surveyType) {
+        if (surveyType == PrivacySandboxSurveyType.SENTIMENT_SURVEY) {
+            return getSentimentSurveyPsd();
+        }
+        return Collections.emptyMap();
+    }
+
     @VisibleForTesting
     public Map<String, Boolean> getSentimentSurveyPsb() {
         Map<String, Boolean> psb = new HashMap<>();
@@ -243,8 +312,6 @@
     }
 
     private static boolean shouldInitializeForActiveStudy() {
-        // TODO(crbug.com/379930582): Add a check for CCT surveys
-
         // Sentiment survey should be checked last as it should always be on.
         if (!ChromeFeatureList.isEnabled(ChromeFeatureList.PRIVACY_SANDBOX_SENTIMENT_SURVEY)) {
             emitFeatureDisabledHistogram(PrivacySandboxSurveyType.SENTIMENT_SURVEY);
@@ -285,7 +352,7 @@
         }
     }
 
-    /** Set whether to trigger the start up survey in tests. */
+    // Set whether to trigger the start up survey in tests.
     public static void setEnableForTesting() {
         sEnableForTesting = true;
         ResettersForTesting.register(() -> sEnableForTesting = false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index a1e7b0f..bec9b49 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -50,8 +50,8 @@
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.data_sharing.DataSharingNotificationManager;
 import org.chromium.chrome.browser.data_sharing.DataSharingServiceFactory;
-import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
 import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupsDelegate;
+import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
 import org.chromium.chrome.browser.data_sharing.InstantMessageDelegateFactory;
 import org.chromium.chrome.browser.data_sharing.InstantMessageDelegateImpl;
 import org.chromium.chrome.browser.desktop_site.DesktopSiteSettingsIphController;
@@ -172,6 +172,7 @@
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.dragdrop.DragDropGlobalState;
 import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.url.GURL;
 
 import java.util.function.BooleanSupplier;
 import java.util.function.Function;
@@ -1310,8 +1311,8 @@
             }
 
             @Override
-            public void openLearnMoreSharedTabGroupsPage(Context context, String url) {
-                CustomTabActivity.showInfoPage(context, url);
+            public void openLearnMoreSharedTabGroupsPage(Context context, GURL gurl) {
+                CustomTabActivity.showInfoPage(context, gurl.getSpec());
             }
         };
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomContainer.java
index 2bbd348..8799fe4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/BottomContainer.java
@@ -12,7 +12,10 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.lifetime.Destroyable;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController;
+import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.ui.base.ViewportInsets;
 
@@ -34,6 +37,8 @@
     /** The desired Y offset if unaffected by other UI. */
     private float mBaseYOffset;
 
+    private ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeControllerSupplier;
+
     /** Constructor for XML inflation. */
     public BottomContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -43,11 +48,13 @@
     /** Initializes this container. */
     public void initialize(
             BrowserControlsStateProvider browserControlsStateProvider,
-            ApplicationViewportInsetSupplier viewportInsetSupplier) {
+            ApplicationViewportInsetSupplier viewportInsetSupplier,
+            ObservableSupplier<EdgeToEdgeController> edgeToEdgeControllerSupplier) {
         mBrowserControlsStateProvider = browserControlsStateProvider;
         mBrowserControlsStateProvider.addObserver(this);
         mViewportInsetSupplier = viewportInsetSupplier;
         mViewportInsetSupplier.addObserver(mInsetObserver);
+        mEdgeToEdgeControllerSupplier = edgeToEdgeControllerSupplier;
         setTranslationY(mBaseYOffset);
     }
 
@@ -67,6 +74,7 @@
 
     @Override
     public void setTranslationY(float y) {
+
         mBaseYOffset = y;
 
         float offsetFromControls =
@@ -74,9 +82,20 @@
                         - mBrowserControlsStateProvider.getBottomControlsHeight();
         offsetFromControls -= mViewportInsetSupplier.get().viewVisibleHeightInset;
 
-        // Sit on top of either the bottom sheet or the bottom toolbar depending on which is larger
-        // (offsets are negative).
-        super.setTranslationY(mBaseYOffset + offsetFromControls);
+        if (SnackbarManager.isFloatingSnackbarEnabled()) {
+            int bottomInset =
+                    mEdgeToEdgeControllerSupplier != null
+                                    && mEdgeToEdgeControllerSupplier.get() != null
+                            ? mEdgeToEdgeControllerSupplier.get().getBottomInsetPx()
+                            : 0;
+
+            // The floating snackbar shouldn't scroll into the bottom inset.
+            super.setTranslationY(Math.min(mBaseYOffset + offsetFromControls, -bottomInset));
+        } else {
+            // Sit on top of either the bottom sheet or the bottom toolbar depending on which is
+            // larger (offsets are negative).
+            super.setTranslationY(mBaseYOffset + offsetFromControls);
+        }
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java
index d9d00d8bf..5f8b3b7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java
@@ -387,6 +387,34 @@
 
     @Test
     @MediumTest
+    @EnableFeatures(ChromeFeatureList.FLOATING_SNACKBAR)
+    public void testFloatingSnackbar() throws InterruptedException {
+        activateFeatureToEdge();
+        optOutOfToEdge();
+        var snackbarManager = mActivity.getSnackbarManager();
+        snackbarManager.setEdgeToEdgeSupplier(mEdgeToEdgeController);
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    snackbarManager.showSnackbar(
+                            Snackbar.make(
+                                    "Test",
+                                    new SnackbarManager.SnackbarController() {},
+                                    Snackbar.TYPE_PERSISTENT,
+                                    Snackbar.UMA_TEST_SNACKBAR));
+                });
+
+        UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
+
+        var adjuster =
+                snackbarManager
+                        .getCurrentSnackbarViewForTesting()
+                        .getEdgeToEdgePadAdjusterForTesting();
+        Assert.assertNull(
+                "Pad Adjuster is not used in the floating snackbar and should be null.", adjuster);
+    }
+
+    @Test
+    @MediumTest
     @DisabledTest(message = "crbug.com/41492043")
     public void testUnfold() {
         activateFeatureToEdge();
diff --git a/chrome/android/junit/AndroidManifest.xml b/chrome/android/junit/AndroidManifest.xml
index 39a375223..a822a435 100644
--- a/chrome/android/junit/AndroidManifest.xml
+++ b/chrome/android/junit/AndroidManifest.xml
@@ -15,6 +15,8 @@
     <activity android:name="androidx.fragment.app.FragmentActivity" />
     <activity android:name="org.chromium.ui.base.TestActivity"
               android:theme="@style/Theme.Chromium.Activity"/>
+    <activity android:name="org.chromium.chrome.browser.firstrun.FirstRunActivity"
+              android:theme="@style/Theme.Chromium.Activity"/>
     <activity android:name="org.chromium.chrome.browser.ChromeTabbedActivity"
             android:theme="@style/Theme.Chromium.TabbedMode"
             android:exported="true"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifierTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifierTest.java
index 6a0dd5a..93e98e0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifierTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/AuthTabVerifierTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -16,9 +17,14 @@
 import static org.chromium.chrome.browser.flags.ChromeFeatureList.sCctAuthTabEnableHttpsRedirectsVerificationTimeoutMs;
 
 import android.app.Activity;
+import android.content.Context;
+import android.content.pm.verify.domain.DomainVerificationManager;
+import android.content.pm.verify.domain.DomainVerificationUserState;
+import android.os.Build;
 
 import androidx.browser.auth.AuthTabIntent;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -31,6 +37,7 @@
 import org.robolectric.annotation.LooperMode;
 import org.robolectric.shadows.ShadowSystemClock;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.task.test.ShadowPostTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.HistogramWatcher;
@@ -44,6 +51,8 @@
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.url.GURL;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 /** Tests for {@link AuthTabVerifier}. */
@@ -64,12 +73,15 @@
     @Mock ChromeOriginVerifier mOriginVerifier;
     @Mock CustomTabActivityTabProvider mActivityTabProvider;
     @Mock Activity mActivity;
+    @Mock Context mContext;
+    @Mock DomainVerificationManager mDomainVerificationManager;
+    @Mock DomainVerificationUserState mDomainVerificationUserState;
 
     private AuthTabVerifier mDelegate;
     private Runnable mDelayedTask;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         ShadowPostTask.setTestImpl((taskTraits, task, delay) -> mDelayedTask = task);
 
         when(mIntentDataProvider.getAuthRedirectHost()).thenReturn(REDIRECT_HOST);
@@ -82,6 +94,11 @@
                         mActivity, mLifecycleDispatcher, mIntentDataProvider, mActivityTabProvider);
     }
 
+    @After
+    public void tearDown() {
+        ShadowSystemClock.reset();
+    }
+
     void simulateVerificationResultFromNetwork(String url, boolean success) {
         // Simulate the OriginVerifier comes back with the verification result.
         ArgumentCaptor<OriginVerificationListener> verifyCallback =
@@ -204,4 +221,32 @@
         verify(mActivity).finish();
         histograms.assertExpected();
     }
+
+    @Test
+    @Config(sdk = Build.VERSION_CODES.S)
+    public void androidAppLinksApiInBackground() throws Exception {
+        ContextUtils.initApplicationContextForTests(mContext);
+
+        Map<String, Integer> hostToStateMap = new HashMap<>();
+        hostToStateMap.put(REDIRECT_HOST, DomainVerificationUserState.DOMAIN_STATE_VERIFIED);
+        when(mContext.getSystemService(DomainVerificationManager.class))
+                .thenReturn(mDomainVerificationManager);
+        when(mDomainVerificationManager.getDomainVerificationUserState(anyString()))
+                .thenReturn(mDomainVerificationUserState);
+        when(mDomainVerificationUserState.getHostToStateMap()).thenReturn(hostToStateMap);
+
+        // Restart AuthTabVerifier with AppLink activated.
+        mDelegate =
+                new AuthTabVerifier(
+                        mActivity, mLifecycleDispatcher, mIntentDataProvider, mActivityTabProvider);
+
+        assertTrue(mDelegate.shouldRunOriginVerifier());
+        mDelayedTask.run();
+        mDelayedTask.run();
+        assertFalse("Android AppLink should be completed", mDelegate.shouldRunOriginVerifier());
+
+        // Verify that Chrome DAL verification is never executed.
+        mDelegate.onFinishNativeInitialization();
+        verify(mOriginVerifier, never()).start(any(), any());
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
index 73b374bb..284cc86 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
@@ -247,21 +247,11 @@
         mTabGroupContextMenuCoordinator.buildCollaborationMenuItems(modelList, MemberRole.OWNER);
 
         // Assert: verify number of items in the model list.
-        assertEquals("Number of items in the list menu is incorrect", 8, modelList.size());
+        assertEquals("Number of items in the list menu is incorrect", 7, modelList.size());
 
-        // Assert: verify normal menu items.
-        verifyNormalListItems(modelList, 5);
-
-        // Assert: verify collaboration menu items.
-        assertEquals(
-                R.id.manage_sharing,
-                modelList.get(3).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(
-                R.id.recent_activity,
-                modelList.get(4).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(
-                R.id.delete_shared_group,
-                modelList.get(7).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        // Assert: verify collaboration menu items; shared group should not have the option to
+        // ungroup.
+        verifyCollaborationListItems(modelList, MemberRole.OWNER);
     }
 
     @Test
@@ -283,24 +273,9 @@
         // Assert: verify number of items in the model list.
         assertEquals("Number of items in the list menu is incorrect", 7, modelList.size());
 
-        // Assert: verify normal and collaboration menu items; members should not have the option to
+        // Assert: verify collaboration menu items; shared group should not have the option to
         // ungroup.
-        assertEquals(ListMenuItemType.DIVIDER, modelList.get(0).type);
-        assertEquals(
-                R.id.open_new_tab_in_group,
-                modelList.get(1).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(
-                R.id.manage_sharing,
-                modelList.get(2).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(
-                R.id.recent_activity,
-                modelList.get(3).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(
-                R.id.close_tab_group,
-                modelList.get(4).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-        assertEquals(ListMenuItemType.DIVIDER, modelList.get(5).type);
-        assertEquals(
-                R.id.leave_group, modelList.get(6).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        verifyCollaborationListItems(modelList, MemberRole.MEMBER);
     }
 
     @Test
@@ -417,9 +392,36 @@
                 modelList.get(1).model.get(ListMenuItemProperties.MENU_ITEM_ID));
         assertEquals(
                 R.id.ungroup_tab, modelList.get(2).model.get(ListMenuItemProperties.MENU_ITEM_ID));
-
         assertEquals(
                 R.id.close_tab_group,
                 modelList.get(closeGroupPosition).model.get(ListMenuItemProperties.MENU_ITEM_ID));
     }
+
+    private void verifyCollaborationListItems(ModelList modelList, @MemberRole int memberRole) {
+        assertEquals(ListMenuItemType.DIVIDER, modelList.get(0).type);
+        assertEquals(
+                R.id.open_new_tab_in_group,
+                modelList.get(1).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        assertEquals(
+                R.id.manage_sharing,
+                modelList.get(2).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        assertEquals(
+                R.id.recent_activity,
+                modelList.get(3).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        assertEquals(
+                R.id.close_tab_group,
+                modelList.get(4).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        assertEquals(ListMenuItemType.DIVIDER, modelList.get(5).type);
+
+        // Verify delete group or leave group depending on the member role.
+        if (memberRole == MemberRole.OWNER) {
+            assertEquals(
+                    R.id.delete_shared_group,
+                    modelList.get(6).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        } else if (memberRole == MemberRole.MEMBER) {
+            assertEquals(
+                    R.id.leave_group,
+                    modelList.get(6).model.get(ListMenuItemProperties.MENU_ITEM_ID));
+        }
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFilterTouchUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFilterTouchUnitTest.java
new file mode 100644
index 0000000..5837ca6e
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFilterTouchUnitTest.java
@@ -0,0 +1,78 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.firstrun;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+
+import android.view.MotionEvent;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
+
+/** Tests {@link FirstActivity} filters touch events from overlay activity. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Batch(Batch.UNIT_TESTS)
+@CommandLineFlags.Add({
+    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+    ChromeSwitches.DISABLE_NATIVE_INITIALIZATION
+})
+@EnableFeatures(ChromeFeatureList.CCT_REPORT_PRERENDER_EVENTS)
+public class FirstRunFilterTouchUnitTest {
+    @Rule
+    public ActivityScenarioRule<FirstRunActivity> mActivityScenarioRule =
+            new ActivityScenarioRule<>(FirstRunActivity.class);
+
+    @Mock private MotionEvent mMotionEvent;
+
+    private FirstRunActivity mActivity;
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityScenarioRule.getScenario().onActivity((activity) -> mActivity = activity);
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    @SmallTest
+    public void testShouldPreventTouch() {
+        ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
+        assertFalse("Events should be accepted.", mActivity.shouldPreventTouch(mMotionEvent));
+        ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
+        assertTrue("Events should be discarded.", mActivity.shouldPreventTouch(mMotionEvent));
+    }
+
+    @Test
+    @SmallTest
+    public void testInjectMissingEventInMultiWindowMode() {
+        ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
+        assertTrue("Events should be consumed", mActivity.dispatchTouchEvent(mMotionEvent));
+
+        MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true);
+        ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
+        mActivity.onWindowFocusChanged(/* hasFocus= */ true);
+        verify(mMotionEvent, atLeast(1)).setAction(eq(MotionEvent.ACTION_DOWN));
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyControllerTest.java
index 1e3614c..67b0670 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/privacy_sandbox/PrivacySandboxSurveyControllerTest.java
@@ -27,6 +27,9 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.task.TaskTraits;
+import org.chromium.base.task.test.ShadowPostTask;
+import org.chromium.base.task.test.ShadowPostTask.TestImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features;
 import org.chromium.base.test.util.HistogramWatcher;
@@ -51,9 +54,13 @@
 import org.chromium.components.user_prefs.UserPrefsJni;
 import org.chromium.url.GURL;
 
+import java.util.Collections;
+
 /** Unit tests for {@link PrivacySandboxSurveyController} */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(
+        manifest = Config.NONE,
+        shadows = {ShadowPostTask.class})
 @Features.EnableFeatures(ChromeFeatureList.PRIVACY_SANDBOX_SENTIMENT_SURVEY)
 public class PrivacySandboxSurveyControllerTest {
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -71,7 +78,13 @@
     @Mock IdentityServicesProvider mIdentityServicesProvider;
     @Mock IdentityManager mIdentityManager;
 
-    private static final String SENTIMENT_SURVEY_TRIGGER_ID = "privacy-sandbox-sentiment-survey";
+    private static final String SENTIMENT_SURVEY_TRIGGER = "privacy-sandbox-sentiment-survey";
+    private static final String CCT_ADS_NOTICE_EEA_ACCEPTED_TRIGGER =
+            "privacy-sandbox-cct-ads-notice-eea-accepted";
+    private static final String CCT_ADS_NOTICE_EEA_DECLINED_TRIGGER =
+            "privacy-sandbox-cct-ads-notice-eea-declined";
+    private static final String CCT_ADS_NOTICE_ROW_ACKNOWLEDGED_TRIGGER =
+            "privacy-sandbox-cct-ads-notice-row-acknowledged";
 
     @Before
     public void before() {
@@ -87,11 +100,23 @@
         when(IdentityServicesProvider.get().getIdentityManager(mProfile))
                 .thenReturn(mIdentityManager);
         when(mIdentityManager.hasPrimaryAccount(ConsentLevel.SIGNIN)).thenReturn(false);
+        ShadowPostTask.setTestImpl(
+                new TestImpl() {
+                    @Override
+                    public void postDelayedTask(
+                            @TaskTraits int taskTraits, Runnable task, long delay) {
+                        // Run task immediately.
+                        task.run();
+                    }
+                });
     }
 
     @Test
     public void surveyControllerInitializes() {
-        setTestSurveyConfigForTrigger(SENTIMENT_SURVEY_TRIGGER_ID, new String[0], new String[0]);
+        setTestSurveyConfigForTrigger(
+                SENTIMENT_SURVEY_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
         PrivacySandboxSurveyController controller =
                 PrivacySandboxSurveyController.initialize(
                         mTabModelSelector,
@@ -120,8 +145,11 @@
 
     @Test
     @Features.DisableFeatures(ChromeFeatureList.PRIVACY_SANDBOX_SENTIMENT_SURVEY)
-    public void surveyControllerDoesNotInitalizeWhenFeatureDisabled() {
-        setTestSurveyConfigForTrigger(SENTIMENT_SURVEY_TRIGGER_ID, new String[0], new String[0]);
+    public void surveyControllerDoesNotInitalizeWhenSentimentFeatureDisabled() {
+        setTestSurveyConfigForTrigger(
+                SENTIMENT_SURVEY_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
         HistogramWatcher histogramWatcher =
                 HistogramWatcher.newSingleRecordWatcher(
                         "PrivacySandbox.SentimentSurvey.Status",
@@ -139,8 +167,11 @@
     }
 
     @Test
-    public void surveyControllerLaunchesSurvey() {
-        setTestSurveyConfigForTrigger(SENTIMENT_SURVEY_TRIGGER_ID, new String[0], new String[0]);
+    public void surveyControllerLaunchesSentimentSurvey() {
+        setTestSurveyConfigForTrigger(
+                SENTIMENT_SURVEY_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
         MockTab startTab = new MockTab(0, mProfile);
         mActivityTabProvider.set(startTab);
         PrivacySandboxSurveyController controller =
@@ -198,8 +229,11 @@
     }
 
     @Test
-    public void surveyControllerDoesNotTriggerSurveyIfTabIsNull() {
-        setTestSurveyConfigForTrigger(SENTIMENT_SURVEY_TRIGGER_ID, new String[0], new String[0]);
+    public void surveyControllerDoesNotTriggerSentimentSurveyIfTabIsNull() {
+        setTestSurveyConfigForTrigger(
+                SENTIMENT_SURVEY_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
         MockTab startTab = new MockTab(0, mProfile);
         mActivityTabProvider.set(startTab);
         PrivacySandboxSurveyController controller =
@@ -320,4 +354,178 @@
 
         controller.destroy();
     }
+
+    @Test
+    @Features.EnableFeatures({
+        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY
+                + ":app-id/com.google.android.googlequicksearchbox"
+    })
+    public void surveyControllerLaunchsAdsCctSurveyForEeaAccepted() {
+        setTestSurveyConfigForTrigger(
+                CCT_ADS_NOTICE_EEA_ACCEPTED_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_CONSENT_DECISION_MADE))
+                .thenReturn(true);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_TOPICS_ENABLED)).thenReturn(true);
+        controller.scheduleAdsCctTreatmentSurveyLaunch("com.google.android.googlequicksearchbox");
+        verify(mSurveyClient)
+                .showSurvey(
+                        mActivity,
+                        mActivityLifecycleDispatcher,
+                        Collections.emptyMap(),
+                        Collections.emptyMap());
+    }
+
+    @Test
+    @Features.EnableFeatures({
+        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY
+                + ":app-id/com.google.android.googlequicksearchbox"
+    })
+    public void surveyControllerLaunchsAdsCctSurveyForEeaDeclined() {
+        setTestSurveyConfigForTrigger(
+                CCT_ADS_NOTICE_EEA_DECLINED_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_CONSENT_DECISION_MADE))
+                .thenReturn(true);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_TOPICS_ENABLED)).thenReturn(false);
+        controller.scheduleAdsCctTreatmentSurveyLaunch("com.google.android.googlequicksearchbox");
+        verify(mSurveyClient)
+                .showSurvey(
+                        mActivity,
+                        mActivityLifecycleDispatcher,
+                        Collections.emptyMap(),
+                        Collections.emptyMap());
+    }
+
+    @Test
+    @Features.EnableFeatures({
+        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY
+                + ":app-id/com.google.android.googlequicksearchbox"
+    })
+    public void surveyControllerLaunchsAdsCctSurveyForRowAcknowledged() {
+        setTestSurveyConfigForTrigger(
+                CCT_ADS_NOTICE_ROW_ACKNOWLEDGED_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_ROW_NOTICE_ACKNOWLEDGED))
+                .thenReturn(true);
+        controller.scheduleAdsCctTreatmentSurveyLaunch("com.google.android.googlequicksearchbox");
+        verify(mSurveyClient)
+                .showSurvey(
+                        mActivity,
+                        mActivityLifecycleDispatcher,
+                        Collections.emptyMap(),
+                        Collections.emptyMap());
+    }
+
+    @Test
+    @Features.EnableFeatures({ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY})
+    public void surveyControllerLaunchsAdsCctSurveyWithEmptyAppIdParameter() {
+        // Arbitrary choose to launch the ROW acknowledged survey.
+        // Any of the treatment surveys should work here.
+        setTestSurveyConfigForTrigger(
+                CCT_ADS_NOTICE_ROW_ACKNOWLEDGED_TRIGGER,
+                /* psdBitFields= */ new String[0],
+                /* psdStringFields= */ new String[0]);
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        when(mPrefService.getBoolean(Pref.PRIVACY_SANDBOX_M1_ROW_NOTICE_ACKNOWLEDGED))
+                .thenReturn(true);
+        controller.scheduleAdsCctTreatmentSurveyLaunch("any-app-id");
+        verify(mSurveyClient)
+                .showSurvey(
+                        mActivity,
+                        mActivityLifecycleDispatcher,
+                        Collections.emptyMap(),
+                        Collections.emptyMap());
+    }
+
+    @Test
+    @Features.EnableFeatures({
+        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY
+                + ":app-id/com.google.android.googlequicksearchbox"
+    })
+    public void surveyControllerDoesNotLaunchsAdsCctSurveyWithNoConsentOrNoticeInteraction() {
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        // TODO(crbug.com/379930582): Assert that the histogram detailing that we found no
+        // consent/notice interactions happened.
+        controller.scheduleAdsCctTreatmentSurveyLaunch("com.google.android.googlequicksearchbox");
+        verify(mSurveyClient, times(0)).showSurvey(any(), any(), any(), any());
+    }
+
+    @Test
+    @Features.EnableFeatures({
+        ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY
+                + ":app-id/com.google.android.googlequicksearchbox"
+    })
+    public void surveyControllerDoesNotLaunchAdsCctSurveyWithMismatchedAppId() {
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        // TODO(crbug.com/379930582): Assert that the histogram detailing mismatching app-id is
+        // emitted.
+        controller.scheduleAdsCctTreatmentSurveyLaunch("mismatched-appid");
+        verify(mSurveyClient, times(0)).showSurvey(any(), any(), any(), any());
+    }
+
+    @Test
+    @Features.DisableFeatures(ChromeFeatureList.PRIVACY_SANDBOX_CCT_ADS_NOTICE_SURVEY)
+    public void surveyControllerDoesNotLaunchAdsCctSurveyWithDisabledFeature() {
+        PrivacySandboxSurveyController controller =
+                PrivacySandboxSurveyController.initialize(
+                        mTabModelSelector,
+                        mActivityLifecycleDispatcher,
+                        mActivity,
+                        mMessageDispatcher,
+                        mActivityTabProvider,
+                        mProfile);
+        // TODO(crbug.com/379930582): Assert that the histogram detailing feature was disable was
+        // emitted.
+        controller.scheduleAdsCctTreatmentSurveyLaunch("com.google.android.googlequicksearchbox");
+        verify(mSurveyClient, times(0)).showSurvey(any(), any(), any(), any());
+    }
 }
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index bcd9e96c..01723504 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -5815,7 +5815,7 @@
   <message name="IDS_SETTINGS_POWER_IDLE_WHILE_CHARGING_LABEL" desc="In Device Settings > Power, label for behavior when device is idle.">
     While charging
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL" desc="In Device Settings > Power, label for behavior when device is inactive and plugged in.">
+<message name="IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL" desc="In Device Settings > Power, label for behavior when device is inactive and plugged in.">
     While inactive and plugged in
   </message>
   <message name="IDS_SETTINGS_POWER_IDLE_WHILE_CHARGING_ARIA_LABEL" desc="In Device Settings > Power, aria label for behavior when device is idle.">
@@ -5824,7 +5824,7 @@
   <message name="IDS_SETTINGS_POWER_IDLE_WHILE_ON_BATTERY_LABEL" desc="In Device Settings > Power, label for behavior when device is idle.">
     While on battery
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL" desc="In Device Settings > Power, label for behavior when device is inactive and on battery.">
+  <message name="IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL" desc="In Device Settings > Power, label for behavior when device is inactive and on battery.">
     While inactive and on battery
   </message>
   <message name="IDS_SETTINGS_POWER_IDLE_WHILE_ON_BATTERY_ARIA_LABEL" desc="In Device Settings > Power, aria label for behavior when device is idle.">
@@ -5880,7 +5880,7 @@
   <message name="IDS_SETTINGS_RESET_TITLE" desc="Title of a section of settings. This section describes settings for resetting the device.">
     Reset settings
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_RESET_TITLE" desc="Title of a section of settings. This section describes settings for resetting the device.">
+  <message name="IDS_OS_SETTINGS_RESET_TITLE" desc="Title of a section of settings. This section describes settings for resetting the device.">
     Reset
   </message>
   <message name="IDS_SETTINGS_FACTORY_RESET" desc="Name of the factory reset option on the Chrome settings page">
@@ -5892,7 +5892,7 @@
   <message name="IDS_SETTINGS_FACTORY_RESET_DESCRIPTION" desc="Description of the factory reset option on the Chrome settings page">
     Remove all user accounts and reset your <ph name="IDS_SHORT_PRODUCT_NAME">$1<ex>Chrome</ex></ph> device to be just like new.
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_FACTORY_RESET_DESCRIPTION" desc="Description of the factory reset option on the ChromeOS settings page">
+  <message name="IDS_OS_SETTINGS_FACTORY_RESET_DESCRIPTION" desc="Description of the factory reset option on the ChromeOS settings page">
     Remove all user accounts and reset your Chromebook to be just like new.
   </message>
   <message name="IDS_SETTINGS_FACTORY_RESET_WARNING" desc="Warning text in the 'Factory Reset' window">
@@ -7241,10 +7241,10 @@
   <message name="IDS_OS_SETTINGS_ON_STARTUP_SETTINGS_CARD_TITLE" desc="The title of the settings card that allows the user to configure the restore apps and pages options on startup.">
     Startup
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_ON_STARTUP_TITLE" desc="The title of the dropdown menu that allows the user to configure the restore apps and pages options on startup.">
+  <message name="IDS_OS_SETTINGS_ON_STARTUP_TITLE" desc="The title of the dropdown menu that allows the user to configure the restore apps and pages options on startup.">
     Welcome Recap
   </message>
-  <message name="IDS_OS_SETTINGS_REVAMP_ON_STARTUP_DESCRIPTION" desc="The description of the dropdown menu that allows the user to configure the restore apps and pages options on startup.">
+  <message name="IDS_OS_SETTINGS_ON_STARTUP_DESCRIPTION" desc="The description of the dropdown menu that allows the user to configure the restore apps and pages options on startup.">
     Open your previous windows and tabs to easily continue where you left off
   </message>
   <message name="IDS_OS_SETTINGS_ON_STARTUP_ALWAYS" desc="Label for the dropdown menu which enables the always restore apps and pages option on startup.">
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_FACTORY_RESET_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_FACTORY_RESET_DESCRIPTION.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_FACTORY_RESET_DESCRIPTION.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_FACTORY_RESET_DESCRIPTION.png.sha1
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_ON_STARTUP_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DESCRIPTION.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_ON_STARTUP_DESCRIPTION.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DESCRIPTION.png.sha1
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_ON_STARTUP_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_TITLE.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_ON_STARTUP_TITLE.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_TITLE.png.sha1
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL.png.sha1
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL.png.sha1
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_RESET_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_RESET_TITLE.png.sha1
similarity index 100%
rename from chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_REVAMP_RESET_TITLE.png.sha1
rename to chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_RESET_TITLE.png.sha1
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 18fa0de..cdafc17 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4357,6 +4357,7 @@
       "//third_party/zxcvbn-cpp",
       "//ui/views",
       "//ui/web_dialogs",
+      "//ui/webui",
       "//ui/webui/resources/cr_components/app_management:mojo_bindings",
       "//ui/webui/resources/cr_components/help_bubble:mojo_bindings",
       "//ui/webui/resources/cr_components/history_clusters:mojo_bindings",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 37b8218..cbb5e3da 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2249,6 +2249,30 @@
     {segmentation_platform::features::kEphemeralCardRankerForceHideCardParam,
      segmentation_platform::kDefaultBrowserPromo},
 };
+const FeatureEntry::FeatureParam kTabGroupPromoShowArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceShowCardParam,
+     segmentation_platform::kTabGroupPromo},
+};
+const FeatureEntry::FeatureParam kTabGroupPromoHideArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceHideCardParam,
+     segmentation_platform::kTabGroupPromo},
+};
+const FeatureEntry::FeatureParam kTabGroupSyncPromoShowArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceShowCardParam,
+     segmentation_platform::kTabGroupSyncPromo},
+};
+const FeatureEntry::FeatureParam kTabGroupSyncPromoHideArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceHideCardParam,
+     segmentation_platform::kTabGroupSyncPromo},
+};
+const FeatureEntry::FeatureParam kQuickDeletePromoShowArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceShowCardParam,
+     segmentation_platform::kQuickDeletePromo},
+};
+const FeatureEntry::FeatureParam kQuickDeletePromoHideArm[] = {
+    {segmentation_platform::features::kEphemeralCardRankerForceHideCardParam,
+     segmentation_platform::kQuickDeletePromo},
+};
 
 const FeatureEntry::FeatureVariation kEphemeralCardRankerCardOverrideOptions[] =
     {
@@ -2256,26 +2280,18 @@
          std::size(kDefaultBrowserPromoShowArm), nullptr},
         {"- Force hide default browser promo", kDefaultBrowserPromoHideArm,
          std::size(kDefaultBrowserPromoHideArm), nullptr},
-};
-
-const FeatureEntry::FeatureParam kEducationalTipModule_force_default_browser[] =
-    {{"force_default_browser", "true"}};
-const FeatureEntry::FeatureParam kEducationalTipModule_force_tab_group[] = {
-    {"force_tab_group", "true"}};
-const FeatureEntry::FeatureParam kEducationalTipModule_force_tab_group_sync[] =
-    {{"force_tab_group_sync", "true"}};
-const FeatureEntry::FeatureParam kEducationalTipModule_force_quick_delete[] = {
-    {"force_quick_delete", "true"}};
-
-const FeatureEntry::FeatureVariation kEducationalTipModuleVariations[] = {
-    {"Show default browser promo", kEducationalTipModule_force_default_browser,
-     std::size(kEducationalTipModule_force_default_browser), nullptr},
-    {"Show tab group promo", kEducationalTipModule_force_tab_group,
-     std::size(kEducationalTipModule_force_tab_group), nullptr},
-    {"Show tab group sync promo", kEducationalTipModule_force_tab_group_sync,
-     std::size(kEducationalTipModule_force_tab_group_sync), nullptr},
-    {"Show quick delete promo", kEducationalTipModule_force_quick_delete,
-     std::size(kEducationalTipModule_force_quick_delete), nullptr},
+        {"- Force show tab group promo", kTabGroupPromoShowArm,
+         std::size(kTabGroupPromoShowArm), nullptr},
+        {"- Force hide tab group promo", kTabGroupPromoHideArm,
+         std::size(kTabGroupPromoHideArm), nullptr},
+        {"- Force show tab group sync promo", kTabGroupSyncPromoShowArm,
+         std::size(kTabGroupSyncPromoShowArm), nullptr},
+        {"- Force hide tab group sync promo", kTabGroupSyncPromoHideArm,
+         std::size(kTabGroupSyncPromoHideArm), nullptr},
+        {"- Force show quick delete promo", kQuickDeletePromoShowArm,
+         std::size(kQuickDeletePromoShowArm), nullptr},
+        {"- Force hide quick delete promo", kQuickDeletePromoHideArm,
+         std::size(kQuickDeletePromoHideArm), nullptr},
 };
 #endif  // BUILDFLAG(IS_ANDROID)
 #if BUILDFLAG(IS_ANDROID)
@@ -4763,10 +4779,6 @@
     {"instant-tethering", flag_descriptions::kTetherName,
      flag_descriptions::kTetherDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kInstantTethering)},
-    {"improved-keyboard-shortcuts",
-     flag_descriptions::kImprovedKeyboardShortcutsName,
-     flag_descriptions::kImprovedKeyboardShortcutsDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kImprovedKeyboardShortcuts)},
     {"deprecate-alt-click", flag_descriptions::kDeprecateAltClickName,
      flag_descriptions::kDeprecateAltClickDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kDeprecateAltClick)},
@@ -7206,10 +7218,8 @@
     {"enable-educational-tip-module",
      flag_descriptions::kEducationalTipModuleName,
      flag_descriptions::kEducationalTipModuleDescription, kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         segmentation_platform::features::kEducationalTipModule,
-         kEducationalTipModuleVariations,
-         "EducationalTipModule")},
+     FEATURE_VALUE_TYPE(
+         segmentation_platform::features::kEducationalTipModule)},
 
     {"enable-segmentation-platform-ephemeral_card_ranker",
      flag_descriptions::kSegmentationPlatformEphemeralCardRankerName,
@@ -7905,11 +7915,6 @@
      flag_descriptions::kEnableOAuthIppDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kEnableOAuthIpp)},
 
-    {"enable-shortcut-customization",
-     flag_descriptions::kEnableShortcutCustomizationName,
-     flag_descriptions::kEnableShortcutCustomizationDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kShortcutCustomization)},
-
     {"enable-search-customizable-shortcuts-in-launcher",
      flag_descriptions::kEnableSearchCustomizableShortcutsInLauncherName,
      flag_descriptions::kEnableSearchCustomizableShortcutsInLauncherDescription,
diff --git a/chrome/browser/ash/accessibility/magnification_manager.cc b/chrome/browser/ash/accessibility/magnification_manager.cc
index 09f5683..9eaf21aa 100644
--- a/chrome/browser/ash/accessibility/magnification_manager.cc
+++ b/chrome/browser/ash/accessibility/magnification_manager.cc
@@ -143,9 +143,6 @@
       event_type != ax::mojom::Event::kSelection) {
     return;
   }
-
-  ui::AXNodeData data;
-  view->GetViewAccessibility().GetAccessibleNodeData(&data);
 }
 
 void MagnificationManager::SetProfileForTest(Profile* profile) {
diff --git a/chrome/browser/ash/ambient/ambient_client_impl_unittest.cc b/chrome/browser/ash/ambient/ambient_client_impl_unittest.cc
index c2785ce..71393bc 100644
--- a/chrome/browser/ash/ambient/ambient_client_impl_unittest.cc
+++ b/chrome/browser/ash/ambient/ambient_client_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_task_environment.h"
+#include "google_apis/gaia/gaia_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 constexpr char kTestProfileName[] = "user@gmail.com";
@@ -101,28 +102,28 @@
 
 TEST_F(AmbientClientImplTest, AllowedByPrimaryUser) {
   AddAndLoginUser(AccountId::FromUserEmailGaiaId(
-      profile()->GetProfileUserName(), kTestGaiaId));
+      profile()->GetProfileUserName(), GaiaId(kTestGaiaId)));
   EXPECT_TRUE(ash::AmbientClient::Get()->IsAmbientModeAllowed());
 }
 
 TEST_F(AmbientClientImplTest, DisallowedByNonPrimaryUser) {
   AddAndLoginUser(
-      AccountId::FromUserEmailGaiaId("user2@gmail.com", kTestGaiaId));
+      AccountId::FromUserEmailGaiaId("user2@gmail.com", GaiaId(kTestGaiaId)));
   AddAndLoginUser(AccountId::FromUserEmailGaiaId(
-      profile()->GetProfileUserName(), kTestGaiaId));
+      profile()->GetProfileUserName(), GaiaId(kTestGaiaId)));
   EXPECT_FALSE(ash::AmbientClient::Get()->IsAmbientModeAllowed());
 }
 
 TEST_F(AmbientClientImplTest, DisallowedByEmailDomain) {
-  AddAndLoginUser(
-      AccountId::FromUserEmailGaiaId("user@gmailtest.com", kTestGaiaId));
+  AddAndLoginUser(AccountId::FromUserEmailGaiaId("user@gmailtest.com",
+                                                 GaiaId(kTestGaiaId)));
   EXPECT_FALSE(ash::AmbientClient::Get()->IsAmbientModeAllowed());
 }
 
 TEST_F(AmbientClientImplTest, DownloadImage) {
   identity_test_env()->SetAutomaticIssueOfAccessTokens(true);
   AddAndLoginUser(AccountId::FromUserEmailGaiaId(
-      profile()->GetProfileUserName(), kTestGaiaId));
+      profile()->GetProfileUserName(), GaiaId(kTestGaiaId)));
   ambient_client().DownloadImage("test_url", base::DoNothing());
   base::RunLoop().RunUntilIdle();
 
@@ -135,7 +136,7 @@
 TEST_F(AmbientClientImplTest, DownloadImageMultipleTimes) {
   identity_test_env()->SetAutomaticIssueOfAccessTokens(true);
   AddAndLoginUser(AccountId::FromUserEmailGaiaId(
-      profile()->GetProfileUserName(), kTestGaiaId));
+      profile()->GetProfileUserName(), GaiaId(kTestGaiaId)));
   // make sure multiple images can download at the same time.
   ambient_client().DownloadImage("test_url_1", base::DoNothing());
   ambient_client().DownloadImage("test_url_2", base::DoNothing());
diff --git a/chrome/browser/ash/app_list/search/keyboard_shortcut_result.cc b/chrome/browser/ash/app_list/search/keyboard_shortcut_result.cc
index 5f8c7d071..fda4f4a6 100644
--- a/chrome/browser/ash/app_list/search/keyboard_shortcut_result.cc
+++ b/chrome/browser/ash/app_list/search/keyboard_shortcut_result.cc
@@ -142,6 +142,8 @@
       return IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ACCESSIBILITY;
     case ash::SearchResultTextItem::kKeyboardShortcutKeyboardQuickInsert:
       return IDS_KEYBOARD_QUICK_INSERT_LABEL;
+    case ash::SearchResultTextItem::kKeyboardShortcutDoNotDisturb:
+      return IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB;
   }
 }
 
@@ -274,6 +276,8 @@
       return IconCode::kKeyboardShortcutMicrophone;
     case (KeyboardCode::VKEY_ACCESSIBILITY):
       return IconCode::kKeyboardShortcutAccessibility;
+    case KeyboardCode::VKEY_DO_NOT_DISTURB:
+      return IconCode::kKeyboardShortcutDoNotDisturb;
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     case (KeyboardCode::VKEY_QUICK_INSERT):
       return IconCode::kKeyboardShortcutKeyboardQuickInsert;
@@ -304,6 +308,7 @@
        {u"BrowserHome", IconCode::kKeyboardShortcutBrowserHome},
        {u"BrowserRefresh", IconCode::kKeyboardShortcutBrowserRefresh},
        {u"BrowserSearch", IconCode::kKeyboardShortcutBrowserSearch},
+       {u"DoNotDisturb", IconCode::kKeyboardShortcutDoNotDisturb},
        {u"EmojiPicker", IconCode::kKeyboardShortcutEmojiPicker},
        {u"EnableOrToggleDictation", IconCode::kKeyboardShortcutDictationToggle},
        {u"KeyboardBacklightToggle",
diff --git a/chrome/browser/ash/assistant/assistant_util_unittest.cc b/chrome/browser/ash/assistant/assistant_util_unittest.cc
index 46f1451e..0760137 100644
--- a/chrome/browser/ash/assistant/assistant_util_unittest.cc
+++ b/chrome/browser/ash/assistant/assistant_util_unittest.cc
@@ -33,6 +33,7 @@
 #include "components/user_manager/user_type.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_task_environment.h"
+#include "google_apis/gaia/gaia_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/icu/source/common/unicode/locid.h"
 #include "ui/events/devices/device_data_manager.h"
@@ -213,7 +214,7 @@
 
   AccountId GetGaiaUserAccountId(const TestingProfile* profile) {
     return AccountId::FromUserEmailGaiaId(profile->GetProfileUserName(),
-                                          kTestGaiaId);
+                                          GaiaId(kTestGaiaId));
   }
 
   AccountId GetGaiaUserAccountId(const std::string& user_name,
@@ -248,7 +249,7 @@
 TEST_F(ChromeAssistantUtilTest, IsAssistantAllowedForProfile_SecondaryUser) {
   ScopedLogIn secondary_user_login(
       GetFakeUserManager(), identity_test_env(),
-      GetGaiaUserAccountId("user2@gmail.com", "0123456789"));
+      GetGaiaUserAccountId("user2@gmail.com", GaiaId("0123456789")));
   ScopedLogIn primary_user_login(GetFakeUserManager(), identity_test_env(),
                                  GetGaiaUserAccountId(profile()));
 
@@ -315,15 +316,16 @@
 TEST_F(ChromeAssistantUtilTest, IsAssistantAllowedForProfile_NonGmail) {
   ScopedLogIn login(
       GetFakeUserManager(), identity_test_env(),
-      GetGaiaUserAccountId("user2@someotherdomain.com", "0123456789"));
+      GetGaiaUserAccountId("user2@someotherdomain.com", GaiaId("0123456789")));
 
   EXPECT_EQ(ash::assistant::AssistantAllowedState::DISALLOWED_BY_ACCOUNT_TYPE,
             IsAssistantAllowedForProfile(profile()));
 }
 
 TEST_F(ChromeAssistantUtilTest, IsAssistantAllowedForProfile_GoogleMail) {
-  ScopedLogIn login(GetFakeUserManager(), identity_test_env(),
-                    GetGaiaUserAccountId("user2@googlemail.com", "0123456789"));
+  ScopedLogIn login(
+      GetFakeUserManager(), identity_test_env(),
+      GetGaiaUserAccountId("user2@googlemail.com", GaiaId("0123456789")));
 
   EXPECT_EQ(ash::assistant::AssistantAllowedState::ALLOWED,
             IsAssistantAllowedForProfile(profile()));
@@ -333,7 +335,7 @@
        IsAssistantAllowed_AllowsNonGmailOnGoogleBrandedDevices) {
   ScopedLogIn login(
       GetFakeUserManager(), identity_test_env(),
-      GetGaiaUserAccountId("user2@someotherdomain.com", "0123456789"));
+      GetGaiaUserAccountId("user2@someotherdomain.com", GaiaId("0123456789")));
 
   ScopedSpoofGoogleBrandedDevice make_google_branded_device;
   EXPECT_EQ(ash::assistant::AssistantAllowedState::ALLOWED,
@@ -362,8 +364,9 @@
   feature_list_.InitAndEnableFeature(
       ash::assistant::features::kEnableLibAssistantDLC);
 
-  ScopedLogIn login(GetFakeUserManager(), identity_test_env(),
-                    GetGaiaUserAccountId("user2@googlemail.com", "0123456789"));
+  ScopedLogIn login(
+      GetFakeUserManager(), identity_test_env(),
+      GetGaiaUserAccountId("user2@googlemail.com", GaiaId("0123456789")));
 
   EXPECT_EQ(ash::assistant::AssistantAllowedState::ALLOWED,
             IsAssistantAllowedForProfile(profile()));
@@ -373,8 +376,9 @@
   feature_list_.InitAndDisableFeature(
       ash::assistant::features::kEnableLibAssistantDLC);
 
-  ScopedLogIn login(GetFakeUserManager(), identity_test_env(),
-                    GetGaiaUserAccountId("user2@googlemail.com", "0123456789"));
+  ScopedLogIn login(
+      GetFakeUserManager(), identity_test_env(),
+      GetGaiaUserAccountId("user2@googlemail.com", GaiaId("0123456789")));
 
   EXPECT_EQ(ash::assistant::AssistantAllowedState::DISALLOWED_BY_NO_BINARY,
             IsAssistantAllowedForProfile(profile()));
@@ -384,8 +388,9 @@
   feature_list_.InitAndEnableFeature(
       ash::assistant::features::kEnableNewEntryPoint);
 
-  ScopedLogIn login(GetFakeUserManager(), identity_test_env(),
-                    GetGaiaUserAccountId("user2@googlemail.com", "0123456789"));
+  ScopedLogIn login(
+      GetFakeUserManager(), identity_test_env(),
+      GetGaiaUserAccountId("user2@googlemail.com", GaiaId("0123456789")));
 
   EXPECT_EQ(
       ash::assistant::AssistantAllowedState::DISALLOWED_BY_NEW_ENTRY_POINT,
diff --git a/chrome/browser/ash/calendar/calendar_keyed_service_unittest.cc b/chrome/browser/ash/calendar/calendar_keyed_service_unittest.cc
index 8fc6d50..9c2a550 100644
--- a/chrome/browser/ash/calendar/calendar_keyed_service_unittest.cc
+++ b/chrome/browser/ash/calendar/calendar_keyed_service_unittest.cc
@@ -59,7 +59,9 @@
     ProfileHelper::SetProfileToUserForTestingEnabled(false);
   }
 
-  std::string GetDefaultProfileName() override { return kPrimaryProfileName; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kPrimaryProfileName;
+  }
 
   TestingProfile* CreateSecondaryProfile() {
     LogIn(kSecondaryProfileName);
@@ -134,8 +136,23 @@
       test_shared_loader_factory_;
 };
 
+class NoProfileCalendarKeyedServiceTest : public CalendarKeyedServiceTest {
+ public:
+  NoProfileCalendarKeyedServiceTest() = default;
+  NoProfileCalendarKeyedServiceTest(
+      const NoProfileCalendarKeyedServiceTest& other) = delete;
+  NoProfileCalendarKeyedServiceTest& operator=(
+      const NoProfileCalendarKeyedServiceTest& other) = delete;
+  ~NoProfileCalendarKeyedServiceTest() override = default;
+
+  // CalendarKeyedServiceTest:
+  std::optional<std::string> GetDefaultProfileName() override {
+    return std::nullopt;
+  }
+};
+
 // Calendar service does not support guest user.
-TEST_F(CalendarKeyedServiceTest, GuestUserProfile) {
+TEST_F(NoProfileCalendarKeyedServiceTest, GuestUserProfile) {
   // Construct a guest session profile.
   TestingProfile::Builder guest_profile_builder;
   guest_profile_builder.SetGuestSession();
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index 1aef9811..89cc01b 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -194,8 +194,6 @@
     "volume_manager_ash.h",
     "vpn_service_ash.cc",
     "vpn_service_ash.h",
-    "wallpaper_ash.cc",
-    "wallpaper_ash.h",
     "web_app_service_ash.cc",
     "web_app_service_ash.h",
     "web_kiosk_service_ash.cc",
@@ -312,7 +310,6 @@
     "//chrome/browser/chromeos/extensions/login_screen/login_screen_storage",
     "//chrome/browser/chromeos/extensions/login_screen/login_state",
     "//chrome/browser/chromeos/extensions/vpn_provider",
-    "//chrome/browser/chromeos/extensions/wallpaper",
     "//chrome/browser/chromeos/platform_keys",
     "//chrome/browser/chromeos/policy/dlp",
     "//chrome/browser/chromeos/printing/print_preview",
@@ -339,7 +336,6 @@
     "//chrome/browser/ui/ash/shelf/app_service",
     "//chrome/browser/ui/ash/shell_delegate",
     "//chrome/browser/ui/ash/system_web_apps",
-    "//chrome/browser/ui/ash/wallpaper",
     "//chrome/browser/ui/chromeos/magic_boost",
     "//chrome/browser/ui/views/select_file_dialog_extension",
     "//chrome/browser/ui/webui/ash/cloud_upload",
@@ -513,7 +509,6 @@
     "//chrome/browser/chromeos/extensions/login_screen/login_screen_storage",
     "//chrome/browser/chromeos/extensions/login_screen/login_state",
     "//chrome/browser/chromeos/extensions/vpn_provider",
-    "//chrome/browser/chromeos/extensions/wallpaper",
     "//chrome/browser/chromeos/platform_keys",
     "//chrome/browser/chromeos/printing/print_preview",
     "//chrome/browser/chromeos/video_conference",
@@ -619,7 +614,6 @@
     "primary_profile_creation_waiter_unittest.cc",
     "screen_ai_downloader_ash_unittest.cc",
     "search_controller_ash_unittest.cc",
-    "wallpaper_ash_unittest.cc",
   ]
 
   if (use_cups) {
@@ -656,14 +650,11 @@
     "//chrome/browser/ash/scanning:test_support",
     "//chrome/browser/ash/settings",
     "//chrome/browser/ash/settings:test_support",
-    "//chrome/browser/ash/wallpaper_handlers:test_support",
     "//chrome/browser/chromeos/platform_keys",
     "//chrome/browser/chromeos/policy/dlp",
     "//chrome/browser/chromeos/policy/dlp/test:test_support",
     "//chrome/browser/ui/ash/desks",
     "//chrome/browser/ui/ash/shelf",
-    "//chrome/browser/ui/ash/wallpaper",
-    "//chrome/browser/ui/ash/wallpaper:test_support",
     "//chrome/browser/ui/webui/ash/parent_access",
     "//chrome/common/printing",
     "//chrome/test:test_support",
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index 77a907a8..8958b12 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -88,7 +88,6 @@
 #include "chrome/browser/ash/crosapi/virtual_keyboard_ash.h"
 #include "chrome/browser/ash/crosapi/volume_manager_ash.h"
 #include "chrome/browser/ash/crosapi/vpn_service_ash.h"
-#include "chrome/browser/ash/crosapi/wallpaper_ash.h"
 #include "chrome/browser/ash/crosapi/web_app_service_ash.h"
 #include "chrome/browser/ash/crosapi/web_kiosk_service_ash.h"
 #include "chrome/browser/ash/input_method/editor_mediator_factory.h"
@@ -280,7 +279,6 @@
       virtual_keyboard_ash_(std::make_unique<VirtualKeyboardAsh>()),
       volume_manager_ash_(std::make_unique<VolumeManagerAsh>()),
       vpn_service_ash_(std::make_unique<VpnServiceAsh>()),
-      wallpaper_ash_(std::make_unique<WallpaperAsh>()),
       web_app_service_ash_(std::make_unique<WebAppServiceAsh>()),
       web_kiosk_service_ash_(std::make_unique<WebKioskServiceAsh>()) {
   receiver_set_.set_disconnect_handler(base::BindRepeating(
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h
index d7cbfff..cbf37b3ee 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.h
+++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -125,7 +125,6 @@
 class TaskManagerAsh;
 class TimeZoneServiceAsh;
 class VpnServiceAsh;
-class WallpaperAsh;
 class WebAppServiceAsh;
 class WebKioskServiceAsh;
 class VirtualKeyboardAsh;
@@ -549,8 +548,6 @@
 
   TaskManagerAsh* task_manager_ash() { return task_manager_ash_.get(); }
 
-  WallpaperAsh* wallpaper_ash() { return wallpaper_ash_.get(); }
-
   WebAppServiceAsh* web_app_service_ash() { return web_app_service_ash_.get(); }
 
   WebKioskServiceAsh* web_kiosk_service_ash() {
@@ -663,9 +660,6 @@
   std::unique_ptr<VirtualKeyboardAsh> virtual_keyboard_ash_;
   std::unique_ptr<VolumeManagerAsh> volume_manager_ash_;
   std::unique_ptr<VpnServiceAsh> vpn_service_ash_;
-  // TODO(crbug.com/373972275): Move ownership of this object elsewhere. It is
-  // no longer a crosapi, but it is still used internally by ash-chrome.
-  std::unique_ptr<WallpaperAsh> wallpaper_ash_;
   std::unique_ptr<WebAppServiceAsh> web_app_service_ash_;
   std::unique_ptr<WebKioskServiceAsh> web_kiosk_service_ash_;
 
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc
index 712c2c35..36fa9b60 100644
--- a/chrome/browser/ash/events/event_rewriter_unittest.cc
+++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -51,6 +51,7 @@
 #include "ui/base/ime/ash/input_method_manager.h"
 #include "ui/base/ime/ash/mock_input_method_manager.h"
 #include "ui/base/ime/ash/mock_input_method_manager_impl.h"
+#include "ui/base/shortcut_mapping_pref_delegate.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/ash/caps_lock_event_rewriter.h"
 #include "ui/events/ash/discard_key_event_rewriter.h"
@@ -606,6 +607,22 @@
     kWilco1_5Keyboard,
 };
 
+// Use to emulate `ImprovedKeyboardShortcuts` is disabled by the policy on
+// enrolled device.
+class TestShortcutMappingPrefDelegate : public ui::ShortcutMappingPrefDelegate {
+ public:
+  TestShortcutMappingPrefDelegate() = default;
+  TestShortcutMappingPrefDelegate(const TestShortcutMappingPrefDelegate&) =
+      delete;
+  TestShortcutMappingPrefDelegate& operator=(
+      const TestShortcutMappingPrefDelegate&) = delete;
+  ~TestShortcutMappingPrefDelegate() override = default;
+
+  // ui::ShortcutMappingPrefDelegate:
+  bool IsDeviceEnterpriseManaged() const override { return true; }
+  bool IsI18nShortcutPrefEnabled() const override { return false; }
+};
+
 }  // namespace
 
 namespace ash {
@@ -2010,72 +2027,6 @@
   scoped_feature_list_.Reset();
 }
 
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-TEST_P(EventRewriterTest, TestRewriteExtendedKeysAltVariantsOld) {
-  Preferences::RegisterProfilePrefs(prefs()->registry());
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {::features::kImprovedKeyboardShortcuts,
-           features::kAltClickAndSixPackCustomization});
-
-  for (const auto keyboard : kNonAppleKeyboardVariants) {
-    SCOPED_TRACE(keyboard.name);
-    SetUpKeyboard(keyboard);
-
-    // Alt+Backspace -> Delete
-    EXPECT_EQ(KeyDelete::Typed(),
-              RunRewriter(KeyBackspace::Typed(), ui::EF_ALT_DOWN));
-
-    // Control+Alt+Backspace -> Control+Delete
-    EXPECT_EQ(KeyDelete::Typed(ui::EF_CONTROL_DOWN),
-              RunRewriter(KeyBackspace::Typed(),
-                          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
-
-    // Search+Alt+Backspace -> Alt+Backspace
-    EXPECT_EQ(KeyBackspace::Typed(ui::EF_ALT_DOWN),
-              RunRewriter(KeyBackspace::Typed(),
-                          ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN));
-
-    // Search+Control+Alt+Backspace -> Control+Alt+Backspace
-    EXPECT_EQ(KeyBackspace::Typed(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN),
-              RunRewriter(KeyBackspace::Typed(), ui::EF_ALT_DOWN |
-                                                     ui::EF_COMMAND_DOWN |
-                                                     ui::EF_CONTROL_DOWN));
-
-    // Alt+Up -> Prior
-    EXPECT_EQ(KeyPageUp::Typed(),
-              RunRewriter(KeyArrowUp::Typed(), ui::EF_ALT_DOWN));
-
-    // Alt+Down -> Next
-    EXPECT_EQ(KeyPageDown::Typed(),
-              RunRewriter(KeyArrowDown::Typed(), ui::EF_ALT_DOWN));
-
-    // Ctrl+Alt+Up -> Home
-    EXPECT_EQ(KeyHome::Typed(),
-              RunRewriter(KeyArrowUp::Typed(),
-                          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
-
-    // Ctrl+Alt+Down -> End
-    EXPECT_EQ(KeyEnd::Typed(),
-              RunRewriter(KeyArrowDown::Typed(),
-                          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
-
-    // NOTE: The following are workarounds to avoid rewriting the
-    // Alt variants by additionally pressing Search.
-    // Search+Ctrl+Alt+Up -> Ctrl+Alt+Up
-    EXPECT_EQ(
-        KeyArrowUp::Typed(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN),
-        RunRewriter(KeyArrowUp::Typed(), ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN |
-                                             ui::EF_COMMAND_DOWN));
-
-    // Search+Ctrl+Alt+Down -> Ctrl+Alt+Down
-    EXPECT_EQ(KeyArrowDown::Typed(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN),
-              RunRewriter(KeyArrowDown::Typed(), ui::EF_ALT_DOWN |
-                                                     ui::EF_CONTROL_DOWN |
-                                                     ui::EF_COMMAND_DOWN));
-  }
-}
-
 TEST_P(EventRewriterTest, TestRewriteExtendedKeysAltVariants) {
   Preferences::RegisterProfilePrefs(prefs()->registry());
   base::test::ScopedFeatureList scoped_feature_list;
@@ -2154,37 +2105,11 @@
   }
 }
 
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-TEST_P(EventRewriterTest, TestRewriteExtendedKeyInsertOld) {
-  Preferences::RegisterProfilePrefs(prefs()->registry());
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {::features::kImprovedKeyboardShortcuts,
-           features::kAltClickAndSixPackCustomization});
-  for (const auto keyboard : kNonAppleKeyboardVariants) {
-    SCOPED_TRACE(keyboard.name);
-    SetUpKeyboard(keyboard);
-
-    // Period -> Period
-    EXPECT_EQ(KeyPeriod::Typed(), RunRewriter(KeyPeriod::Typed()));
-
-    // Search+Period -> Insert
-    EXPECT_EQ(KeyInsert::Typed(),
-              RunRewriter(KeyPeriod::Typed(), ui::EF_COMMAND_DOWN));
-
-    // Control+Search+Period -> Control+Insert
-    EXPECT_EQ(KeyInsert::Typed(ui::EF_CONTROL_DOWN),
-              RunRewriter(KeyPeriod::Typed(),
-                          ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN));
-  }
-}
-
 TEST_P(EventRewriterTest, TestRewriteExtendedKeyInsertDeprecatedNotification) {
   Preferences::RegisterProfilePrefs(prefs()->registry());
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {::features::kImprovedKeyboardShortcuts},
-      {features::kAltClickAndSixPackCustomization});
+      {}, {features::kAltClickAndSixPackCustomization});
 
   for (const auto keyboard : kNonAppleKeyboardVariants) {
     SCOPED_TRACE(keyboard.name);
@@ -2208,13 +2133,11 @@
   }
 }
 
-// TODO(crbug.com/1179893): Rename once the feature is enabled permanently.
-TEST_P(EventRewriterTest, TestRewriteExtendedKeyInsertNew) {
+TEST_P(EventRewriterTest, TestRewriteExtendedKeyInsert) {
   Preferences::RegisterProfilePrefs(prefs()->registry());
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {::features::kImprovedKeyboardShortcuts},
-      {features::kAltClickAndSixPackCustomization});
+      {}, {features::kAltClickAndSixPackCustomization});
 
   for (const auto keyboard : kNonAppleKeyboardVariants) {
     SCOPED_TRACE(keyboard.name);
@@ -2300,12 +2223,11 @@
   }
 }
 
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-TEST_P(EventRewriterTest, TestRewriteSearchNumberToFunctionKeyOld) {
+TEST_P(EventRewriterTest, TestRewriteSearchNumberToFunctionKey) {
+  TestShortcutMappingPrefDelegate delegate;
+  CHECK(!::features::IsImprovedKeyboardShortcutsEnabled());
+  ASSERT_FALSE(::features::IsImprovedKeyboardShortcutsEnabled());
   Preferences::RegisterProfilePrefs(prefs()->registry());
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      ::features::kImprovedKeyboardShortcuts);
 
   for (const auto& keyboard : kNonAppleNonCustomLayoutKeyboardVariants) {
     SCOPED_TRACE(keyboard.name);
@@ -3757,8 +3679,7 @@
   // behavior or create a notification.
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {::features::kImprovedKeyboardShortcuts},
-      {features::kAltClickAndSixPackCustomization});
+      {}, {features::kAltClickAndSixPackCustomization});
   DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN);
   EXPECT_EQ(message_center_.NotificationCount(), 0u);
 }
@@ -4712,11 +4633,13 @@
 }
 
 TEST_P(EventRewriterTest, RecordRewritingToFunctionKeys) {
+  TestShortcutMappingPrefDelegate delegate;
+  ASSERT_FALSE(::features::IsImprovedKeyboardShortcutsEnabled());
+
   Preferences::RegisterProfilePrefs(prefs()->registry());
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kInputDeviceSettingsSplit},
-      {::features::kImprovedKeyboardShortcuts});
+  scoped_feature_list.InitWithFeatures({features::kInputDeviceSettingsSplit},
+                                       {});
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectTotalCount("ChromeOS.Inputs.Keyboard.F1Pressed", 0);
diff --git a/chrome/browser/ash/fileapi/file_change_service_unittest.cc b/chrome/browser/ash/fileapi/file_change_service_unittest.cc
index 62847f36..1fb9359 100644
--- a/chrome/browser/ash/fileapi/file_change_service_unittest.cc
+++ b/chrome/browser/ash/fileapi/file_change_service_unittest.cc
@@ -239,7 +239,7 @@
 
  private:
   // BrowserWithTestWindowTest:
-  std::string GetDefaultProfileName() override {
+  std::optional<std::string> GetDefaultProfileName() override {
     return "promary_profile@test";
   }
 };
diff --git a/chrome/browser/ash/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/ash/input_method/input_method_manager_impl_unittest.cc
index 337f682..ec7b91e6 100644
--- a/chrome/browser/ash/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_manager_impl_unittest.cc
@@ -1712,24 +1712,7 @@
   EXPECT_TRUE(result.empty());
 }
 
-// TODO(crbug.com/1179893): Remove once the feature is enabled permanently.
-class InputMethodManagerImplPositionalTest : public InputMethodManagerImplTest {
- public:
-  InputMethodManagerImplPositionalTest() = default;
-  ~InputMethodManagerImplPositionalTest() override = default;
-
-  void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        ::features::kImprovedKeyboardShortcuts);
-
-    InputMethodManagerImplTest::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(InputMethodManagerImplPositionalTest, ValidatePositionalShortcutLayout) {
+TEST_F(InputMethodManagerImplTest, ValidatePositionalShortcutLayout) {
   // Initialize with one positional (US) and one non-positional (US-dvorak)
   // layout.
   std::string us_id = ImeIdFromEngineId("xkb:us::eng");
diff --git a/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc
index 29e3bf82..2e6e7752 100644
--- a/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/main_parts/chrome_browser_main_parts_ash.cc
@@ -1393,10 +1393,7 @@
       accessibility_event_rewriter_delegate_.get());
   // `ShortcutInputHandler` and `ModifierKeyComboRecorder` are dependent on
   // `EventRewriterController`'s initialization.
-  if (ash::features::IsPeripheralCustomizationEnabled() ||
-      ::features::IsShortcutCustomizationEnabled()) {
-    Shell::Get()->shortcut_input_handler()->Initialize();
-  }
+  Shell::Get()->shortcut_input_handler()->Initialize();
   Shell::Get()->modifier_key_combo_recorder()->Initialize();
   Shell::Get()->rapid_key_sequence_recorder()->Initialize();
 
diff --git a/chrome/browser/ash/note_taking/note_taking_helper_unittest.cc b/chrome/browser/ash/note_taking/note_taking_helper_unittest.cc
index dd60e00..0fa548ce8 100644
--- a/chrome/browser/ash/note_taking/note_taking_helper_unittest.cc
+++ b/chrome/browser/ash/note_taking/note_taking_helper_unittest.cc
@@ -367,7 +367,9 @@
   }
 
   // BrowserWithTestWindowTest:
-  std::string GetDefaultProfileName() override { return kTestProfileName; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kTestProfileName;
+  }
 
   // TODO(crbug.com/40286020): merge into BrowserWithTestWindowTest.
   void LogIn(const std::string& email) override {
diff --git a/chrome/browser/ash/notifications/idle_app_name_notification_view.cc b/chrome/browser/ash/notifications/idle_app_name_notification_view.cc
index faacda50..71f059f 100644
--- a/chrome/browser/ash/notifications/idle_app_name_notification_view.cc
+++ b/chrome/browser/ash/notifications/idle_app_name_notification_view.cc
@@ -235,10 +235,8 @@
 }
 
 std::u16string IdleAppNameNotificationView::GetShownTextForTest() {
-  ui::AXNodeData node_data;
   DCHECK(view_);
-  view_->GetViewAccessibility().GetAccessibleNodeData(&node_data);
-  return node_data.GetString16Attribute(ax::mojom::StringAttribute::kName);
+  return view_->GetViewAccessibility().GetCachedName();
 }
 
 void IdleAppNameNotificationView::ShowMessage(
diff --git a/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc b/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
index 3ba3e2c2..8efc15a 100644
--- a/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
+++ b/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
@@ -64,7 +64,7 @@
     BrowserWithTestWindowTest::TearDown();
   }
 
-  std::string GetDefaultProfileName() override {
+  std::optional<std::string> GetDefaultProfileName() override {
     // TODO(crbug.com/40286020): Use google.com domain to forcibly enable
     // release note notification. Will merge into BrowserWithTestWindowTest.
     return "primary_profile@google.com";
diff --git a/chrome/browser/ash/system_web_apps/test_support/BUILD.gn b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
index 2618141..dacd64d 100644
--- a/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
+++ b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
@@ -34,7 +34,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/web_applications",
     "//chrome/browser/web_applications:web_applications_test_support",
     "//components/crx_file",
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
index ec2858a..43ea5c6 100644
--- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
+++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressManager.java
@@ -168,13 +168,6 @@
     private Supplier<Boolean> mIsGestureNavEnabledSupplier = () -> false;
 
     /**
-     * @return True if the tab navigation should be corrected on fallback callback.
-     */
-    public static boolean correctTabNavigationOnFallback() {
-        return false;
-    }
-
-    /**
      * Record when the back press is consumed by a certain feature.
      *
      * @param type The {@link Type} which consumes the back press event.
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java
index 075ed60..1471e39f 100644
--- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java
+++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/MinimizeAppAndCloseTabBackPressHandler.java
@@ -200,9 +200,6 @@
             // minimizing app and closing tab.
             if (currentTab.canGoBack()) {
                 assert false : "Tab should be navigated back before closing or exiting app";
-                if (BackPressManager.correctTabNavigationOnFallback()) {
-                    return BackPressResult.FAILURE;
-                }
             }
             // At this point we know either the tab will close or the app will minimize.
             NativePage nativePage = currentTab.getNativePage();
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 0318009..252f8266 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -1278,11 +1278,8 @@
       ash::settings::mojom::DisplaySettingsProvider,
       ash::settings::OSSettingsUI>(map);
 
-  if (::features::IsShortcutCustomizationEnabled()) {
-    RegisterWebUIControllerInterfaceBinder<
-        ash::common::mojom::AcceleratorFetcher, ash::settings::OSSettingsUI>(
-        map);
-  }
+  RegisterWebUIControllerInterfaceBinder<ash::common::mojom::AcceleratorFetcher,
+                                         ash::settings::OSSettingsUI>(map);
 
   RegisterWebUIControllerInterfaceBinder<
       ash::common::mojom::ShortcutInputProvider, ash::settings::OSSettingsUI,
diff --git a/chrome/browser/chromeos/extensions/DEPS b/chrome/browser/chromeos/extensions/DEPS
index 89c58a3c..164c304 100644
--- a/chrome/browser/chromeos/extensions/DEPS
+++ b/chrome/browser/chromeos/extensions/DEPS
@@ -19,6 +19,7 @@
   "+chrome/browser/extensions/external_loader.h",
   "+chrome/browser/net",
   "+chrome/browser/profiles/profile.h",
+  "+chrome/browser/ui/ash/wallpaper/wallpaper_ash.h",
   "+chrome/browser/ui/browser_window.h",
   "+chrome/common",
 ]
@@ -48,4 +49,8 @@
   "accessibility_service_private\.cc": [
     "+chrome/browser/ash/accessibility/accessibility_manager.h",
   ],
+
+  "wallpaper_api\.h": [
+    "+ash/public/mojom/wallpaper.mojom.h",
+  ]
 }
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/common/api_guard_delegate_unittest.cc b/chrome/browser/chromeos/extensions/telemetry/api/common/api_guard_delegate_unittest.cc
index 8336cb7..f978244 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/common/api_guard_delegate_unittest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/common/api_guard_delegate_unittest.cc
@@ -172,7 +172,9 @@
   }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  std::string GetDefaultProfileName() override { return kUserEmail; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kUserEmail;
+  }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
  protected:
@@ -627,7 +629,7 @@
   }
 
   // BrowserWithTestWindowTest overrides.
-  std::string GetDefaultProfileName() override {
+  std::optional<std::string> GetDefaultProfileName() override {
     return ash::kShimlessRmaAppBrowserContextBaseName;
   }
 
diff --git a/chrome/browser/chromeos/extensions/wallpaper/BUILD.gn b/chrome/browser/chromeos/extensions/wallpaper/BUILD.gn
index f8b71fd5..d67fbe9 100644
--- a/chrome/browser/chromeos/extensions/wallpaper/BUILD.gn
+++ b/chrome/browser/chromeos/extensions/wallpaper/BUILD.gn
@@ -17,6 +17,7 @@
   ]
 
   public_deps = [
+    "//ash/public/mojom",
     "//chrome/common/extensions/api",
     "//components/account_id",
     "//extensions/browser",
@@ -29,7 +30,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/common:constants",
     "//chrome/common/extensions",
-    "//chromeos/crosapi/mojom",
     "//components/user_manager",
     "//content/public/browser",
     "//extensions/common",
diff --git a/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.cc
index bd372b2..962a60c 100644
--- a/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.cc
@@ -16,12 +16,10 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/values.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/ash/crosapi/wallpaper_ash.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/wallpaper/wallpaper_ash.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "components/user_manager/user.h"
@@ -48,24 +46,20 @@
 
 namespace {
 
-crosapi::mojom::WallpaperLayout GetMojoLayoutEnum(
+ash::mojom::WallpaperLayout GetMojoLayoutEnum(
     extensions::api::wallpaper::WallpaperLayout layout) {
   switch (layout) {
     case extensions::api::wallpaper::WallpaperLayout::kStretch:
-      return crosapi::mojom::WallpaperLayout::kStretch;
+      return ash::mojom::WallpaperLayout::kStretch;
     case extensions::api::wallpaper::WallpaperLayout::kCenter:
-      return crosapi::mojom::WallpaperLayout::kCenter;
+      return ash::mojom::WallpaperLayout::kCenter;
     case extensions::api::wallpaper::WallpaperLayout::kCenterCropped:
-      return crosapi::mojom::WallpaperLayout::kCenterCropped;
+      return ash::mojom::WallpaperLayout::kCenterCropped;
     default:
-      return crosapi::mojom::WallpaperLayout::kCenter;
+      return ash::mojom::WallpaperLayout::kCenter;
   }
 }
 
-crosapi::WallpaperAsh* GetWallpaperAsh() {
-  return crosapi::CrosapiManager::Get()->crosapi_ash()->wallpaper_ash();
-}
-
 class WallpaperFetcher {
  public:
   WallpaperFetcher() = default;
@@ -194,7 +188,7 @@
 }
 
 void WallpaperSetWallpaperFunction::OnWallpaperSetOnAsh(
-    const crosapi::mojom::SetWallpaperResultPtr result) {
+    const ash::mojom::SetWallpaperResultPtr result) {
   if (result->is_thumbnail_data()) {
     Respond(params_->details.thumbnail
                 ? WithArguments(Value(std::move(result->get_thumbnail_data())))
@@ -213,13 +207,13 @@
     extension_name = ext->name();
   }
 
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   settings->data = *params_->details.data;
   settings->layout = GetMojoLayoutEnum(params_->details.layout);
   settings->filename = params_->details.filename;
 
-  auto* wallpaper_ash = GetWallpaperAsh();
+  auto* wallpaper_ash = WallpaperAsh::Get();
   CHECK(wallpaper_ash);
   wallpaper_ash->SetWallpaper(
       std::move(settings), extension_id, extension_name,
diff --git a/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.h b/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.h
index 53f84c8..92fefe8 100644
--- a/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.h
+++ b/chrome/browser/chromeos/extensions/wallpaper/wallpaper_api.h
@@ -7,8 +7,8 @@
 
 #include <optional>
 
+#include "ash/public/mojom/wallpaper.mojom.h"
 #include "chrome/common/extensions/api/wallpaper.h"
-#include "chromeos/crosapi/mojom/wallpaper.mojom.h"
 #include "components/account_id/account_id.h"
 #include "extensions/browser/extension_function.h"
 
@@ -36,7 +36,7 @@
   // Called by OnURLFetchComplete().
   void OnWallpaperFetched(bool success, const std::string& response);
 
-  void OnWallpaperSetOnAsh(const crosapi::mojom::SetWallpaperResultPtr result);
+  void OnWallpaperSetOnAsh(const ash::mojom::SetWallpaperResultPtr result);
 
   void SetWallpaperOnAsh();
 
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupsDelegate.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupsDelegate.java
index dd65301..afe0e0db 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupsDelegate.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabGroupsDelegate.java
@@ -6,6 +6,8 @@
 
 import android.content.Context;
 
+import org.chromium.url.GURL;
+
 /** An interface to handle actions related to tab groups. */
 public interface DataSharingTabGroupsDelegate {
     /**
@@ -19,7 +21,7 @@
      * Open url in the Chrome Custom Tab.
      *
      * @param context The context of the current activity.
-     * @param url The URL of the page to be opened in CCT.
+     * @param gurl The GURL of the page to be opened in CCT.
      */
-    public void openLearnMoreSharedTabGroupsPage(Context context, String url);
+    public void openLearnMoreSharedTabGroupsPage(Context context, GURL gurl);
 }
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
index 6bdfb2d..a87bed4 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManager.java
@@ -45,16 +45,17 @@
 import org.chromium.components.data_sharing.PeopleGroupActionFailure;
 import org.chromium.components.data_sharing.PeopleGroupActionOutcome;
 import org.chromium.components.data_sharing.SharedTabGroupPreview;
+import org.chromium.components.data_sharing.TabPreview;
 import org.chromium.components.data_sharing.configs.DataSharingCreateUiConfig;
 import org.chromium.components.data_sharing.configs.DataSharingJoinUiConfig;
 import org.chromium.components.data_sharing.configs.DataSharingManageUiConfig;
-import org.chromium.components.data_sharing.configs.DataSharingPreviewDataConfig;
 import org.chromium.components.data_sharing.configs.DataSharingPreviewDetailsConfig;
 import org.chromium.components.data_sharing.configs.DataSharingRuntimeDataConfig;
 import org.chromium.components.data_sharing.configs.DataSharingStringConfig;
 import org.chromium.components.data_sharing.configs.DataSharingUiConfig;
 import org.chromium.components.tab_group_sync.LocalTabGroupId;
 import org.chromium.components.tab_group_sync.SavedTabGroup;
+import org.chromium.components.tab_group_sync.SavedTabGroupTab;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
 import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.components.tab_group_sync.TriggerSource;
@@ -402,28 +403,41 @@
                                         .setSharedDataPreview(previewData.sharedDataPreview)
                                         .build()));
 
-        fetchFavicons(
-                activity,
-                joinFlowTracker,
-                preview,
-                /* fetchAll= */ false,
-                () -> {
-                    fetchFavicons(
-                            activity, joinFlowTracker, preview, /* fetchAll= */ true, () -> {});
-                });
+        fetchFavicons(activity, joinFlowTracker.getSessionId(), preview.tabs);
     }
 
-    private void fetchFavicons(
+    private void fetchFavicons(Activity activity, String sessionId, List<TabPreview> tabs) {
+        // First fetch favicons for up to 4 tabs, then fetch favicons for the remaining tabs.
+        Runnable onFetched = () -> {};
+        int previewImageSize = 4;
+        if (tabs.size() > previewImageSize) {
+            onFetched =
+                    () -> {
+                        fetchFaviconsInternal(
+                                activity, sessionId, tabs, /* maxTabs= */ tabs.size(), () -> {});
+                    };
+        }
+        fetchFaviconsInternal(
+                activity, sessionId, tabs, /* maxTabs= */ previewImageSize, onFetched);
+    }
+
+    private void fetchFaviconsInternal(
             Activity activity,
-            JoinFlowTracker joinFlowTracker,
-            SharedTabGroupPreview preview,
-            boolean fetchAll,
+            String sessionId,
+            List<TabPreview> tabs,
+            int maxTabs,
             Runnable doneCallback) {
-        int maxNumToFetch = fetchAll ? preview.tabs.size() : 4;
-        int numToFetch = Math.min(maxNumToFetch, preview.tabs.size());
         List<GURL> urls = new ArrayList<>();
-        for (int i = 0; i < numToFetch; ++i) {
-            urls.add(preview.tabs.get(i).url);
+        List<String> displayUrls = new ArrayList<>();
+
+        // Fetch URLs for favicons (up to maxTabs).
+        for (int i = 0; i < Math.min(maxTabs, tabs.size()); i++) {
+            urls.add(tabs.get(i).url);
+        }
+
+        // Always collect all display URLs.
+        for (TabPreview tab : tabs) {
+            displayUrls.add(tab.displayUrl);
         }
         mBulkFaviconUtil.fetchAsBitmap(
                 activity,
@@ -432,50 +446,39 @@
                 // TODO(haileywang): add this to resources when using it in service.
                 /* size= */ 72,
                 (favicons) -> {
-                    if (fetchAll) {
-                        updateAllFavicons(joinFlowTracker, preview, favicons);
-                    } else {
-                        updatePreviewImage(joinFlowTracker, favicons);
-                    }
+                    updateFavicons(sessionId, displayUrls, favicons);
                     doneCallback.run();
                 });
     }
 
-    private void updateAllFavicons(
-            JoinFlowTracker joinFlowTracker, SharedTabGroupPreview preview, List<Bitmap> favicons) {
-        List<DataSharingPreviewDetailsConfig.TabPreview> tabPreviews = new ArrayList<>();
-        for (int i = 0; i < favicons.size(); ++i) {
-            tabPreviews.add(
+    private void updateFavicons(String sessionId, List<String> displayUrls, List<Bitmap> favicons) {
+        List<DataSharingPreviewDetailsConfig.TabPreview> tabsPreviewList = new ArrayList<>();
+        for (int i = 0; i < displayUrls.size(); i++) {
+            tabsPreviewList.add(
                     new DataSharingPreviewDetailsConfig.TabPreview(
-                            preview.tabs.get(i).displayUrl, favicons.get(i)));
+                            displayUrls.get(i), i < favicons.size() ? favicons.get(i) : null));
         }
         DataSharingRuntimeDataConfig runtimeConfig =
                 new DataSharingRuntimeDataConfig.Builder()
-                        .setSessionId(joinFlowTracker.getSessionId())
+                        .setSessionId(sessionId)
                         .setDataSharingPreviewDetailsConfig(
                                 new DataSharingPreviewDetailsConfig.Builder()
-                                        .setTabPreviews(tabPreviews)
+                                        .setTabPreviews(tabsPreviewList)
                                         .build())
                         .build();
-        mDataSharingService
-                .getUiDelegate()
-                .updateRuntimeData(joinFlowTracker.getSessionId(), runtimeConfig);
+        mDataSharingService.getUiDelegate().updateRuntimeData(sessionId, runtimeConfig);
     }
 
-    private void updatePreviewImage(JoinFlowTracker joinFlowTracker, List<Bitmap> favicons) {
-        // TODO(ssid): Make bitmap of the grid view.
-        Bitmap previewImage = favicons.get(0);
-        DataSharingRuntimeDataConfig runtimeConfig =
-                new DataSharingRuntimeDataConfig.Builder()
-                        .setSessionId(joinFlowTracker.getSessionId())
-                        .setDataSharingPreviewDataConfig(
-                                new DataSharingPreviewDataConfig.Builder()
-                                        .setTabGroupPreviewImage(previewImage)
-                                        .build())
-                        .build();
-        mDataSharingService
-                .getUiDelegate()
-                .updateRuntimeData(joinFlowTracker.getSessionId(), runtimeConfig);
+    private List<TabPreview> convertToTabsPreviewList(
+            List<SavedTabGroupTab> savedTabs, int maxTabs) {
+        int tabsCount = Math.min(maxTabs, savedTabs.size());
+        List<TabPreview> preview = new ArrayList<>();
+        for (int i = 0; i < tabsCount; ++i) {
+            // displayUrl field is not used in the create or manage UI where local tab group is
+            // available.
+            preview.add(new TabPreview(savedTabs.get(i).url, /* displayUrl= */ ""));
+        }
+        return preview;
     }
 
     private void showInvitationFailureDialog() {
@@ -637,13 +640,17 @@
                         public void getDataSharingUrl(
                                 GroupToken tokenSecret, Callback<String> url) {}
                     };
-            uiDelegate.showCreateFlow(
-                    new DataSharingCreateUiConfig.Builder()
-                            .setCommonConfig(
-                                    getCommonConfig(activity, tabGroupDisplayName, stringConfig))
-                            .setCreateCallback(createCallback)
-                            .build());
 
+            String sessionId =
+                    uiDelegate.showCreateFlow(
+                            new DataSharingCreateUiConfig.Builder()
+                                    .setCommonConfig(
+                                            getCommonConfig(
+                                                    activity, tabGroupDisplayName, stringConfig))
+                                    .setCreateCallback(createCallback)
+                                    .build());
+            fetchFavicons(
+                    activity, sessionId, convertToTabsPreviewList(existingGroup.savedTabs, 4));
             return;
         }
 
@@ -790,8 +797,7 @@
         DataSharingUiConfig.DataSharingCallback dataSharingCallback =
                 new DataSharingUiConfig.DataSharingCallback() {
                     @Override
-                    public void onLearnMoreAboutSharedTabGroupsClicked(
-                            Context context, String url) {
+                    public void onLearnMoreAboutSharedTabGroupsClicked(Context context, GURL url) {
                         mDataSharingTabGroupsDelegate.openLearnMoreSharedTabGroupsPage(
                                 context, url);
                     }
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java
index 1731b8e..8c7ece2 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingTabManagerUnitTest.java
@@ -198,6 +198,7 @@
         mSavedTabGroup.collaborationId = COLLABORATION_ID1;
         mSavedTabGroup.localId = LOCAL_ID;
         mSavedTabGroup.savedTabs = SyncedGroupTestHelper.tabsFromIds(TAB_ID);
+        mSavedTabGroup.savedTabs.get(0).url = new GURL("https://www.example.com/");
 
         when(mDataSharingService.getUiDelegate()).thenReturn(mDataSharingUiDelegate);
         when(mProfile.getOriginalProfile()).thenReturn(mProfile);
@@ -493,6 +494,9 @@
     @Test
     @EnableFeatures({ChromeFeatureList.DATA_SHARING_ANDROID_V2})
     public void testCreateFlowWithNewTabGroup() {
+        mDataSharingTabManager
+                .getBulkFaviconUtilForTesting()
+                .setFaviconHelperForTesting(mFaviconHelper);
         doReturn(mProfile).when(mProfile).getOriginalProfile();
         doReturn(null).when(mTabGroupSyncService).getGroup(LOCAL_ID);
 
@@ -533,6 +537,9 @@
     @Test
     @EnableFeatures({ChromeFeatureList.DATA_SHARING_ANDROID_V2})
     public void testCreateFlowCancelled() {
+        mDataSharingTabManager
+                .getBulkFaviconUtilForTesting()
+                .setFaviconHelperForTesting(mFaviconHelper);
         doReturn(mProfile).when(mProfile).getOriginalProfile();
         doReturn(null).when(mTabGroupSyncService).getGroup(LOCAL_ID);
 
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
index e3c94a05..793adcedb 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProvider.java
@@ -52,8 +52,4 @@
 
     /** Called when the module is hidden. */
     default void destroy() {}
-
-    /** Gets the type of the card. */
-    @EducationalTipCardType
-    int getCardType();
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java
index 1dd92955..2a01a39 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandler.java
@@ -6,7 +6,6 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.ResettersForTesting;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.EducationalTipCardType;
 import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
 import org.chromium.chrome.browser.tabmodel.TabGroupModelFilterProvider;
@@ -18,52 +17,42 @@
 import org.chromium.components.segmentation_platform.InputContext;
 import org.chromium.components.segmentation_platform.ProcessedValue;
 
-import java.util.HashSet;
-
-/**
- * Provides information about the signals of cards in the educational tip module.
- *
- * <p>This class serves as a single educational tip module's cards signals' logic gateway.
- */
+/** Provides information about the signals of cards in the educational tip module. */
 public class EducationalTipCardProviderSignalHandler {
-    /**
-     * A list includes all card types (excluding the default browser promo card) that have been
-     * displayed to the user during the current session.
-     */
-    private final HashSet<Integer> mVisibleCardList;
-
-    /** Static class that implements the initialization-on-demand holder idiom. */
-    private static class LazyHolder {
-        static EducationalTipCardProviderSignalHandler sInstance =
-                new EducationalTipCardProviderSignalHandler();
-    }
-
-    /** Returns the singleton instance of EducationalTipCardProviderSignalHandler. */
-    public static EducationalTipCardProviderSignalHandler getInstance() {
-        return EducationalTipCardProviderSignalHandler.LazyHolder.sInstance;
-    }
-
-    EducationalTipCardProviderSignalHandler() {
-        mVisibleCardList = new HashSet<>();
-    }
-
     /** Creates an instance of InputContext. */
     @VisibleForTesting
-    InputContext createInputContext(
-            EducationTipModuleActionDelegate actionDelegate, Tracker tracker) {
+    static InputContext createInputContext(
+            @EducationalTipCardType int cardType,
+            EducationTipModuleActionDelegate actionDelegate,
+            Tracker tracker) {
         InputContext inputContext = new InputContext();
-        inputContext.addEntry(
-                "should_show_non_role_manager_default_browser_promo",
-                ProcessedValue.fromFloat(
-                        shouldShowNonRoleManagerDefaultBrowserPromo(actionDelegate)));
-        inputContext.addEntry(
-                "has_default_browser_promo_shown_in_other_surface",
-                ProcessedValue.fromFloat(hasDefaultBrowserPromoShownInOtherSurface(tracker)));
-        inputContext.addEntry(
-                "tab_group_exists", ProcessedValue.fromFloat(tabGroupExists(actionDelegate)));
-        inputContext.addEntry(
-                "number_of_tabs", ProcessedValue.fromFloat(getCurrentTabCount(actionDelegate)));
-        return inputContext;
+        switch (cardType) {
+            case EducationalTipCardType.DEFAULT_BROWSER_PROMO:
+                inputContext.addEntry(
+                        "should_show_non_role_manager_default_browser_promo",
+                        ProcessedValue.fromFloat(
+                                shouldShowNonRoleManagerDefaultBrowserPromo(actionDelegate)));
+                inputContext.addEntry(
+                        "has_default_browser_promo_shown_in_other_surface",
+                        ProcessedValue.fromFloat(
+                                hasDefaultBrowserPromoShownInOtherSurface(tracker)));
+                return inputContext;
+            case EducationalTipCardType.TAB_GROUP:
+                inputContext.addEntry(
+                        "tab_group_exists",
+                        ProcessedValue.fromFloat(tabGroupExists(actionDelegate)));
+                inputContext.addEntry(
+                        "number_of_tabs",
+                        ProcessedValue.fromFloat(getCurrentTabCount(actionDelegate)));
+                return inputContext;
+            case EducationalTipCardType.TAB_GROUP_SYNC:
+                return inputContext;
+            case EducationalTipCardType.QUICK_DELETE:
+                return inputContext;
+            default:
+                assert false : "Card type not supported!";
+                return inputContext;
+        }
     }
 
     /**
@@ -71,7 +60,7 @@
      *     to indicate that a default browser promo, other than the Role Manager Promo, should be
      *     displayed. If not, it returns 0.0f.
      */
-    private float shouldShowNonRoleManagerDefaultBrowserPromo(
+    private static float shouldShowNonRoleManagerDefaultBrowserPromo(
             EducationTipModuleActionDelegate actionDelegate) {
         return DefaultBrowserPromoUtils.getInstance()
                         .shouldShowNonRoleManagerPromo(actionDelegate.getContext())
@@ -85,7 +74,7 @@
      * messages, or alternative NTPs. If the promotion has not been shown within this timeframe, the
      * function returns 0.0f.
      */
-    private float hasDefaultBrowserPromoShownInOtherSurface(Tracker tracker) {
+    private static float hasDefaultBrowserPromoShownInOtherSurface(Tracker tracker) {
         return tracker.wouldTriggerHelpUi(FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK)
                 ? 0.0f
                 : 1.0f;
@@ -95,7 +84,7 @@
      * Returns a value of 1.0f if a tab group exists within either the normal or incognito TabModel.
      * Otherwise, it returns 0.0f.
      */
-    private float tabGroupExists(EducationTipModuleActionDelegate actionDelegate) {
+    private static float tabGroupExists(EducationTipModuleActionDelegate actionDelegate) {
         TabGroupModelFilterProvider provider =
                 actionDelegate.getTabModelSelector().getTabGroupModelFilterProvider();
         TabGroupModelFilter normalFilter =
@@ -107,32 +96,10 @@
     }
 
     /** Returns the total number of tabs across both regular and incognito browsing modes. */
-    private float getCurrentTabCount(EducationTipModuleActionDelegate actionDelegate) {
+    private static float getCurrentTabCount(EducationTipModuleActionDelegate actionDelegate) {
         TabModelSelector tabModelSelector = actionDelegate.getTabModelSelector();
         TabModel normalModel = tabModelSelector.getModel(/* incognito= */ false);
         TabModel incognitoModel = tabModelSelector.getModel(/* incognito= */ true);
         return normalModel.getCount() + incognitoModel.getCount();
     }
-
-    /**
-     * Returns true if this is the first time the card is displayed to the user in the current
-     * session and the event should be recorded.
-     */
-    boolean shouldNotifyCardShownPerSession(@EducationalTipCardType int cardType) {
-        // Ensure that the default browser promo card does not trigger this function.
-        assert cardType < EducationalTipCardType.NUM_ENTRIES && cardType > 0;
-
-        if (mVisibleCardList.contains(cardType)) {
-            return false;
-        }
-
-        return mVisibleCardList.add(cardType);
-    }
-
-    static void setInstanceForTesting(EducationalTipCardProviderSignalHandler testInstance) {
-        var oldInstance = EducationalTipCardProviderSignalHandler.LazyHolder.sInstance;
-        EducationalTipCardProviderSignalHandler.LazyHolder.sInstance = testInstance;
-        ResettersForTesting.register(
-                () -> EducationalTipCardProviderSignalHandler.LazyHolder.sInstance = oldInstance);
-    }
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
index 059589a..244514e3 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilder.java
@@ -10,25 +10,30 @@
 import androidx.annotation.NonNull;
 
 import org.chromium.base.Callback;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleConfigChecker;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
 import org.chromium.chrome.browser.magic_stack.ModuleProviderBuilder;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.segmentation_platform.InputContext;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
 public class EducationalTipModuleBuilder implements ModuleProviderBuilder, ModuleConfigChecker {
     private final EducationTipModuleActionDelegate mActionDelegate;
-    private final @ModuleType int mModuuleType;
+    private final @ModuleType int mModuleType;
+    private Profile mProfile;
 
     /** Pass in the dependencies needed to build {@link EducationalTipModuleCoordinator}. */
     public EducationalTipModuleBuilder(
             @ModuleType int moduleTypeToBuild,
             @NonNull EducationTipModuleActionDelegate actionDelegate) {
-        mModuuleType = moduleTypeToBuild;
+        mModuleType = moduleTypeToBuild;
         mActionDelegate = actionDelegate;
     }
 
@@ -37,12 +42,18 @@
     public boolean build(
             @NonNull ModuleDelegate moduleDelegate,
             @NonNull Callback<ModuleProvider> onModuleBuiltCallback) {
-        if (!ChromeFeatureList.sEducationalTipModule.isEnabled()) {
+        if (!ChromeFeatureList.sEducationalTipModule.isEnabled()
+                || !ChromeFeatureList.isEnabled(
+                        ChromeFeatureList.SEGMENTATION_PLATFORM_EPHEMERAL_CARD_RANKER)) {
             return false;
         }
 
         EducationalTipModuleCoordinator coordinator =
-                new EducationalTipModuleCoordinator(mModuuleType, moduleDelegate, mActionDelegate);
+                new EducationalTipModuleCoordinator(
+                        mModuleType,
+                        moduleDelegate,
+                        mActionDelegate,
+                        getRegularProfile(mActionDelegate.getProfileSupplier()));
         onModuleBuiltCallback.onResult(coordinator);
         return true;
     }
@@ -73,7 +84,22 @@
 
     @Override
     public InputContext createInputContext() {
-        // TODO(https://crbug.com/382803396): Implement this using signal utility.
-        return null;
+        int cardType = EducationalTipModuleUtils.getCardType(mModuleType);
+        Tracker tracker =
+                TrackerFactory.getTrackerForProfile(
+                        getRegularProfile(mActionDelegate.getProfileSupplier()));
+        return EducationalTipCardProviderSignalHandler.createInputContext(
+                cardType, mActionDelegate, tracker);
+    }
+
+    /** Gets the regular profile if exists. */
+    private Profile getRegularProfile(ObservableSupplier<Profile> profileSupplier) {
+        if (mProfile != null) {
+            return mProfile;
+        }
+
+        assert profileSupplier.hasValue();
+        mProfile = profileSupplier.get().getOriginalProfile();
+        return mProfile;
     }
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
index 8cdcacf..87ec3ae 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleCoordinator.java
@@ -11,6 +11,7 @@
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Coordinator for the educational tip module. */
@@ -20,10 +21,12 @@
     public EducationalTipModuleCoordinator(
             @ModuleType int moduleType,
             @NonNull ModuleDelegate moduleDelegate,
-            @NonNull EducationTipModuleActionDelegate actionDelegate) {
+            @NonNull EducationTipModuleActionDelegate actionDelegate,
+            @NonNull Profile profile) {
         PropertyModel model = new PropertyModel(EducationalTipModuleProperties.ALL_KEYS);
         mMediator =
-                new EducationalTipModuleMediator(moduleType, model, moduleDelegate, actionDelegate);
+                new EducationalTipModuleMediator(
+                        moduleType, model, moduleDelegate, actionDelegate, profile);
     }
 
     // ModuleProvider implementation.
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
index cb888da..82936e0 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediator.java
@@ -9,10 +9,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.CallbackController;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.EducationalTipCardType;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -20,19 +18,14 @@
 import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils.DefaultBrowserPromoTriggerStateListener;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
-import org.chromium.components.segmentation_platform.PredictionOptions;
 import org.chromium.ui.modelutil.PropertyModel;
 
 /** Mediator for the educational tip module. */
 public class EducationalTipModuleMediator {
-    @VisibleForTesting static final String FORCE_TAB_GROUP = "force_tab_group";
-    @VisibleForTesting static final String FORCE_TAB_GROUP_SYNC = "force_tab_group_sync";
-    @VisibleForTesting static final String FORCE_QUICK_DELETE = "force_quick_delete";
-    @VisibleForTesting static final String FORCE_DEFAULT_BROWSER = "force_default_browser";
-
     private final EducationTipModuleActionDelegate mActionDelegate;
     private final Profile mProfile;
     private final @ModuleType int mModuleType;
+    private final @EducationalTipCardType int mCardType;
     private final PropertyModel mModel;
     private final ModuleDelegate mModuleDelegate;
     private final CallbackController mCallbackController;
@@ -45,12 +38,14 @@
             @ModuleType int moduleType,
             @NonNull PropertyModel model,
             @NonNull ModuleDelegate moduleDelegate,
-            EducationTipModuleActionDelegate actionDelegate) {
+            EducationTipModuleActionDelegate actionDelegate,
+            @NonNull Profile profile) {
         mModuleType = moduleType;
+        mCardType = EducationalTipModuleUtils.getCardType(mModuleType);
         mModel = model;
         mModuleDelegate = moduleDelegate;
         mActionDelegate = actionDelegate;
-        mProfile = getRegularProfile(mActionDelegate.getProfileSupplier());
+        mProfile = profile;
         mTracker = TrackerFactory.getTrackerForProfile(mProfile);
         mDefaultBrowserPromoTriggerStateListener = this::removeModule;
 
@@ -59,40 +54,21 @@
 
     /** Show the educational tip module. */
     void showModule() {
-        @EducationalTipCardType Integer forcedCardType = getForcedCardType();
-        if (forcedCardType != null) {
-            showModuleWithCardInfo(forcedCardType);
-        } else if (ChromeFeatureList.isEnabled(
-                ChromeFeatureList.SEGMENTATION_PLATFORM_EPHEMERAL_CARD_RANKER)) {
-            showModuleWithCardInfo(EducationalTipModuleUtils.getCardType(mModuleType));
-        } else {
-            // The educational tip module doesn’t display any card when no card is forced to show
-            // and the ephemeral card ranker for the segmentation platform service is disabled.
-            showModuleWithCardInfo(/* cardType= */ null);
-        }
+        showModuleWithCardInfo(mCardType);
     }
 
     /** Called when the educational tip module is visible to users on the magic stack. */
     void onViewCreated() {
-        // TODO(https://crbug.com/382803396): Get it from the moduleType instead.
-        @EducationalTipCardType int cardType = mEducationalTipCardProvider.getCardType();
-        if (cardType == EducationalTipCardType.DEFAULT_BROWSER_PROMO) {
+        if (mCardType == EducationalTipCardType.DEFAULT_BROWSER_PROMO) {
             boolean shouldDisplay =
                     mTracker.shouldTriggerHelpUi(
                             FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK);
-            // The shouldDisplay flag should be true in this situation because if the other default
-            // browser promotion is visible to the user, this educational tip module should already
-            // be hidden.
-            if (!ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                    ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_DEFAULT_BROWSER, false)) {
-                assert shouldDisplay;
+            if (shouldDisplay) {
+                DefaultBrowserPromoUtils defaultBrowserPromoUtils =
+                        DefaultBrowserPromoUtils.getInstance();
+                defaultBrowserPromoUtils.removeListener(mDefaultBrowserPromoTriggerStateListener);
+                defaultBrowserPromoUtils.notifyDefaultBrowserPromoVisible();
             }
-
-            DefaultBrowserPromoUtils defaultBrowserPromoUtils =
-                    DefaultBrowserPromoUtils.getInstance();
-            defaultBrowserPromoUtils.removeListener(mDefaultBrowserPromoTriggerStateListener);
-            defaultBrowserPromoUtils.notifyDefaultBrowserPromoVisible();
-            return;
         }
     }
 
@@ -130,30 +106,6 @@
         mModuleDelegate.onDataReady(mModuleType, mModel);
     }
 
-    @EducationalTipCardType
-    private @Nullable Integer getForcedCardType() {
-        if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_DEFAULT_BROWSER, false)) {
-            return EducationalTipCardType.DEFAULT_BROWSER_PROMO;
-        } else if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_TAB_GROUP, false)) {
-            return EducationalTipCardType.TAB_GROUP;
-        } else if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_TAB_GROUP_SYNC, false)) {
-            return EducationalTipCardType.TAB_GROUP_SYNC;
-        } else if (ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, FORCE_QUICK_DELETE, false)) {
-            return EducationalTipCardType.QUICK_DELETE;
-        }
-        return null;
-    }
-
-    /** Creates an instance of PredictionOptions. */
-    @VisibleForTesting
-    PredictionOptions createPredictionOptions() {
-        return new PredictionOptions(/* onDemandExecution= */ true);
-    }
-
     @ModuleType
     int getModuleType() {
         return mModuleType;
@@ -191,13 +143,6 @@
         mModuleDelegate.onModuleClicked(mModuleType);
     }
 
-    /** Gets the regular profile if exists. */
-    private Profile getRegularProfile(ObservableSupplier<Profile> profileSupplier) {
-        assert profileSupplier.hasValue();
-
-        return profileSupplier.get().getOriginalProfile();
-    }
-
     DefaultBrowserPromoTriggerStateListener getDefaultBrowserPromoTriggerStateListenerForTesting() {
         return mDefaultBrowserPromoTriggerStateListener;
     }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoCoordinator.java
index 3d24171..9f4c184 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoCoordinator.java
@@ -93,11 +93,6 @@
         }
     }
 
-    @Override
-    public @EducationalTipCardType int getCardType() {
-        return EducationalTipCardType.DEFAULT_BROWSER_PROMO;
-    }
-
     private Intent createBottomSheetOnClickIntent() {
         Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/QuickDeletePromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/QuickDeletePromoCoordinator.java
index 4123d1e..737597c 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/QuickDeletePromoCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/QuickDeletePromoCoordinator.java
@@ -59,9 +59,4 @@
     public void onCardClicked() {
         mOnClickedRunnable.run();
     }
-
-    @Override
-    public @EducationalTipCardType int getCardType() {
-        return EducationalTipCardType.QUICK_DELETE;
-    }
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
index 2e33e5e..39507f2 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupPromoCoordinator.java
@@ -58,9 +58,4 @@
     public void onCardClicked() {
         mOnClickedRunnable.run();
     }
-
-    @Override
-    public @EducationalTipCardType int getCardType() {
-        return EducationalTipCardType.TAB_GROUP;
-    }
 }
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java
index b0c4bd1..04f81d6 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/TabGroupSyncPromoCoordinator.java
@@ -62,9 +62,4 @@
     public void onCardClicked() {
         mOnClickedRunnable.run();
     }
-
-    @Override
-    public @EducationalTipCardType int getCardType() {
-        return EducationalTipCardType.TAB_GROUP_SYNC;
-    }
 }
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandlerUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandlerUnitTest.java
index cd2bb63..ddc27b4 100644
--- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandlerUnitTest.java
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipCardProviderSignalHandlerUnitTest.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.educational_tip;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
@@ -53,13 +52,11 @@
     @Mock private TabModel mIncognitoModel;
     @Mock private TabGroupModelFilterProvider mProvider;
 
-    private EducationalTipCardProviderSignalHandler mEducationalTipCardProviderSignalHandler;
     private Context mContext;
 
     @Before
     public void setUp() {
         mContext = ApplicationProvider.getApplicationContext();
-        mEducationalTipCardProviderSignalHandler = new EducationalTipCardProviderSignalHandler();
         when(mActionDelegate.getContext()).thenReturn(mContext);
         when(mActionDelegate.getTabModelSelector()).thenReturn(mTabModelSelector);
         when(mTabModelSelector.getTabGroupModelFilterProvider()).thenReturn(mProvider);
@@ -75,20 +72,20 @@
     @Test
     @SmallTest
     @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
-    public void testCreateInputContext() {
+    public void testCreateInputContext_DefaultBrowserPromoCard() {
         assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
 
         InputContext inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
-        assertEquals(4, inputContext.getSizeForTesting());
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.DEFAULT_BROWSER_PROMO, mActionDelegate, mTracker);
+        assertEquals(2, inputContext.getSizeForTesting());
 
         // Test signal "should_show_non_role_manager_default_browser_promo".
         when(mMockDefaultBrowserPromoUtils.shouldShowNonRoleManagerPromo(mContext))
                 .thenReturn(true);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.DEFAULT_BROWSER_PROMO, mActionDelegate, mTracker);
         assertEquals(
                 1,
                 inputContext.getEntryForTesting(
@@ -99,8 +96,8 @@
         when(mMockDefaultBrowserPromoUtils.shouldShowNonRoleManagerPromo(mContext))
                 .thenReturn(false);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.DEFAULT_BROWSER_PROMO, mActionDelegate, mTracker);
         assertEquals(
                 0,
                 inputContext.getEntryForTesting(
@@ -112,8 +109,8 @@
         when(mTracker.wouldTriggerHelpUi(FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK))
                 .thenReturn(true);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.DEFAULT_BROWSER_PROMO, mActionDelegate, mTracker);
         assertEquals(
                 0,
                 inputContext.getEntryForTesting("has_default_browser_promo_shown_in_other_surface")
@@ -123,73 +120,68 @@
         when(mTracker.wouldTriggerHelpUi(FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK))
                 .thenReturn(false);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.DEFAULT_BROWSER_PROMO, mActionDelegate, mTracker);
         assertEquals(
                 1,
                 inputContext.getEntryForTesting("has_default_browser_promo_shown_in_other_surface")
                         .floatValue,
                 0.01);
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
+    public void testCreateInputContext_TabGroupPromoCard() {
+        assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
+
+        InputContext inputContext =
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
+        assertEquals(2, inputContext.getSizeForTesting());
 
         // Test signal "tab_group_exists".
         when(mNormalFilter.getTabGroupCount()).thenReturn(0);
         when(mIncognitoFilter.getTabGroupCount()).thenReturn(0);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(0, inputContext.getEntryForTesting("tab_group_exists").floatValue, 0.01);
 
         when(mNormalFilter.getTabGroupCount()).thenReturn(5);
         when(mIncognitoFilter.getTabGroupCount()).thenReturn(6);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(1, inputContext.getEntryForTesting("tab_group_exists").floatValue, 0.01);
 
         // Test signal "number_of_tabs".
         when(mNormalModel.getCount()).thenReturn(0);
         when(mIncognitoModel.getCount()).thenReturn(0);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(0, inputContext.getEntryForTesting("number_of_tabs").floatValue, 0.01);
 
         when(mNormalModel.getCount()).thenReturn(5);
         when(mIncognitoModel.getCount()).thenReturn(0);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(5, inputContext.getEntryForTesting("number_of_tabs").floatValue, 0.01);
 
         when(mNormalModel.getCount()).thenReturn(0);
         when(mIncognitoModel.getCount()).thenReturn(10);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(10, inputContext.getEntryForTesting("number_of_tabs").floatValue, 0.01);
 
         when(mNormalModel.getCount()).thenReturn(10);
         when(mIncognitoModel.getCount()).thenReturn(10);
         inputContext =
-                mEducationalTipCardProviderSignalHandler.createInputContext(
-                        mActionDelegate, mTracker);
+                EducationalTipCardProviderSignalHandler.createInputContext(
+                        EducationalTipCardType.TAB_GROUP, mActionDelegate, mTracker);
         assertEquals(20, inputContext.getEntryForTesting("number_of_tabs").floatValue, 0.01);
     }
-
-    @Test
-    @SmallTest
-    public void testShouldNotifyCardShownPerSession() {
-        for (int cardType = 1; cardType < EducationalTipCardType.NUM_ENTRIES; cardType++) {
-            assertTrue(
-                    mEducationalTipCardProviderSignalHandler.shouldNotifyCardShownPerSession(
-                            cardType));
-
-            assertFalse(
-                    mEducationalTipCardProviderSignalHandler.shouldNotifyCardShownPerSession(
-                            cardType));
-            assertFalse(
-                    mEducationalTipCardProviderSignalHandler.shouldNotifyCardShownPerSession(
-                            cardType));
-        }
-    }
 }
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
index 68474aa9..fcf9b1b8 100644
--- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleBuilderUnitTest.java
@@ -5,12 +5,17 @@
 package org.chromium.chrome.browser.educational_tip;
 
 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.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
@@ -30,9 +35,17 @@
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate;
+import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
 import org.chromium.chrome.browser.magic_stack.ModuleProvider;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilterProvider;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils;
+import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
+import org.chromium.components.segmentation_platform.InputContext;
 import org.chromium.ui.shadows.ShadowAppCompatResources;
 
 /** Test relating to {@link EducationalTipModuleBuilder} */
@@ -49,16 +62,40 @@
     @Mock private ObservableSupplier<Profile> mProfileSupplier;
     @Mock private Profile mProfile;
     @Mock private Tracker mTracker;
+    @Mock private DefaultBrowserPromoUtils mMockDefaultBrowserPromoUtils;
+    @Mock private TabModelSelector mTabModelSelector;
+    @Mock private TabGroupModelFilterProvider mProvider;
+    @Mock private TabGroupModelFilter mNormalFilter;
+    @Mock private TabGroupModelFilter mIncognitoFilter;
+    @Mock private TabModel mNormalModel;
+    @Mock private TabModel mIncognitoModel;
 
     private EducationalTipModuleBuilder mModuleBuilder;
+    private Context mContext;
 
     @Before
     public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
         when(mActionDelegate.getProfileSupplier()).thenReturn(mProfileSupplier);
         when(mProfileSupplier.hasValue()).thenReturn(true);
         when(mProfileSupplier.get()).thenReturn(mProfile);
         when(mProfile.getOriginalProfile()).thenReturn(mProfile);
+        DefaultBrowserPromoUtils.setInstanceForTesting(mMockDefaultBrowserPromoUtils);
         TrackerFactory.setTrackerForTests(mTracker);
+        when(mTracker.wouldTriggerHelpUi(FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK))
+                .thenReturn(true);
+        when(mActionDelegate.getTabModelSelector()).thenReturn(mTabModelSelector);
+        when(mTabModelSelector.getTabGroupModelFilterProvider()).thenReturn(mProvider);
+        when(mProvider.getTabGroupModelFilter(/* isIncognito= */ false)).thenReturn(mNormalFilter);
+        when(mProvider.getTabGroupModelFilter(/* isIncognito= */ true))
+                .thenReturn(mIncognitoFilter);
+        when(mNormalFilter.getTabGroupCount()).thenReturn(0);
+        when(mIncognitoFilter.getTabGroupCount()).thenReturn(0);
+        when(mTabModelSelector.getModel(/* incognito= */ false)).thenReturn(mNormalModel);
+        when(mTabModelSelector.getModel(/* incognito= */ true)).thenReturn(mIncognitoModel);
+        when(mNormalModel.getCount()).thenReturn(0);
+        when(mIncognitoModel.getCount()).thenReturn(0);
+
         mModuleBuilder =
                 new EducationalTipModuleBuilder(
                         ModuleDelegate.ModuleType.DEFAULT_BROWSER_PROMO, mActionDelegate);
@@ -76,11 +113,44 @@
 
     @Test
     @SmallTest
-    @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
+    @EnableFeatures({
+        ChromeFeatureList.EDUCATIONAL_TIP_MODULE,
+        ChromeFeatureList.SEGMENTATION_PLATFORM_EPHEMERAL_CARD_RANKER
+    })
     public void testBuildEducationalTipModule_Eligible() {
         assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
 
         assertTrue(mModuleBuilder.build(mModuleDelegate, mBuildCallback));
         verify(mBuildCallback).onResult(any(ModuleProvider.class));
     }
+
+    @Test
+    @SmallTest
+    @EnableFeatures({
+        ChromeFeatureList.EDUCATIONAL_TIP_MODULE,
+        ChromeFeatureList.SEGMENTATION_PLATFORM_EPHEMERAL_CARD_RANKER
+    })
+    public void testCreateInputContext() {
+        InputContext inputContextForTest = mModuleBuilder.createInputContext();
+        assertNotNull(
+                inputContextForTest.getEntryForTesting(
+                        "should_show_non_role_manager_default_browser_promo"));
+        assertNotNull(
+                inputContextForTest.getEntryForTesting(
+                        "has_default_browser_promo_shown_in_other_surface"));
+        assertNull(inputContextForTest.getEntryForTesting("tab_group_exists"));
+        assertNull(inputContextForTest.getEntryForTesting("number_of_tabs"));
+
+        EducationalTipModuleBuilder moduleBuilderForTabGroupPromo =
+                new EducationalTipModuleBuilder(ModuleType.TAB_GROUPS, mActionDelegate);
+        inputContextForTest = moduleBuilderForTabGroupPromo.createInputContext();
+        assertNull(
+                inputContextForTest.getEntryForTesting(
+                        "should_show_non_role_manager_default_browser_promo"));
+        assertNull(
+                inputContextForTest.getEntryForTesting(
+                        "has_default_browser_promo_shown_in_other_surface"));
+        assertNotNull(inputContextForTest.getEntryForTesting("tab_group_exists"));
+        assertNotNull(inputContextForTest.getEntryForTesting("number_of_tabs"));
+    }
 }
diff --git a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java
index 62684a10..84e5d27 100644
--- a/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java
+++ b/chrome/browser/educational_tip/junit/src/org/chromium/chrome/browser/educational_tip/EducationalTipModuleMediatorUnitTest.java
@@ -10,11 +10,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static org.chromium.chrome.browser.educational_tip.EducationalTipModuleMediator.FORCE_DEFAULT_BROWSER;
-import static org.chromium.chrome.browser.educational_tip.EducationalTipModuleMediator.FORCE_QUICK_DELETE;
-import static org.chromium.chrome.browser.educational_tip.EducationalTipModuleMediator.FORCE_TAB_GROUP;
-import static org.chromium.chrome.browser.educational_tip.EducationalTipModuleMediator.FORCE_TAB_GROUP_SYNC;
-
 import android.content.Context;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -32,7 +27,6 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.FeatureList;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.educational_tip.EducationalTipCardProvider.EducationalTipCardType;
@@ -59,14 +53,10 @@
     @Mock private PropertyModel mModel;
     @Mock private ModuleDelegate mModuleDelegate;
     @Mock private EducationTipModuleActionDelegate mActionDelegate;
-    @Mock private ObservableSupplier<Profile> mProfileSupplier;
     @Mock private Profile mProfile;
     @Mock private Tracker mTracker;
     @Mock private DefaultBrowserPromoUtils mMockDefaultBrowserPromoUtils;
 
-    @Mock
-    private EducationalTipCardProviderSignalHandler mMockEducationalTipCardProviderSignalHandler;
-
     @Captor
     private ArgumentCaptor<DefaultBrowserPromoTriggerStateListener>
             mDefaultBrowserPromoTriggerStateListener;
@@ -81,54 +71,49 @@
         mParamsTestValues = new FeatureList.TestValues();
         mContext = ApplicationProvider.getApplicationContext();
         when(mActionDelegate.getContext()).thenReturn(mContext);
-        when(mActionDelegate.getProfileSupplier()).thenReturn(mProfileSupplier);
-        when(mProfileSupplier.hasValue()).thenReturn(true);
-        when(mProfileSupplier.get()).thenReturn(mProfile);
         when(mProfile.getOriginalProfile()).thenReturn(mProfile);
         mExpectedModuleType = ModuleType.DEFAULT_BROWSER_PROMO;
         TrackerFactory.setTrackerForTests(mTracker);
         DefaultBrowserPromoUtils.setInstanceForTesting(mMockDefaultBrowserPromoUtils);
-        EducationalTipCardProviderSignalHandler.setInstanceForTesting(
-                mMockEducationalTipCardProviderSignalHandler);
 
         mEducationalTipModuleMediator =
                 new EducationalTipModuleMediator(
-                        mExpectedModuleType, mModel, mModuleDelegate, mActionDelegate);
+                        mExpectedModuleType, mModel, mModuleDelegate, mActionDelegate, mProfile);
     }
 
     @Test
     @SmallTest
     @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
-    public void testShowModuleWithForcedCardType() {
+    public void testShowModuleWithCardInfo() {
         assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
 
         // Test showing default browser promo card.
-        testShowModuleWithForcedCardTypeImpl(
-                FORCE_DEFAULT_BROWSER,
+        testShowModuleWithCardInfoImpl(
+                EducationalTipCardType.DEFAULT_BROWSER_PROMO,
                 R.string.educational_tip_default_browser_title,
                 R.string.educational_tip_default_browser_description,
                 R.drawable.default_browser_promo_logo,
                 /* timesOfCall= */ 1);
 
         // Test showing tab group promo card.
-        testShowModuleWithForcedCardTypeImpl(
-                FORCE_TAB_GROUP,
+        testShowModuleWithCardInfoImpl(
+                EducationalTipCardType.TAB_GROUP,
                 R.string.educational_tip_tab_group_title,
                 R.string.educational_tip_tab_group_description,
                 R.drawable.tab_group_promo_logo,
                 /* timesOfCall= */ 2);
 
         // Test showing tab group sync promo card.
-        testShowModuleWithForcedCardTypeImpl(
-                FORCE_TAB_GROUP_SYNC,
+        testShowModuleWithCardInfoImpl(
+                EducationalTipCardType.TAB_GROUP_SYNC,
                 R.string.educational_tip_tab_group_sync_title,
                 R.string.educational_tip_tab_group_sync_description,
                 R.drawable.tab_group_sync_promo_logo,
                 /* timesOfCall= */ 3);
 
         // Test showing quick delete promo card.
-        testShowModuleWithForcedCardTypeImpl(
-                FORCE_QUICK_DELETE,
+        testShowModuleWithCardInfoImpl(
+                EducationalTipCardType.QUICK_DELETE,
                 R.string.educational_tip_quick_delete_title,
                 R.string.educational_tip_quick_delete_description,
                 R.drawable.quick_delete_promo_logo,
@@ -143,7 +128,11 @@
 
         mEducationalTipModuleMediator =
                 new EducationalTipModuleMediator(
-                        ModuleType.DEFAULT_BROWSER_PROMO, mModel, mModuleDelegate, mActionDelegate);
+                        ModuleType.DEFAULT_BROWSER_PROMO,
+                        mModel,
+                        mModuleDelegate,
+                        mActionDelegate,
+                        mProfile);
 
         when(mTracker.shouldTriggerHelpUi(FeatureConstants.DEFAULT_BROWSER_PROMO_MAGIC_STACK))
                 .thenReturn(true);
@@ -159,30 +148,7 @@
 
         mEducationalTipModuleMediator =
                 new EducationalTipModuleMediator(
-                        ModuleType.TAB_GROUPS, mModel, mModuleDelegate, mActionDelegate);
-        mEducationalTipModuleMediator.showModuleWithCardInfo(EducationalTipCardType.TAB_GROUP);
-        mEducationalTipModuleMediator.onViewCreated();
-    }
-
-    @Test
-    @SmallTest
-    @EnableFeatures({ChromeFeatureList.EDUCATIONAL_TIP_MODULE})
-    public void testOnViewCreated_TabGroupPromo() {
-        assertTrue(ChromeFeatureList.sEducationalTipModule.isEnabled());
-
-        mEducationalTipModuleMediator =
-                new EducationalTipModuleMediator(
-                        ModuleType.TAB_GROUPS, mModel, mModuleDelegate, mActionDelegate);
-
-        when(mMockEducationalTipCardProviderSignalHandler.shouldNotifyCardShownPerSession(
-                        EducationalTipCardType.TAB_GROUP))
-                .thenReturn(true);
-        mEducationalTipModuleMediator.showModuleWithCardInfo(EducationalTipCardType.TAB_GROUP);
-        mEducationalTipModuleMediator.onViewCreated();
-
-        when(mMockEducationalTipCardProviderSignalHandler.shouldNotifyCardShownPerSession(
-                        EducationalTipCardType.TAB_GROUP))
-                .thenReturn(false);
+                        ModuleType.TAB_GROUPS, mModel, mModuleDelegate, mActionDelegate, mProfile);
         mEducationalTipModuleMediator.showModuleWithCardInfo(EducationalTipCardType.TAB_GROUP);
         mEducationalTipModuleMediator.onViewCreated();
     }
@@ -203,16 +169,13 @@
                 .removeListener(mDefaultBrowserPromoTriggerStateListener.capture());
     }
 
-    private void testShowModuleWithForcedCardTypeImpl(
-            String enabledParam,
+    private void testShowModuleWithCardInfoImpl(
+            @EducationalTipCardType int cardType,
             int titleId,
             int descriptionId,
             int imageResource,
             int timesOfCall) {
-        mParamsTestValues.addFieldTrialParamOverride(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, enabledParam, "true");
-        FeatureList.setTestValues(mParamsTestValues);
-        mEducationalTipModuleMediator.showModule();
+        mEducationalTipModuleMediator.showModuleWithCardInfo(cardType);
 
         verify(mModel)
                 .set(
@@ -225,8 +188,5 @@
         verify(mModel).set(EducationalTipModuleProperties.MODULE_CONTENT_IMAGE, imageResource);
         verify(mModuleDelegate, times(timesOfCall)).onDataReady(mExpectedModuleType, mModel);
         verify(mModuleDelegate, never()).onDataFetchFailed(mExpectedModuleType);
-
-        mParamsTestValues.addFieldTrialParamOverride(
-                ChromeFeatureList.EDUCATIONAL_TIP_MODULE, enabledParam, "false");
     }
 }
diff --git a/chrome/browser/enterprise/data_controls/BUILD.gn b/chrome/browser/enterprise/data_controls/BUILD.gn
index 8be9810..31017f63 100644
--- a/chrome/browser/enterprise/data_controls/BUILD.gn
+++ b/chrome/browser/enterprise/data_controls/BUILD.gn
@@ -38,6 +38,16 @@
     "//url",
   ]
 
+  if (is_android) {
+    sources += [
+      "android_data_controls_dialog.cc",
+      "android_data_controls_dialog.h",
+      "android_data_controls_dialog_factory.cc",
+      "android_data_controls_dialog_factory.h",
+    ]
+    deps += [ "//ui/android" ]
+  }
+
   if (!is_android) {
     sources += [
       "desktop_data_controls_dialog.cc",
diff --git a/chrome/browser/enterprise/data_controls/android_data_controls_dialog.cc b/chrome/browser/enterprise/data_controls/android_data_controls_dialog.cc
new file mode 100644
index 0000000..cac70f3
--- /dev/null
+++ b/chrome/browser/enterprise/data_controls/android_data_controls_dialog.cc
@@ -0,0 +1,85 @@
+// Copyright 2024 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/enterprise/data_controls/android_data_controls_dialog.h"
+
+#include "base/functional/callback.h"
+#include "chrome/browser/enterprise/data_controls/android_data_controls_dialog.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/android/modal_dialog_wrapper.h"
+#include "ui/android/window_android.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/dialog_model.h"
+#include "ui/base/models/dialog_model_field.h"
+
+namespace data_controls {
+
+void AndroidDataControlsDialog::Show(base::OnceClosure on_destructed) {
+  on_destructed_ = std::move(on_destructed);
+
+  ui::DialogModel::Builder dialog_builder;
+  dialog_builder.SetTitle(GetDialogTitle())
+      .AddParagraph(ui::DialogModelLabel(GetDialogLabel()))
+      .AddOkButton(std::move(on_destructed_),
+                   ui::DialogModel::Button::Params().SetLabel(
+                       l10n_util::GetStringUTF16(IDS_OK)));
+
+  ui::WindowAndroid* window = web_contents()->GetTopLevelNativeWindow();
+  ui::ModalDialogWrapper::ShowTabModal(dialog_builder.Build(), window);
+}
+
+AndroidDataControlsDialog::~AndroidDataControlsDialog() {
+  if (on_destructed_) {
+    std::move(on_destructed_).Run();
+  }
+}
+
+std::u16string AndroidDataControlsDialog::GetDialogTitle() const {
+  int id;
+  switch (type_) {
+    case Type::kClipboardPasteBlock:
+      id = IDS_DATA_CONTROLS_CLIPBOARD_PASTE_BLOCK_TITLE;
+      break;
+
+    case Type::kClipboardCopyBlock:
+      id = IDS_DATA_CONTROLS_CLIPBOARD_COPY_BLOCK_TITLE;
+      break;
+
+    case Type::kClipboardPasteWarn:
+      id = IDS_DATA_CONTROLS_CLIPBOARD_PASTE_WARN_TITLE;
+      break;
+
+    case Type::kClipboardCopyWarn:
+      id = IDS_DATA_CONTROLS_CLIPBOARD_COPY_WARN_TITLE;
+      break;
+  }
+  return l10n_util::GetStringUTF16(id);
+}
+
+std::u16string AndroidDataControlsDialog::GetDialogLabel() const {
+  int id;
+  switch (type_) {
+    case Type::kClipboardPasteBlock:
+    case Type::kClipboardCopyBlock:
+      id = IDS_DATA_CONTROLS_BLOCKED_LABEL;
+      break;
+
+    case Type::kClipboardPasteWarn:
+    case Type::kClipboardCopyWarn:
+      id = IDS_DATA_CONTROLS_WARNED_LABEL;
+      break;
+  }
+  return l10n_util::GetStringUTF16(id);
+}
+
+AndroidDataControlsDialog::AndroidDataControlsDialog(
+    Type type,
+    content::WebContents* contents,
+    base::OnceCallback<void(bool bypassed)> callback)
+    : DataControlsDialog(type, std::move(callback)),
+      content::WebContentsObserver(contents) {}
+
+}  // namespace data_controls
diff --git a/chrome/browser/enterprise/data_controls/android_data_controls_dialog.h b/chrome/browser/enterprise/data_controls/android_data_controls_dialog.h
new file mode 100644
index 0000000..bd93b673
--- /dev/null
+++ b/chrome/browser/enterprise/data_controls/android_data_controls_dialog.h
@@ -0,0 +1,44 @@
+// Copyright 2024 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_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_H_
+#define CHROME_BROWSER_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_H_
+
+#include <vector>
+
+#include "base/functional/callback_forward.h"
+#include "components/enterprise/data_controls/core/browser/data_controls_dialog.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace data_controls {
+
+class AndroidDataControlsDialogFactory;
+
+// Android implementation of `DataControlsDialog`, done using the modal dialog
+// manager.
+class AndroidDataControlsDialog : public DataControlsDialog,
+                                  public content::WebContentsObserver {
+ public:
+  void Show(base::OnceClosure on_destructed) override;
+
+  ~AndroidDataControlsDialog() override;
+
+ private:
+  friend AndroidDataControlsDialogFactory;
+
+  AndroidDataControlsDialog(Type type,
+                            content::WebContents* web_contents,
+                            base::OnceCallback<void(bool bypassed)> callback);
+
+  // Return the title and label for the dialog corresponding to the action that
+  // triggered it.
+  std::u16string GetDialogTitle() const;
+  std::u16string GetDialogLabel() const;
+
+  base::OnceClosure on_destructed_;
+};
+
+}  // namespace data_controls
+
+#endif  // CHROME_BROWSER_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_H_
diff --git a/chrome/browser/enterprise/data_controls/android_data_controls_dialog_browsertest.cc b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_browsertest.cc
new file mode 100644
index 0000000..39379ff8
--- /dev/null
+++ b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_browsertest.cc
@@ -0,0 +1,53 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "ui/android/modal_dialog_wrapper.h"
+
+namespace data_controls {
+
+class AndroidDataControlsDialogUiTest
+    : public AndroidBrowserTest,
+      public testing::WithParamInterface<DataControlsDialog::Type> {
+ public:
+  AndroidDataControlsDialogUiTest() = default;
+  ~AndroidDataControlsDialogUiTest() override = default;
+
+  void SetUp() override { AndroidBrowserTest::SetUp(); }
+
+  DataControlsDialog::Type type() const { return GetParam(); }
+
+  content::WebContents* web_contents() {
+    return chrome_test_utils::GetActiveWebContents(this);
+  }
+
+  ui::WindowAndroid* window_android() {
+    return web_contents()->GetTopLevelNativeWindow();
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    AndroidDataControlsDialogUiTest,
+    testing::Values(
+        data_controls::DataControlsDialog::Type::kClipboardCopyWarn,
+        data_controls::DataControlsDialog::Type::kClipboardCopyBlock,
+        data_controls::DataControlsDialog::Type::kClipboardPasteWarn,
+        data_controls::DataControlsDialog::Type::kClipboardPasteBlock));
+
+IN_PROC_BROWSER_TEST_P(AndroidDataControlsDialogUiTest, SmokeTest) {
+  EXPECT_EQ(nullptr, ui::ModalDialogWrapper::GetDialogForTesting());
+
+  AndroidDataControlsDialogFactory::GetInstance()->ShowDialogIfNeeded(
+      web_contents(), type());
+  EXPECT_NE(nullptr, ui::ModalDialogWrapper::GetDialogForTesting());
+}
+
+}  // namespace data_controls
diff --git a/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.cc b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.cc
new file mode 100644
index 0000000..39a9cf7d
--- /dev/null
+++ b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.cc
@@ -0,0 +1,25 @@
+// Copyright 2024 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/enterprise/data_controls/android_data_controls_dialog_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/enterprise/data_controls/android_data_controls_dialog.h"
+
+namespace data_controls {
+
+// static
+AndroidDataControlsDialogFactory*
+AndroidDataControlsDialogFactory::GetInstance() {
+  return base::Singleton<AndroidDataControlsDialogFactory>::get();
+}
+
+DataControlsDialog* AndroidDataControlsDialogFactory::CreateDialog(
+    DataControlsDialog::Type type,
+    content::WebContents* web_contents,
+    base::OnceCallback<void(bool bypassed)> callback) {
+  return new AndroidDataControlsDialog(type, web_contents, std::move(callback));
+}
+
+}  // namespace data_controls
diff --git a/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.h b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.h
new file mode 100644
index 0000000..6fe95b9
--- /dev/null
+++ b/chrome/browser/enterprise/data_controls/android_data_controls_dialog_factory.h
@@ -0,0 +1,28 @@
+// Copyright 2024 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_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_FACTORY_H_
+#define CHROME_BROWSER_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_FACTORY_H_
+
+#include "components/enterprise/data_controls/core/browser/data_controls_dialog_factory.h"
+
+namespace data_controls {
+
+class AndroidDataControlsDialogFactory : public DataControlsDialogFactory {
+ public:
+  static AndroidDataControlsDialogFactory* GetInstance();
+
+  AndroidDataControlsDialogFactory() = default;
+  virtual ~AndroidDataControlsDialogFactory() = default;
+
+ private:
+  DataControlsDialog* CreateDialog(
+      DataControlsDialog::Type type,
+      content::WebContents* web_contents,
+      base::OnceCallback<void(bool bypassed)> callback) override;
+};
+
+}  // namespace data_controls
+
+#endif  // CHROME_BROWSER_ENTERPRISE_DATA_CONTROLS_ANDROID_DATA_CONTROLS_DIALOG_FACTORY_H_
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
index 455328b..c6beb48 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
@@ -106,7 +106,9 @@
   }
 
   // This will be called by BrowserWithTestWindowTest::SetUp();
-  std::string GetDefaultProfileName() override { return kUserEmail; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kUserEmail;
+  }
 
   void LogIn(const std::string& email) override {
     const AccountId account_id = AccountId::FromUserEmail(email);
diff --git a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
index 54df2d3f..c6219485 100644
--- a/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
@@ -211,7 +211,9 @@
     RunSetModes(QuickUnlockModeList{}, CredentialList{});
   }
 
-  std::string GetDefaultProfileName() override { return kTestUserEmail; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kTestUserEmail;
+  }
 
   TestingProfile* CreateProfile(const std::string& profile_name) override {
     auto pref_service =
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/facilitated_payments_payment_methods_sheet_header_item.xml b/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/facilitated_payments_payment_methods_sheet_header_item.xml
index 13d0095..b12994f 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/facilitated_payments_payment_methods_sheet_header_item.xml
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/facilitated_payments_payment_methods_sheet_header_item.xml
@@ -16,7 +16,7 @@
 
     <ImageView
         android:id="@+id/branding_icon"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="@dimen/facilitated_payments_product_icon_height"
         android:layout_marginVertical="@dimen/facilitated_payments_product_icon_margin_vertical"
         android:importantForAccessibility="no"
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/res/values/dimens.xml b/chrome/browser/facilitated_payments/ui/android/internal/java/res/values/dimens.xml
index d9c0ed8b..de76f15 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/res/values/dimens.xml
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/res/values/dimens.xml
@@ -14,7 +14,7 @@
     <dimen name="facilitated_payments_fop_icon_padding_vertical">3dp</dimen>
     <dimen name="facilitated_payments_fop_icon_height">24dp</dimen>
     <dimen name="facilitated_payments_fop_icon_width">40dp</dimen>
-    <dimen name="facilitated_payments_product_icon_height">32dp</dimen>
+    <dimen name="facilitated_payments_product_icon_height">28dp</dimen>
     <dimen name="facilitated_payments_product_icon_margin_vertical">8dp</dimen>
     <dimen name="facilitated_payments_horizontal_margin">8dp</dimen>
     <dimen name="facilitated_payments_header_bottom_margin">24dp</dimen>
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 72e2fc8..8d0c69b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1495,11 +1495,6 @@
     "resources from loading in a 3p context. This flag applies only in "
     "Incognito mode.";
 
-const char kEnableShortcutCustomizationName[] =
-    "Enable customization in new shortcuts app";
-const char kEnableShortcutCustomizationDescription[] =
-    "Enable customization of shortcuts in the new shortcuts app.";
-
 const char kEnableSearchCustomizableShortcutsInLauncherName[] =
     "Enable search for customizable shortcuts in launcher";
 const char kEnableSearchCustomizableShortcutsInLauncherDescription[] =
@@ -2335,12 +2330,6 @@
     "Overrides the built-in software rendering list and enables "
     "GPU-acceleration on unsupported system configurations.";
 
-const char kImprovedKeyboardShortcutsName[] =
-    "Enable improved keyboard shortcuts";
-const char kImprovedKeyboardShortcutsDescription[] =
-    "Ensure keyboard shortcuts work consistently with international keyboard "
-    "layouts and deprecate legacy shortcuts.";
-
 const char kIncrementLocalSurfaceIdForMainframeSameDocNavigationName[] =
     "Increments LocalSurfaceId for main-frame same-doc navigations";
 const char kIncrementLocalSurfaceIdForMainframeSameDocNavigationDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index ee78b84..d95305f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -962,9 +962,6 @@
 extern const char kEnableProcessPerSiteUpToMainFrameThresholdName[];
 extern const char kEnableProcessPerSiteUpToMainFrameThresholdDescription[];
 
-extern const char kEnableShortcutCustomizationName[];
-extern const char kEnableShortcutCustomizationDescription[];
-
 extern const char kEnableSearchCustomizableShortcutsInLauncherName[];
 extern const char kEnableSearchCustomizableShortcutsInLauncherDescription[];
 
@@ -1324,9 +1321,6 @@
 extern const char kIgnoreGpuBlocklistName[];
 extern const char kIgnoreGpuBlocklistDescription[];
 
-extern const char kImprovedKeyboardShortcutsName[];
-extern const char kImprovedKeyboardShortcutsDescription[];
-
 extern const char kIncrementLocalSurfaceIdForMainframeSameDocNavigationName[];
 extern const char
     kIncrementLocalSurfaceIdForMainframeSameDocNavigationDescription[];
diff --git a/chrome/browser/glic/glic_keyed_service.cc b/chrome/browser/glic/glic_keyed_service.cc
index eb00dce5..08cdf2ab 100644
--- a/chrome/browser/glic/glic_keyed_service.cc
+++ b/chrome/browser/glic/glic_keyed_service.cc
@@ -26,15 +26,19 @@
       window_controller_(Profile::FromBrowserContext(browser_context)),
       focused_tab_manager_(Profile::FromBrowserContext(browser_context),
                            window_controller_),
-      profile_manager_(profile_manager) {}
+      profile_manager_(profile_manager) {
+  focused_tab_changed_subscription_ =
+      focused_tab_manager_.AddFocusedTabChangedCallback(base::BindRepeating(
+          &GlicKeyedService::OnFocusedTabChanged, GetWeakPtr()));
+}
 
 GlicKeyedService::~GlicKeyedService() = default;
 
-void GlicKeyedService::Shutdown() {
-  window_controller_.Shutdown();
-}
-
 void GlicKeyedService::LaunchUI(views::View* glic_button_view) {
+  // Do not open glic window if the user is browsing in incognito or guest mode.
+  DCHECK(GlicProfileManager::IsProfileSupported(
+      Profile::FromBrowserContext(browser_context_)));
+
   profile_manager_->OnUILaunching(this);
   window_controller_.Show(glic_button_view);
 
@@ -126,6 +130,22 @@
           std::move(fetcher), std::move(callback)));
 }
 
+void GlicKeyedService::OnFocusedTabChanged(
+    const content::WebContents* focused_tab) {
+  CHECK_EQ(focused_tab, GetFocusedTab());
+  // TODO(crbug.com/385382048): We shouldn't cancel and restart the animation.
+  // Instead we should transit the current animation state from the previous
+  // browser window to the currently focused browser window.
+  BorderView::CancelAllAnimationsForProfile(
+      Profile::FromBrowserContext(browser_context_));
+  if (focused_tab && window_controller_.HasWindow()) {
+    if (BorderView* border =
+            BorderView::FindBorderForWebContents(focused_tab)) {
+      border->StartAnimation();
+    }
+  }
+}
+
 content::WebContents* GlicKeyedService::GetFocusedTab() {
   return focused_tab_manager_.GetWebContentsForFocusedTab();
 }
diff --git a/chrome/browser/glic/glic_keyed_service.h b/chrome/browser/glic/glic_keyed_service.h
index 9981c21c..e1a585b 100644
--- a/chrome/browser/glic/glic_keyed_service.h
+++ b/chrome/browser/glic/glic_keyed_service.h
@@ -32,9 +32,6 @@
   GlicKeyedService& operator=(const GlicKeyedService&) = delete;
   ~GlicKeyedService() override;
 
-  // KeyedService
-  void Shutdown() override;
-
   // Launches the Glic UI anchored at the given View object. When started from
   // the launcher, no anchor view is provided.
   void LaunchUI(views::View* glic_button_view);
@@ -76,12 +73,17 @@
   base::WeakPtr<GlicKeyedService> GetWeakPtr();
 
  private:
+  void OnFocusedTabChanged(const content::WebContents* focused_tab);
+
   raw_ptr<content::BrowserContext> browser_context_;
 
   GlicWindowController window_controller_;
   GlicFocusedTabManager focused_tab_manager_;
   // Unowned
   raw_ptr<GlicProfileManager> profile_manager_;
+
+  base::CallbackListSubscription focused_tab_changed_subscription_;
+
   base::WeakPtrFactory<GlicKeyedService> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/glic/glic_keyed_service_factory.cc b/chrome/browser/glic/glic_keyed_service_factory.cc
index 15224667..7fc041b 100644
--- a/chrome/browser/glic/glic_keyed_service_factory.cc
+++ b/chrome/browser/glic/glic_keyed_service_factory.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/glic/glic_keyed_service_factory.h"
 
 #include "chrome/browser/glic/glic_profile_manager.h"
-#include "extensions/browser/api/declarative/rules_registry_service.h"
 
 namespace glic {
 
@@ -24,12 +23,7 @@
 
 GlicKeyedServiceFactory::GlicKeyedServiceFactory()
     : ProfileKeyedServiceFactory("GlicKeyedService",
-                                 ProfileSelections::BuildForRegularProfile()) {
-  // GlicKeyedService has an indirect dependency on the
-  // RulesRegistryService through extensions::TabHelper::WebContentsDestroyed
-  // when the glic web contents is destroyed.
-  DependsOn(extensions::RulesRegistryService::GetFactoryInstance());
-}
+                                 ProfileSelections::BuildForRegularProfile()) {}
 
 GlicKeyedServiceFactory::~GlicKeyedServiceFactory() = default;
 
diff --git a/chrome/browser/glic/glic_profile_manager.cc b/chrome/browser/glic/glic_profile_manager.cc
index be09a84a..e8ce3b2 100644
--- a/chrome/browser/glic/glic_profile_manager.cc
+++ b/chrome/browser/glic/glic_profile_manager.cc
@@ -13,10 +13,29 @@
 
 namespace glic {
 
+namespace {
+
+// Ensures that the window is closed early enough (if we don't do this, we
+// won't have cleaned up by the time that keyed services are destroyed).
+void OnAppTerminating() {
+  GlicProfileManager* mgr = GlicProfileManager::GetInstance();
+  if (!mgr) {
+    return;
+  }
+  mgr->CloseGlicWindow();
+}
+
+}  // namespace
+
 GlicProfileManager* GlicProfileManager::GetInstance() {
   return g_browser_process->GetFeatures()->glic_profile_manager();
 }
 
+bool GlicProfileManager::IsProfileSupported(Profile* profile) {
+  // Unsupported if user is browsing in incognito or guest mode.
+  return !profile->IsOffTheRecord();
+}
+
 void GlicProfileManager::CloseGlicWindow() {
   if (active_glic_) {
     active_glic_->ClosePanel();
@@ -36,7 +55,9 @@
   active_glic_ = glic->GetWeakPtr();
 }
 
-GlicProfileManager::GlicProfileManager() {}
+GlicProfileManager::GlicProfileManager()
+    : termination_subscription_(browser_shutdown::AddAppTerminatingCallback(
+          base::BindOnce(&OnAppTerminating))) {}
 
 GlicProfileManager::~GlicProfileManager() = default;
 
diff --git a/chrome/browser/glic/glic_profile_manager.h b/chrome/browser/glic/glic_profile_manager.h
index 58b5d5b6..50f8ea0 100644
--- a/chrome/browser/glic/glic_profile_manager.h
+++ b/chrome/browser/glic/glic_profile_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_GLIC_GLIC_PROFILE_MANAGER_H_
 #define CHROME_BROWSER_GLIC_GLIC_PROFILE_MANAGER_H_
 
+#include "base/callback_list.h"
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/glic/glic_keyed_service.h"
 
@@ -23,6 +24,9 @@
   // Returns the global instance.
   static GlicProfileManager* GetInstance();
 
+  // Returns whether the given profile is supported for glic.
+  static bool IsProfileSupported(Profile* profile);
+
   GlicProfileManager(const GlicProfileManager&) = delete;
   GlicProfileManager& operator=(const GlicProfileManager&) = delete;
 
@@ -38,6 +42,7 @@
 
  private:
   base::WeakPtr<GlicKeyedService> active_glic_;
+  base::CallbackListSubscription termination_subscription_;
 };
 }  // namespace glic
 
diff --git a/chrome/browser/glic/glic_window_controller.cc b/chrome/browser/glic/glic_window_controller.cc
index e67b6c4..bb131c7 100644
--- a/chrome/browser/glic/glic_window_controller.cc
+++ b/chrome/browser/glic/glic_window_controller.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/glic/glic_window_controller.h"
 
-#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
-#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -16,7 +14,6 @@
 #include "chrome/browser/ui/views/tabs/glic_button.h"
 #include "chrome/browser/ui/views/tabs/tab_glic_container.h"
 #include "chrome/browser/ui/webui/glic/glic.mojom.h"
-#include "chrome/common/webui_url_constants.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_observer.h"
 #include "ui/views/controls/webview/webview.h"
@@ -33,32 +30,6 @@
 constexpr static int kWidgetHeight = 800;
 constexpr static int kWidgetTopBarHeight = 80;
 
-class ContentsAndProfileKeepAlive {
- public:
-  explicit ContentsAndProfileKeepAlive(Profile* profile)
-      : profile_keep_alive_(profile, ProfileKeepAliveOrigin::kGlicView),
-        web_contents_(content::WebContents::Create(
-            content::WebContents::CreateParams(profile))) {
-    DCHECK(web_contents_);
-    web_contents_->SetPageBaseBackgroundColor(SK_ColorTRANSPARENT);
-    web_contents_->GetController().LoadURLWithParams(
-        content::NavigationController::LoadURLParams(
-            GURL{chrome::kChromeUIGlicURL}));
-  }
-
-  ~ContentsAndProfileKeepAlive() { web_contents_->ClosePage(); }
-
-  ContentsAndProfileKeepAlive(const ContentsAndProfileKeepAlive&) = delete;
-  ContentsAndProfileKeepAlive& operator=(const ContentsAndProfileKeepAlive&) =
-      delete;
-
-  content::WebContents* web_contents() { return web_contents_.get(); }
-
- private:
-  ScopedProfileKeepAlive profile_keep_alive_;
-  std::unique_ptr<content::WebContents> web_contents_;
-};
-
 // Helper class for observing mouse and key events from native window.
 class WindowEventObserver : public ui::EventObserver {
  public:
@@ -147,15 +118,9 @@
     should_attach_to_browser = true;
   }
 
-  if (!contents_) {
-    contents_ = std::make_unique<ContentsAndProfileKeepAlive>(profile_);
-  }
-
-  widget_ = GlicView::CreateWidget(
+  widget_ = glic::GlicView::CreateWidget(
       profile_, {top_right_point.x() - kWidgetWidth - padding,
                  top_right_point.y() + padding, kWidgetWidth, kWidgetHeight});
-  GlicView::FromWidget(*widget_)->web_view()->SetWebContents(
-      contents_->web_contents());
   widget_->AddObserver(this);
   glic_widget_observer_ =
       std::make_unique<GlicWidgetObserver>(this, widget_.get());
@@ -443,6 +408,10 @@
   return widget_ && widget_->IsActive();
 }
 
+bool GlicWindowController::HasWindow() const {
+  return !!widget_;
+}
+
 base::CallbackListSubscription
 GlicWindowController::AddWindowActivationChangedCallback(
     WindowActivationChangedCallback callback) {
@@ -506,12 +475,6 @@
   }
 }
 
-void GlicWindowController::Shutdown() {
-  // Hide first, then clean up.
-  Close();
-  contents_.reset();
-}
-
 GlicWindowController::GlicWidgetObserver::~GlicWidgetObserver() {
   if (widget_ && widget_->HasObserver(this)) {
     widget_->RemoveObserver(this);
diff --git a/chrome/browser/glic/glic_window_controller.h b/chrome/browser/glic/glic_window_controller.h
index a781a99..94198cd 100644
--- a/chrome/browser/glic/glic_window_controller.h
+++ b/chrome/browser/glic/glic_window_controller.h
@@ -11,7 +11,6 @@
 #include "base/observer_list_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/glic/glic.mojom.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/views/widget/unique_widget_ptr.h"
 
 class Browser;
@@ -21,7 +20,6 @@
 }  // namespace gfx
 
 namespace {
-class ContentsAndProfileKeepAlive;
 class GlicWidgetObserver;
 class WindowEventObserver;
 }  // namespace
@@ -49,9 +47,6 @@
   // Shows the glic window.
   void Show(views::View* glic_button_view);
 
-  // Destroy the glic panel and its web contents.
-  void Shutdown();
-
   // Sets the size of the glic window to the specified dimensions. Returns true
   // if the operation succeeded.
   bool Resize(const gfx::Size& size);
@@ -62,7 +57,7 @@
   // Sets the areas of the view from which it should be draggable.
   void SetDraggableAreas(const std::vector<gfx::Rect>& draggable_areas);
 
-  // Close the panel but keep the glic WebContents alive in the background.
+  // Called to notify the controller that the window was requested to be closed.
   void Close();
 
   // Drags the glic window following the current mouse location with a given
@@ -76,6 +71,9 @@
   // Returns whether or not the glic window is currently active.
   bool IsActive();
 
+  // Whether there is a glic window, regardless of it's visibility to the user.
+  bool HasWindow() const;
+
   using WindowActivationChangedCallback =
       base::RepeatingCallback<void(bool active)>;
 
@@ -169,11 +167,6 @@
   std::unique_ptr<views::Widget> holder_widget_;
 
   const raw_ptr<Profile> profile_;
-
-  // Keep profile alive as long as the glic web contents. This object should be
-  // destroyed when the profile needs to be destroyed.
-  std::unique_ptr<ContentsAndProfileKeepAlive> contents_;
-
   views::UniqueWidgetPtr widget_;
   bool widget_visible_ = false;
 
diff --git a/chrome/browser/history_embeddings/history_embeddings_service_browsertest.cc b/chrome/browser/history_embeddings/history_embeddings_service_browsertest.cc
index f4b0be5..f02ba66c 100644
--- a/chrome/browser/history_embeddings/history_embeddings_service_browsertest.cc
+++ b/chrome/browser/history_embeddings/history_embeddings_service_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "components/history_embeddings/history_embeddings_service.h"
 
+#include <algorithm>
+
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -592,6 +594,37 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(HistoryEmbeddingsBrowserTest, TitleInserted) {
+  auto contains_title = [](const std::string& s) {
+    return s.find("test1.html") != std::string::npos;
+  };
+  ASSERT_TRUE(embedded_test_server()->Start());
+  {
+    base::test::TestFuture<UrlData> store_future;
+    service()->SetPassagesStoredCallbackForTesting(
+        store_future.GetRepeatingCallback());
+    const GURL url = embedded_test_server()->GetURL("/inner_text/test1.html");
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    UrlData url_data = store_future.Take();
+    // No title anywhere in passages.
+    EXPECT_FALSE(
+        std::ranges::any_of(url_data.passages.passages(), contains_title));
+  }
+  {
+    ScopedFeatureParametersForTesting enable_insert_title_passage;
+    enable_insert_title_passage.Get().insert_title_passage = true;
+
+    base::test::TestFuture<UrlData> store_future;
+    service()->SetPassagesStoredCallbackForTesting(
+        store_future.GetRepeatingCallback());
+    const GURL url = embedded_test_server()->GetURL("/inner_text/test1.html");
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    UrlData url_data = store_future.Take();
+    // Title is in first passage.
+    EXPECT_TRUE(contains_title(url_data.passages.passages(0)));
+  }
+}
+
 IN_PROC_BROWSER_TEST_F(HistoryEmbeddingsRestrictedSigninBrowserTest,
                        SearchDoesNotReceiveAnswerForRestrictedSignin) {
   OverrideVisibilityScoresForTesting({
diff --git a/chrome/browser/history_embeddings/history_embeddings_tab_helper.cc b/chrome/browser/history_embeddings/history_embeddings_tab_helper.cc
index 334b6d2..f8b4378 100644
--- a/chrome/browser/history_embeddings/history_embeddings_tab_helper.cc
+++ b/chrome/browser/history_embeddings/history_embeddings_tab_helper.cc
@@ -7,6 +7,7 @@
 #include <numeric>
 
 #include "base/check.h"
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
@@ -64,6 +65,7 @@
 }
 
 void OnGotInnerText(mojo::Remote<blink::mojom::InnerTextAgent> remote,
+                    std::string title,
                     base::ElapsedTimer passage_extraction_timer,
                     base::OnceCallback<void(std::vector<std::string>)> callback,
                     blink::mojom::InnerTextFramePtr mojo_frame) {
@@ -86,6 +88,22 @@
                                valid_passages.size());
   base::UmaHistogramCounts10M("History.Embeddings.Passages.TotalTextSize",
                               total_text_size);
+
+  bool title_inserted = false;
+  if (history_embeddings::GetFeatureParameters().insert_title_passage &&
+      !title.empty() && !base::Contains(valid_passages, title)) {
+    VLOG(2) << "Title passage inserted: " << title;
+    valid_passages.insert(valid_passages.begin(), std::move(title));
+    if (valid_passages.size() >
+        static_cast<size_t>(
+            history_embeddings::GetFeatureParameters().max_passages_per_page)) {
+      valid_passages.pop_back();
+    }
+    title_inserted = true;
+  }
+  base::UmaHistogramBoolean("History.Embeddings.Passages.TitleInserted",
+                            title_inserted);
+
   std::move(callback).Run(std::move(valid_passages));
 }
 
@@ -295,7 +313,9 @@
       std::move(params),
       mojo::WrapCallbackWithDefaultInvokeIfNotRun(
           base::BindOnce(
-              &OnGotInnerText, std::move(agent), base::ElapsedTimer(),
+              &OnGotInnerText, std::move(agent),
+              base::UTF16ToUTF8(GetWebContents().GetTitle()),
+              base::ElapsedTimer(),
               base::BindOnce(&history_embeddings::HistoryEmbeddingsService::
                                  ComputeAndStorePassageEmbeddings,
                              GetHistoryEmbeddingsService()->AsWeakPtr(), url_id,
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
index 4bc978e1..c5d88715 100644
--- a/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
+++ b/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
@@ -91,10 +91,9 @@
       android:visibility="gone"
       android:layout_width="match_parent"
       android:layout_height="@dimen/hub_search_box_height"
-      android:layout_marginHorizontal="12dp"
+      android:layout_marginHorizontal="16dp"
       android:layout_marginVertical="8dp"
-      android:paddingStart="24dp"
-      android:paddingEnd="12dp"
+      android:paddingHorizontal="16dp"
       android:orientation="horizontal"
       android:gravity="center_vertical"
       android:background="@drawable/hub_search_box_background">
diff --git a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java
index 47f53ac..943726c9 100644
--- a/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java
+++ b/chrome/browser/magic_stack/android/java/src/org/chromium/chrome/browser/magic_stack/HomeModulesMetricsUtils.java
@@ -129,11 +129,11 @@
             case DEFAULT_BROWSER_PROMO:
                 return "DefaultBrowserPromo";
             case TAB_GROUPS:
-                return "TabGroups";
+                return "TabGroupPromo";
             case TAB_GROUP_SYNC:
-                return "TabGroupSync";
+                return "TabGroupSyncPromo";
             case QUICK_DELETE:
-                return "QuickDelete";
+                return "QuickDeletePromo";
             default:
                 assert false : "Module type not supported!";
                 return null;
@@ -177,11 +177,11 @@
                 return AUXILIARY_SEARCH;
             case "DefaultBrowserPromo":
                 return DEFAULT_BROWSER_PROMO;
-            case "TabGroups":
+            case "TabGroupPromo":
                 return TAB_GROUPS;
-            case "TabGroupSync":
+            case "TabGroupSyncPromo":
                 return TAB_GROUP_SYNC;
-            case "QuickDelete":
+            case "QuickDeletePromo":
                 return QUICK_DELETE;
             default:
                 assert false : "Module type not supported!";
diff --git a/chrome/browser/optimization_guide/BUILD.gn b/chrome/browser/optimization_guide/BUILD.gn
index 203cd29..1be2d69e 100644
--- a/chrome/browser/optimization_guide/BUILD.gn
+++ b/chrome/browser/optimization_guide/BUILD.gn
@@ -60,11 +60,11 @@
     "//chrome/browser/profiles:profiles",
     "//chrome/browser/sync:sync",
     "//chrome/browser/ui:ui",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/metrics_services_manager:metrics_services_manager",
     "//components/no_state_prefetch/browser:browser",
     "//components/user_prefs:user_prefs",
     "//components/variations/service:service",
+    "//ui/webui",
   ]
   if (is_android) {
     deps += [
diff --git a/chrome/browser/os_crypt/app_bound_encryption_win.cc b/chrome/browser/os_crypt/app_bound_encryption_win.cc
index 868074b..7ef6d8b 100644
--- a/chrome/browser/os_crypt/app_bound_encryption_win.cc
+++ b/chrome/browser/os_crypt/app_bound_encryption_win.cc
@@ -11,6 +11,7 @@
 #include <userenv.h>
 #include <wrl/client.h>
 
+#include "base/check_op.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
@@ -31,9 +32,29 @@
 namespace os_crypt {
 
 namespace {
+
 bool g_non_standard_user_data_dir_supported_for_testing = false;
+
+ProtectionLevel AddFlags(ProtectionLevel protection_level,
+                         elevation_service::EncryptFlags flags) {
+  // Check protection_level fits into 8-bits.
+  CHECK_EQ(protection_level, protection_level & 0xFF);
+
+  uint32_t flag_value = 0;
+  if (flags.use_latest_key) {
+    flag_value |= elevation_service::internal::kFlagUseLatestKey;
+  }
+  // Double check flags fits into 24-bits. This is checked elsewhere too by
+  // static_asserts.
+  CHECK_EQ(flag_value, flag_value & 0xFFFFFF);
+
+  return static_cast<ProtectionLevel>(
+      elevation_service::internal::PackFlagsAndProtectionLevel(
+          flag_value, protection_level));
 }
 
+}  // namespace
+
 namespace features {
 BASE_FEATURE(kAppBoundDataReencrypt,
              "AppBoundDataReencrypt",
@@ -128,7 +149,8 @@
 HRESULT EncryptAppBoundString(ProtectionLevel protection_level,
                               const std::string& plaintext,
                               std::string& ciphertext,
-                              DWORD& last_error) {
+                              DWORD& last_error,
+                              elevation_service::EncryptFlags* flags) {
   base::win::AssertComInitialized();
   Microsoft::WRL::ComPtr<IElevator> elevator;
   last_error = ERROR_GEN_FAILURE;
@@ -151,6 +173,9 @@
            plaintext.length());
 
   base::win::ScopedBstr encrypted_data;
+  if (flags) {
+    protection_level = AddFlags(protection_level, *flags);
+  }
   hr = elevator->EncryptData(protection_level, plaintext_data.Get(),
                              encrypted_data.Receive(), &last_error);
   if (FAILED(hr))
@@ -168,7 +193,8 @@
                               std::string& plaintext,
                               ProtectionLevel protection_level,
                               std::optional<std::string>& new_ciphertext,
-                              DWORD& last_error) {
+                              DWORD& last_error,
+                              elevation_service::EncryptFlags* flags) {
   DCHECK(!ciphertext.empty());
   base::win::AssertComInitialized();
   Microsoft::WRL::ComPtr<IElevator> elevator;
@@ -204,6 +230,9 @@
       hr == elevation_service::Elevator::kSuccessShouldReencrypt) {
     DWORD encrypt_last_error;
     base::win::ScopedBstr reencrypted_data;
+    if (flags) {
+      protection_level = AddFlags(protection_level, *flags);
+    }
     HRESULT encrypt_hr =
         elevator->EncryptData(protection_level, plaintext_data.Get(),
                               reencrypted_data.Receive(), &encrypt_last_error);
diff --git a/chrome/browser/os_crypt/app_bound_encryption_win.h b/chrome/browser/os_crypt/app_bound_encryption_win.h
index 0a75dac6..f09469a 100644
--- a/chrome/browser/os_crypt/app_bound_encryption_win.h
+++ b/chrome/browser/os_crypt/app_bound_encryption_win.h
@@ -11,6 +11,7 @@
 #include "base/feature_list.h"
 #include "base/win/windows_types.h"
 #include "chrome/elevation_service/elevation_service_idl.h"
+#include "chrome/elevation_service/elevator.h"
 
 class PrefService;
 
@@ -54,6 +55,9 @@
 // `src/chrome/elevation_service/elevation-service_idl.idl` for the definition
 // of available protection levels.
 //
+// If `flags` is supplied, then this can control the behavior of the Encrypt
+// operation. See `EncryptFlags` in `elevator.h` for more details.
+//
 // This returns an HRESULT as defined by src/chrome/elevation_service/elevator.h
 // or S_OK for success. If the call fails then `last_error` will be set to the
 // value returned from the most recent failing Windows API call or
@@ -63,7 +67,8 @@
 HRESULT EncryptAppBoundString(ProtectionLevel level,
                               const std::string& plaintext,
                               std::string& ciphertext,
-                              DWORD& last_error);
+                              DWORD& last_error,
+                              elevation_service::EncryptFlags* flags = nullptr);
 
 // Decrypts a string previously encrypted by a call to EncryptAppBoundString.
 //
@@ -74,14 +79,16 @@
 //
 // App-Bound may recommend re-encryption of the data, for example if the key has
 // been rotated. If so, `new_ciphertext` will contain the re-encrypted data
-// according to the `protection_level` specified.
+// according to the `protection_level` specified with the `flags`, if also
+// specified.
 //
 // This should be called on a COM-enabled thread.
 HRESULT DecryptAppBoundString(const std::string& ciphertext,
                               std::string& plaintext,
                               ProtectionLevel protection_level,
                               std::optional<std::string>& new_ciphertext,
-                              DWORD& last_error);
+                              DWORD& last_error,
+                              elevation_service::EncryptFlags* flags = nullptr);
 
 // Allow non-standard user data dir for testing.
 void SetNonStandardUserDataDirSupportedForTesting(bool supported);
diff --git a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
index 9382aee..96b5ee7 100644
--- a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
+++ b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
@@ -141,6 +141,30 @@
   EXPECT_EQ(plaintext, returned_plaintext);
 }
 
+// Test the basic interface to Encrypt and Decrypt data.
+IN_PROC_BROWSER_TEST_F(AppBoundEncryptionWinTest, EncryptDecryptWithFlags) {
+  ASSERT_TRUE(install_static::IsSystemInstall());
+  const std::string plaintext("plaintext");
+  std::string ciphertext;
+  DWORD last_error;
+  elevation_service::EncryptFlags flags;
+  flags.use_latest_key = true;
+  HRESULT hr =
+      EncryptAppBoundString(ProtectionLevel::PROTECTION_PATH_VALIDATION,
+                            plaintext, ciphertext, last_error, &flags);
+
+  ASSERT_HRESULT_SUCCEEDED(hr);
+
+  std::string returned_plaintext;
+  std::optional<std::string> maybe_new_ciphertext;
+  hr = DecryptAppBoundString(ciphertext, returned_plaintext,
+                             ProtectionLevel::PROTECTION_PATH_VALIDATION,
+                             maybe_new_ciphertext, last_error);
+  EXPECT_FALSE(maybe_new_ciphertext);
+  ASSERT_HRESULT_SUCCEEDED(hr);
+  EXPECT_EQ(plaintext, returned_plaintext);
+}
+
 // Test that invalid data is handled correctly.
 IN_PROC_BROWSER_TEST_F(AppBoundEncryptionWinTest, EncryptDecryptInvalid) {
   ASSERT_TRUE(install_static::IsSystemInstall());
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper.cc b/chrome/browser/performance_manager/policies/page_discarding_helper.cc
index 022e33f9..87f85ffe 100644
--- a/chrome/browser/performance_manager/policies/page_discarding_helper.cc
+++ b/chrome/browser/performance_manager/policies/page_discarding_helper.cc
@@ -40,6 +40,10 @@
 namespace policies {
 namespace {
 
+BASE_FEATURE(kIgnoreDiscardAttemptMarker,
+             "IgnoreDiscardAttemptMarker",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // NodeAttachedData used to indicate that there's already been an attempt to
 // discard a PageNode.
 class DiscardAttemptMarker
@@ -350,7 +354,8 @@
   }
 
   // Don't discard tabs for which discarding has already been attempted.
-  if (DiscardAttemptMarker::Get(PageNodeImpl::FromNode(page_node))) {
+  if (DiscardAttemptMarker::Get(PageNodeImpl::FromNode(page_node)) &&
+      !base::FeatureList::IsEnabled(kIgnoreDiscardAttemptMarker)) {
     return CanDiscardResult::kDisallowed;
   }
 
diff --git a/chrome/browser/resources/app_home/BUILD.gn b/chrome/browser/resources/app_home/BUILD.gn
index 3e527b1f..dfac3a8 100644
--- a/chrome/browser/resources/app_home/BUILD.gn
+++ b/chrome/browser/resources/app_home/BUILD.gn
@@ -37,8 +37,8 @@
   ]
 
   mojo_files = [
-    "$root_gen_dir/chrome/browser/web_applications/mojom/user_display_mode.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/app_home/app_home.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/web_applications/mojom/user_display_mode.mojom-webui.ts",
   ]
 
   ts_composite = true
diff --git a/chrome/browser/resources/ash/settings/multidevice_page/multidevice_page.ts b/chrome/browser/resources/ash/settings/multidevice_page/multidevice_page.ts
index fbb826b..0290267 100644
--- a/chrome/browser/resources/ash/settings/multidevice_page/multidevice_page.ts
+++ b/chrome/browser/resources/ash/settings/multidevice_page/multidevice_page.ts
@@ -29,6 +29,8 @@
 import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {Visibility} from 'chrome://resources/mojo/chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom-webui.js';
+import type {InSessionAuthInterface, RequestTokenReply} from 'chrome://resources/mojo/chromeos/components/in_session_auth/mojom/in_session_auth.mojom-webui.js';
+import {InSessionAuth, Reason} from 'chrome://resources/mojo/chromeos/components/in_session_auth/mojom/in_session_auth.mojom-webui.js';
 import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertExhaustive, assertExists} from '../assert_extras.js';
@@ -99,12 +101,22 @@
 
       /**
        * Authentication token provided by password-prompt-dialog.
+       * This is only used if `isAuthPanelInSessionEnabled_` is set to false.
        */
       authToken_: {
         type: Object,
       },
 
       /**
+       * The variable that stores the authentication token we receive
+       * from AuthPanel or ActiveSessionAuth.
+       * This is only used if `isAuthPanelInSessionEnabled_` is set to true.
+       */
+      authTokenReply_: {
+        type: Object,
+      },
+
+      /**
        * Feature which the user has requested to be enabled but could not be
        * enabled immediately because authentication (i.e., entering a password)
        * is required. This value is initialized to null, is set when the
@@ -116,6 +128,10 @@
         value: null,
       },
 
+      /**
+       * Triggers dialog UI that is only used if `isAuthPanelInSessionEnabled_`
+       * is set to false.
+       */
       showPasswordPromptDialog_: {
         type: Boolean,
         value: false,
@@ -203,11 +219,29 @@
         type: Boolean,
         value: false,
       },
+
+      /**
+       * True if auth panel will be used for authentication instead of
+       * password prompt dialog.
+       */
+      isAuthPanelInSessionEnabled_: {
+        type: Boolean,
+        value() {
+          return loadTimeData.getBoolean('isAuthPanelEnabled');
+        },
+        readOnly: true,
+      },
+
+      fakeInSessionAuthForTesting_: {
+        type: Object,
+        value: null,
+      },
     };
   }
 
   isSettingsRetreived: boolean;
   private authToken_: TokenInfo|undefined;
+  private authTokenReply_: RequestTokenReply|undefined|null;
   private browserProxy_: MultiDeviceBrowserProxy;
   private featureToBeEnabledOnceAuthenticated_: MultiDeviceFeature|null;
   private isChromeosScreenLockEnabled_: boolean;
@@ -220,6 +254,9 @@
   private showPasswordPromptDialog_: boolean;
   private shouldShowForgetDeviceDialog_: boolean;
   private showPhonePermissionSetupDialog_: boolean;
+  private isAuthPanelInSessionEnabled_: boolean;
+  private fakeInSessionAuthForTesting_: InSessionAuthInterface;
+
 
   constructor() {
     super();
@@ -395,8 +432,32 @@
     }
   }
 
-  private openPasswordPromptDialog_(): void {
-    this.showPasswordPromptDialog_ = true;
+  /**
+   * Triggers the flow for getting a fresh auth token required to enable
+   * security-sensitive features. The password prompt dialog is opened when
+   * isAuthPanelInSessionEnabled is false. If isAuthPanelInSessionEnabled is
+   * true, the standardized InSessionAuth web UI is evoked.
+   */
+  private async requestUserAuth_(): Promise<void> {
+    if (!this.isAuthPanelInSessionEnabled_) {
+      this.showPasswordPromptDialog_ = true;
+      return;
+    }
+
+    const inSessionAuth =
+        this.fakeInSessionAuthForTesting_ ?? InSessionAuth.getRemote();
+    const tokenInfo: {reply: RequestTokenReply|null} =
+        await inSessionAuth.requestToken(
+            Reason.kAccessAuthenticationSettings,
+            loadTimeData.getString('authPrompt'));
+
+    if (!tokenInfo.reply) {
+      Router.getInstance().navigateToPreviousRoute();
+      return;
+    }
+
+    this.authTokenReply_ = tokenInfo.reply;
+    this.enableFeatureOnceAuthenticated(this.authTokenReply_?.token);
   }
 
   private onDialogClose_(event: Event): void {
@@ -404,28 +465,28 @@
     if (event.composedPath().some(
             element =>
                 (element as HTMLElement).id === 'multidevicePasswordPrompt')) {
-      this.onPasswordPromptDialogClose_();
+      this.enableFeatureOnceAuthenticated(this.authToken_?.token);
     }
   }
 
-  private onPasswordPromptDialogClose_(): void {
+  private enableFeatureOnceAuthenticated(token: string|undefined): void {
     // The password prompt should only be shown when there is a feature waiting
     // to be enabled.
     assert(this.featureToBeEnabledOnceAuthenticated_ !== null);
 
-    // If |this.authToken_| is set when the dialog has been closed, this means
+    // If token is set, this means
     // that the user entered the correct password into the dialog. Thus, send
     // all pending features to be enabled.
-    if (this.authToken_) {
+    if (token) {
       this.browserProxy_.setFeatureEnabledState(
-          this.featureToBeEnabledOnceAuthenticated_, true /* enabled */,
-          this.authToken_.token);
+          this.featureToBeEnabledOnceAuthenticated_, true /* enabled */, token);
       recordSettingChange(Setting.kMultiDeviceOnOff);
 
-      // Reset |this.authToken_| now that it has been used. This ensures that
-      // users cannot keep an old auth token and reuse it on an subsequent
-      // request.
+      // Reset |this.authToken_| and |this.authTokenReply_| now that it has been
+      // used. This ensures that users cannot keep an old auth token and reuse
+      // it on a subsequent request.
       this.authToken_ = undefined;
+      this.authTokenReply_ = undefined;
     }
 
     // Either the feature was enabled above or the user canceled the request by
@@ -448,12 +509,12 @@
     const feature = event.detail.feature;
     const enabled = event.detail.enabled;
 
-    // If the feature required authentication to be enabled, open the password
-    // prompt dialog. This is required every time the user enables a security-
+    // If the feature required authentication to be enabled, request user
+    // authentication. This is required every time the user enables a security-
     // sensitive feature (i.e., use of stale auth tokens is not acceptable).
     if (enabled && this.isAuthenticationRequiredToEnable_(feature)) {
       this.featureToBeEnabledOnceAuthenticated_ = feature;
-      this.openPasswordPromptDialog_();
+      this.requestUserAuth_();
       return;
     }
 
diff --git a/chrome/browser/resources/bluetooth_internals/BUILD.gn b/chrome/browser/resources/bluetooth_internals/BUILD.gn
index 325e40f..cb1e1048 100644
--- a/chrome/browser/resources/bluetooth_internals/BUILD.gn
+++ b/chrome/browser/resources/bluetooth_internals/BUILD.gn
@@ -30,6 +30,7 @@
   non_web_component_files = [
     "adapter_broker.js",
     "adapter_page.js",
+    "bluetooth_internals.js",
     "characteristic_list.js",
     "debug_log_page.js",
     "descriptor_list.js",
@@ -38,10 +39,9 @@
     "device_details_page.js",
     "device_utils.js",
     "devices_page.js",
-    "bluetooth_internals.js",
     "main.js",
-    "page_manager.js",
     "page.js",
+    "page_manager.js",
     "service_list.js",
     "sidebar.js",
   ]
@@ -55,10 +55,10 @@
     "$root_gen_dir/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals.mojom-webui.ts",
     "$root_gen_dir/device/bluetooth/public/mojom/adapter.mojom-webui.ts",
     "$root_gen_dir/device/bluetooth/public/mojom/device.mojom-webui.ts",
-    "$root_gen_dir/device/bluetooth/public/mojom/uuid.mojom-webui.ts",
-    "$root_gen_dir/device/bluetooth/public/mojom/gatt_characteristic_properties.mojom-webui.ts",
     "$root_gen_dir/device/bluetooth/public/mojom/gatt_characteristic_permissions.mojom-webui.ts",
+    "$root_gen_dir/device/bluetooth/public/mojom/gatt_characteristic_properties.mojom-webui.ts",
     "$root_gen_dir/device/bluetooth/public/mojom/gatt_service_error_code.mojom-webui.ts",
+    "$root_gen_dir/device/bluetooth/public/mojom/uuid.mojom-webui.ts",
   ]
 
   ts_composite = true
diff --git a/chrome/browser/resources/bookmarks/BUILD.gn b/chrome/browser/resources/bookmarks/BUILD.gn
index 2d51e70..2a16796 100644
--- a/chrome/browser/resources/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/bookmarks/BUILD.gn
@@ -22,10 +22,10 @@
 
   non_web_component_files = [
     "actions.ts",
-    "bookmarks.ts",
     "api_listener.ts",
-    "bookmarks_api_proxy.ts",
     "bookmark_manager_api_proxy.ts",
+    "bookmarks.ts",
+    "bookmarks_api_proxy.ts",
     "browser_proxy.ts",
     "constants.ts",
     "debouncer.ts",
@@ -34,8 +34,8 @@
     "mouse_focus_behavior.ts",
     "reducers.ts",
     "router.ts",
-    "store_client_mixin.ts",
     "store.ts",
+    "store_client_mixin.ts",
     "types.ts",
     "util.ts",
   ]
@@ -49,8 +49,8 @@
   ts_composite = true
 
   ts_definitions = [
-    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/bookmark_manager_private.d.ts",
+    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/chrome_send.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
diff --git a/chrome/browser/resources/browsing_topics/BUILD.gn b/chrome/browser/resources/browsing_topics/BUILD.gn
index bfa70bc..d9074dbf 100644
--- a/chrome/browser/resources/browsing_topics/BUILD.gn
+++ b/chrome/browser/resources/browsing_topics/BUILD.gn
@@ -8,8 +8,8 @@
   grd_prefix = "browsing_topics_internals"
 
   static_files = [
-    "browsing_topics_internals.html",
     "browsing_topics_internals.css",
+    "browsing_topics_internals.html",
   ]
   non_web_component_files = [ "browsing_topics_internals.ts" ]
   mojo_files = [ "$root_gen_dir/components/browsing_topics/mojom/browsing_topics_internals.mojom-webui.ts" ]
diff --git a/chrome/browser/resources/certificate_viewer/BUILD.gn b/chrome/browser/resources/certificate_viewer/BUILD.gn
index b8ac793..ad2bedc 100644
--- a/chrome/browser/resources/certificate_viewer/BUILD.gn
+++ b/chrome/browser/resources/certificate_viewer/BUILD.gn
@@ -18,8 +18,8 @@
   non_web_component_files = [
     "browser_proxy.ts",
     "certificate_viewer.ts",
-    "modifications_panel.ts",
     "modifications_panel.html.ts",
+    "modifications_panel.ts",
   ]
 
   css_files = [ "modifications_panel.css" ]
diff --git a/chrome/browser/resources/commerce/product_specifications/BUILD.gn b/chrome/browser/resources/commerce/product_specifications/BUILD.gn
index f77e6a6a..6826ab2 100644
--- a/chrome/browser/resources/commerce/product_specifications/BUILD.gn
+++ b/chrome/browser/resources/commerce/product_specifications/BUILD.gn
@@ -8,17 +8,17 @@
   grd_prefix = "commerce_product_specifications"
 
   static_files = [
-    "product_specifications.html",
     "disclosure/product_specifications_disclosure.html",
-    "images/empty_state_dark.svg",
     "images/empty_state.svg",
+    "images/empty_state_dark.svg",
+    "product_specifications.html",
   ]
 
   # Files holding a Polymer element definition and have an equivalent .html file.
   web_component_files = [
     "app.ts",
-    "header_menu.ts",
     "header.ts",
+    "header_menu.ts",
     "new_column_selector.ts",
     "product_selection_menu.ts",
     "product_selector.ts",
diff --git a/chrome/browser/resources/commerce/product_specifications/app.html b/chrome/browser/resources/commerce/product_specifications/app.html
index 04e70a7..becc30d 100644
--- a/chrome/browser/resources/commerce/product_specifications/app.html
+++ b/chrome/browser/resources/commerce/product_specifications/app.html
@@ -1,4 +1,8 @@
 <style include="cr-hidden-style shared-vars">
+  :host {
+    --management-container-min-height: 50px;
+  }
+
   :host([show-table-data-unavailable-container_]),
   :host([show-table-data-unavailable-container_]) #appContainer {
     height: 100%;
@@ -21,13 +25,24 @@
     width: 100%;
   }
 
+  #managementContainer {
+    align-items: flex-start;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: row;
+    flex-grow: 1;
+    gap: 16px;
+    min-height: var(--management-container-min-height);
+    width: 100%;
+  }
+
   #summaryContainer {
     box-sizing: border-box;
     background-color: var(--color-product-specifications-summary-background);
     border-radius: 12px;
     display: flex;
     max-width: 100%;
-    min-height: 50px;
+    min-height: inherit;
     min-width: var(--table-min-width);
     padding: var(--summary-container-padding);
     width: fit-content;
@@ -144,74 +159,82 @@
       on-see-all-click="seeAllSets_">
   </product-specifications-header>
 
-  <div id="summaryContainer" hidden="[[isAppStateNoContent_(appState_)]]">
-    <div id="tableDataUnavailable"
-        hidden="[[!showTableDataUnavailableContainer_]]">
-      <picture>
-        <source srcset="images/empty_state_dark.svg"
-            media="(prefers-color-scheme: dark)">
-        <img id="emptyImg" src="images/empty_state.svg">
-      </picture>
-      <div id="empty"
-          class="table-data-unavailable-container"
-          hidden$="[[!isAppStateTableEmpty_(appState_)]]">
-        <div class="table-data-unavailable-message">$i18n{emptyStateTitle}</div>
-        <div class="table-data-unavailable-description">
-          $i18n{emptyStateDescription}
-        </div>
-        <product-selector id="productSelector"
-            on-selected-url-change="onUrlAdd_">
-        </product-selector>
-      </div>
-      <div id="syncPromo"
-          class="table-data-unavailable-container"
-          hidden="[[!isAppStateSyncScreen_(appState_)]]">
-        <div class="table-data-unavailable-message">
-          $i18n{compareSyncMessage}
-        </div>
-        <div class="table-data-unavailable-description">
-          $i18n{compareSyncDescription}
-        </div>
-        <cr-button id="turnOnSyncButton" class="action-button"
-            on-click="showSyncSetupFlow_">
-          $i18n{compareSyncButton}
-        </cr-button>
-      </div>
-      <div id="error"
-          class="table-data-unavailable-container"
-          hidden="[[!isAppStateError_(appState_)]]">
-        <div class="table-data-unavailable-message">
-          $i18n{compareErrorMessage}
-        </div>
-        <div class="table-data-unavailable-description">
-          $i18n{compareErrorDescription}
-        </div>
-      </div>
-    </div>
-    <!-- TODO(b/357616541): Give loading state the same max-width as
-        the horizontal-carousel and restyle accordingly. -->
-    <loading-state id="loading" hidden$="[[!isAppStateLoading_(appState_)]]"
-        column-count="[[loadingState_.urlCount]]">
-    </loading-state>
-    <horizontal-carousel id="specs"
-        hidden$="[[!isAppStateTablePopulated_(appState_)]]">
-        <product-specifications-table slot="table"
-            id="summaryTable"
-            columns="[[tableColumns_]]"
-            on-url-change="onUrlChange_"
-            on-url-remove="onUrlRemove_"
-            on-url-order-update="onUrlOrderUpdate_"
-            on-unavailable-action-attempted="showOfflineToast_">
-          <div slot="selectorGradient" id="selectorGradient"></div>
-          <new-column-selector slot="newColumnSelector"
-              id="newColumnSelector"
-              excluded-urls="[[getTableUrls_(tableColumns_)]]"
-              is-table-full="[[isTableFull_(tableColumns_.length)]]"
+  <div id="managementContainer" hidden="[[isAppStateNoContent_(appState_)]]">
+    <div id="summaryContainer">
+      <div id="tableDataUnavailable"
+          hidden="[[!showTableDataUnavailableContainer_]]">
+        <picture>
+          <source srcset="images/empty_state_dark.svg"
+              media="(prefers-color-scheme: dark)">
+          <img id="emptyImg" src="images/empty_state.svg">
+        </picture>
+        <div id="empty"
+            class="table-data-unavailable-container"
+            hidden$="[[!isAppStateTableEmpty_(appState_)]]">
+          <div class="table-data-unavailable-message">
+            $i18n{emptyStateTitle}
+          </div>
+          <div class="table-data-unavailable-description">
+            $i18n{emptyStateDescription}
+          </div>
+          <product-selector id="productSelector"
               on-selected-url-change="onUrlAdd_">
-          </new-column-selector>
-        </product-specifications-table>
-    </horizontal-carousel>
+          </product-selector>
+        </div>
+        <div id="syncPromo"
+            class="table-data-unavailable-container"
+            hidden="[[!isAppStateSyncScreen_(appState_)]]">
+          <div class="table-data-unavailable-message">
+            $i18n{compareSyncMessage}
+          </div>
+          <div class="table-data-unavailable-description">
+            $i18n{compareSyncDescription}
+          </div>
+          <cr-button id="turnOnSyncButton" class="action-button"
+              on-click="showSyncSetupFlow_">
+            $i18n{compareSyncButton}
+          </cr-button>
+        </div>
+        <div id="error"
+            class="table-data-unavailable-container"
+            hidden="[[!isAppStateError_(appState_)]]">
+          <div class="table-data-unavailable-message">
+            $i18n{compareErrorMessage}
+          </div>
+          <div class="table-data-unavailable-description">
+            $i18n{compareErrorDescription}
+          </div>
+        </div>
+      </div>
+      <loading-state id="loading" hidden$="[[!isAppStateLoading_(appState_)]]"
+          column-count="[[loadingState_.urlCount]]">
+      </loading-state>
+      <horizontal-carousel id="specs"
+          hidden$="[[!isAppStateTablePopulated_(appState_)]]">
+          <product-specifications-table slot="table"
+              id="summaryTable"
+              columns="[[tableColumns_]]"
+              on-url-change="onUrlChange_"
+              on-url-remove="onUrlRemove_"
+              on-url-order-update="onUrlOrderUpdate_"
+              on-unavailable-action-attempted="showOfflineToast_">
+            <div slot="selectorGradient" id="selectorGradient"></div>
+            <new-column-selector slot="newColumnSelector"
+                id="newColumnSelector"
+                excluded-urls="[[getTableUrls_(tableColumns_)]]"
+                is-table-full="[[isTableFull_(tableColumns_.length)]]"
+                on-selected-url-change="onUrlAdd_">
+            </new-column-selector>
+          </product-specifications-table>
+      </horizontal-carousel>
+    </div>
+
+    <comparison-table-list id="comparisonTableList"
+        tables="[[comparisonTableDetails_]]"
+        hidden$="[[!showComparisonTableList_]]">
+    </comparison-table-list>
   </div>
+
   <div id="footer"
       hidden="[[!canShowFooter_(showTableDataUnavailableContainer_,
           appState_)]]">
diff --git a/chrome/browser/resources/commerce/product_specifications/app.ts b/chrome/browser/resources/commerce/product_specifications/app.ts
index 5378a9a..13d6679c 100644
--- a/chrome/browser/resources/commerce/product_specifications/app.ts
+++ b/chrome/browser/resources/commerce/product_specifications/app.ts
@@ -9,6 +9,7 @@
 import './product_selector.js';
 import './table.js';
 import './horizontal_carousel.js';
+import './comparison_table_list.js';
 import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
 import 'chrome://resources/cr_elements/cr_feedback_buttons/cr_feedback_buttons.js';
 import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
@@ -35,6 +36,8 @@
 
 import {getTemplate} from './app.html.js';
 import type {BuyingOptions} from './buying_options_section.js';
+import type {ComparisonTableDetails, ComparisonTableListElement} from './comparison_table_list.js';
+import type {ComparisonTableListItemClickEvent} from './comparison_table_list_item.js';
 import type {ProductDescription} from './description_section.js';
 import type {HeaderElement} from './header.js';
 import type {NewColumnSelectorElement} from './new_column_selector.js';
@@ -70,11 +73,13 @@
 
 export interface ProductSpecificationsElement {
   $: {
+    comparisonTableList: ComparisonTableListElement,
     empty: HTMLElement,
     error: HTMLElement,
     errorToast: CrToastElement,
     header: HeaderElement,
     loading: HTMLElement,
+    managementContainer: HTMLElement,
     newColumnSelector: NewColumnSelectorElement,
     offlineToast: CrToastElement,
     productSelector: ProductSelectorElement,
@@ -226,8 +231,14 @@
         computed: 'computeAppState_(productSpecificationsFeatureState_.*,' +
             ' loadingState_.loading, showEmptyState_)',
       },
+      comparisonTableDetails_: Array,
       loadingState_: Object,
       setName_: String,
+      showComparisonTableList_: {
+        type: Boolean,
+        computed: 'computeShowComparisonTableList_(showEmptyState_,' +
+            ' comparisonTableDetails_)',
+      },
       showTableDataUnavailableContainer_: {
         type: Boolean,
         computed: 'computeShowTableDataUnavailableContainer_(appState_)',
@@ -238,8 +249,10 @@
   }
 
   private appState_: AppState = AppState.NO_CONTENT;
+  private comparisonTableDetails_: ComparisonTableDetails[] = [];
   private loadingState_: LoadingState = {loading: false, urlCount: 0};
   private setName_: string|null = null;
+  private showComparisonTableList_: boolean = false;
   private showTableDataUnavailableContainer_: boolean;
   private tableColumns_: TableColumn[] = [];
 
@@ -266,11 +279,17 @@
     super.connectedCallback();
 
     this.listenerIds_.push(
+        this.callbackRouter_.onProductSpecificationsSetAdded.addListener(
+            (set: ProductSpecificationsSet) => this.onSetAdded_(set)),
         this.callbackRouter_.onProductSpecificationsSetRemoved.addListener(
             (uuid: Uuid) => this.onSetRemoved_(uuid)),
         this.callbackRouter_.onProductSpecificationsSetUpdated.addListener(
             (set: ProductSpecificationsSet) => this.onSetUpdated_(set)));
 
+    this.addEventListener(
+        'comparison-table-list-item-click',
+        this.onComparisonTableListItemClickEvent_);
+
     // TODO: b/358131415 - use listeners to update. Temporary workaround uses
     // window focus to update the feature state, to check signin.
     window.addEventListener('focus', async () => {
@@ -344,28 +363,14 @@
     const params = new URLSearchParams(router.getCurrentQuery());
     const idParam = params.get('id');
     if (idParam && isValidLowercaseUuid(idParam)) {
-      this.id_ = {value: idParam};
-      const {set} = await this.shoppingApi_.getProductSpecificationsSetByUuid(
-          {value: idParam});
-      if (set) {
-        const {disclosureShown} =
-            await this.productSpecificationsProxy_.maybeShowDisclosure(
-                /* urls= */[], /* name= */ '', idParam);
-        if (disclosureShown) {
-          this.showEmptyState_ = true;
-          this.id_ = null;
-          return;
-        }
-        document.title = set.name;
-        this.setName_ = set.name;
-        this.populateTable_(set.urls.map(url => (url.url)));
+      if (await this.loadSet_({value: idParam})) {
         return;
       }
     }
 
     const urlsParam = params.get('urls');
     if (!urlsParam) {
-      this.showEmptyState_ = true;
+      this.updateEmptyState_(true);
       return;
     }
 
@@ -436,6 +441,15 @@
         this.appState_ === AppState.SYNC_SCREEN;
   }
 
+  private computeShowComparisonTableList_() {
+    if (!loadTimeData.getBoolean('comparisonTableListEnabled')) {
+      return false;
+    }
+
+    return this.showEmptyState_ && this.id_ === null &&
+        this.comparisonTableDetails_.length > 0;
+  }
+
   private canShowFooter_(
       showTableDataUnavailableContainer: boolean, appState: AppState) {
     return !(
@@ -471,14 +485,14 @@
     // Transition directly to the empty state if there are no URLs.
     if (urls.length === 0) {
       this.tableColumns_ = [];
-      this.showEmptyState_ = true;
+      this.updateEmptyState_(true);
       return;
     }
 
     await this.enterLoadingState_(urls.length);
 
     const start = Date.now();
-    this.showEmptyState_ = false;
+    this.updateEmptyState_(false);
 
     const tableColumns: TableColumn[] = [];
     if (urls.length) {
@@ -531,7 +545,7 @@
     }
 
     this.tableColumns_ = tableColumns;
-    this.showEmptyState_ = this.tableColumns_.length === 0;
+    this.updateEmptyState_(this.tableColumns_.length === 0);
     this.exitLoadingState_();
   }
 
@@ -599,6 +613,39 @@
     }
   }
 
+  private async fetchComparisonTableDetails_() {
+    const {sets} = await this.shoppingApi_.getAllProductSpecificationsSets();
+
+    if (sets.length === 0 && this.comparisonTableDetails_.length === 0) {
+      return;
+    }
+
+    this.comparisonTableDetails_ = await Promise.all(
+        sets.map(async set => this.createTableDetailsFromSet_(set)));
+  }
+
+  private async createTableDetailsFromSet_(set: ProductSpecificationsSet):
+      Promise<ComparisonTableDetails> {
+    // Find the first product with an image to use as the list item image.
+    let imageUrl = null;
+    for (let i = 0; i < set.urls.length; i++) {
+      const {productInfo} =
+          await this.shoppingApi_.getProductInfoForUrl(set.urls[i]);
+
+      if (productInfo.imageUrl.url) {
+        imageUrl = productInfo.imageUrl;
+        break;
+      }
+    }
+
+    return {
+      name: set.name,
+      uuid: set.uuid,
+      numUrls: set.urls.length,
+      imageUrl,
+    };
+  }
+
   private seeAllSets_() {
     OpenWindowProxyImpl.getInstance().openUrl(
         loadTimeData.getString('productSpecificationsManagementUrl'));
@@ -734,7 +781,16 @@
     return columnCount >= loadTimeData.getInteger('maxTableSize');
   }
 
-  private onSetUpdated_(set: ProductSpecificationsSet) {
+  private async onSetUpdated_(set: ProductSpecificationsSet) {
+    if (this.showEmptyState_) {
+      const tableIndex = this.comparisonTableDetails_.findIndex(
+          table => table.uuid.value === set.uuid.value);
+      if (tableIndex !== -1) {
+        this.comparisonTableDetails_ = this.comparisonTableDetails_.toSpliced(
+            tableIndex, 1, await this.createTableDetailsFromSet_(set));
+      }
+    }
+
     // If the page does not have focus, schedule the update for later in case a
     // newer update is received before the tab is focused. This prevents all
     // updates from triggering at the same time, which may cause a flicker.
@@ -792,6 +848,11 @@
     if (id.value === this.id_?.value) {
       window.location.replace(window.location.origin);
     }
+
+    if (this.showEmptyState_) {
+      this.comparisonTableDetails_ = this.comparisonTableDetails_.filter(
+          table => table.uuid.value !== id.value);
+    }
   }
 
   private onFeedbackSelectedOptionChanged_(
@@ -812,13 +873,21 @@
     }
   }
 
+  private async onSetAdded_(set: ProductSpecificationsSet) {
+    if (this.showEmptyState_) {
+      this.comparisonTableDetails_ =
+          [await this.createTableDetailsFromSet_(set)].concat(
+              this.comparisonTableDetails_);
+    }
+  }
+
   private getDisclaimerText_(): string {
     return loadTimeData.getStringF(
         'experimentalFeatureDisclaimer', loadTimeData.getString('userEmail'));
   }
 
-  private async fadeAndSlideOutSummaryContainer_() {
-    await this.$.summaryContainer
+  private async fadeAndSlideOutManagementContainer_() {
+    await this.$.managementContainer
         .animate(
             [
               {opacity: 1, transform: 'translateY(0px)'},
@@ -835,8 +904,8 @@
         .finished;
   }
 
-  private async fadeAndSlideInSummaryContainer_() {
-    await this.$.summaryContainer
+  private async fadeAndSlideInManagementContainer_() {
+    await this.$.managementContainer
         .animate(
             [
               {
@@ -867,18 +936,18 @@
     }
 
     return new Promise<void>(async resolve => {
-      await this.fadeAndSlideOutSummaryContainer_();
+      await this.fadeAndSlideOutManagementContainer_();
       this.loadingState_ = {loading: true, urlCount};
       resolve();
-      await this.fadeAndSlideInSummaryContainer_();
+      await this.fadeAndSlideInManagementContainer_();
       this.dispatchLoadingStartEvent_();
     });
   }
 
   private async exitLoadingState_() {
-    await this.fadeAndSlideOutSummaryContainer_();
+    await this.fadeAndSlideOutManagementContainer_();
     this.loadingState_ = {loading: false, urlCount: 0};
-    await this.fadeAndSlideInSummaryContainer_();
+    await this.fadeAndSlideInManagementContainer_();
     this.dispatchLoadingEndEvent_();
   }
 
@@ -891,6 +960,53 @@
     this.dispatchEvent(new CustomEvent(
         LOADING_END_EVENT_TYPE, {bubbles: true, composed: true}));
   }
+
+  private updateEmptyState_(shouldShow: boolean) {
+    this.showEmptyState_ = shouldShow;
+
+    // If we show the empty state and there are no comparison tables, try to
+    // fetch them.
+    if (this.showEmptyState_ && this.comparisonTableDetails_.length === 0) {
+      this.fetchComparisonTableDetails_();
+    }
+  }
+
+  private onComparisonTableListItemClickEvent_(
+      event: ComparisonTableListItemClickEvent) {
+    window.history.replaceState(
+        undefined, '', `?id=${event.detail.uuid.value}`);
+    this.loadSet_(event.detail.uuid);
+  }
+
+  private async loadSet_(uuid: Uuid): Promise<boolean> {
+    const {set} =
+        await this.shoppingApi_.getProductSpecificationsSetByUuid(uuid);
+    if (set) {
+      const {disclosureShown} =
+          await this.productSpecificationsProxy_.maybeShowDisclosure(
+              /* urls= */[], /* name= */ '', uuid.value);
+      if (disclosureShown) {
+        this.updateEmptyState_(true);
+        this.id_ = null;
+        return false;
+      }
+      this.id_ = set.uuid;
+      document.title = set.name;
+      this.setName_ = set.name;
+      this.populateTable_(set.urls.map(url => (url.url)));
+      return true;
+    }
+
+    this.updateEmptyState_(true);
+    this.id_ = null;
+    return false;
+  }
+}
+
+declare global {
+  interface HTMLElementEventMap {
+    'comparison-table-list-item-click': ComparisonTableListItemClickEvent;
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/commerce/product_specifications/shared_vars.css b/chrome/browser/resources/commerce/product_specifications/shared_vars.css
index e3825ce..60c1f5e 100644
--- a/chrome/browser/resources/commerce/product_specifications/shared_vars.css
+++ b/chrome/browser/resources/commerce/product_specifications/shared_vars.css
@@ -9,12 +9,14 @@
 html {
   --app-container-padding: 24px;
   --body-min-width: calc(var(--app-container-padding) * 2 + var(
-      --summary-container-padding) * 2 + var(--table-min-width));
+      --summary-container-padding) * 2 + var(--table-min-width) + var(
+      --comparison-table-list-width));
   --body-table-data-unavailable-height: calc(var(
       --app-container-padding) * 2 + var(--summary-container-padding) * 2 + var(
       --header-height) + var(--header-margin-bottom) + var(
       --table-data-unavailable-min-height));
   --column-hover-padding: 4px;
+  --comparison-table-list-width: 416px;
   --header-height: 38px;
   --header-margin-bottom: 24px;
   --summary-container-padding: 16px;
diff --git a/chrome/browser/resources/components/BUILD.gn b/chrome/browser/resources/components/BUILD.gn
index bbd2c0f..c856204a 100644
--- a/chrome/browser/resources/components/BUILD.gn
+++ b/chrome/browser/resources/components/BUILD.gn
@@ -7,12 +7,12 @@
 build_webui("build") {
   grd_prefix = "components"
   static_files = [
-    "components.html",
     "components.css",
+    "components.html",
   ]
   non_web_component_files = [
-    "components.ts",
     "component.html.ts",
+    "components.ts",
   ]
 
   ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
diff --git a/chrome/browser/resources/compose/BUILD.gn b/chrome/browser/resources/compose/BUILD.gn
index 743772b..bb435418 100644
--- a/chrome/browser/resources/compose/BUILD.gn
+++ b/chrome/browser/resources/compose/BUILD.gn
@@ -9,8 +9,8 @@
   static_files = [ "compose.html" ]
   web_component_files = [
     "app.ts",
-    "textarea.ts",
     "result_text.ts",
+    "textarea.ts",
   ]
   non_web_component_files = [
     "animations/animator.ts",
diff --git a/chrome/browser/resources/data_sharing/BUILD.gn b/chrome/browser/resources/data_sharing/BUILD.gn
index 552577dc..38248d6a 100644
--- a/chrome/browser/resources/data_sharing/BUILD.gn
+++ b/chrome/browser/resources/data_sharing/BUILD.gn
@@ -40,8 +40,8 @@
   non_web_component_files = [
     "browser_proxy.ts",
     "data_sharing_api.ts",
-    "mojom_conversion_utils.ts",
     "data_sharing_sdk_types.ts",
+    "mojom_conversion_utils.ts",
   ]
 
   if (is_chrome_branded) {
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index ee8cbb30..6483acd2 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -77,6 +77,8 @@
     "shortcut_util.ts",
     "sidebar.html.ts",
     "sidebar.ts",
+    "site_permissions/site_permissions.html.ts",
+    "site_permissions/site_permissions.ts",
     "site_permissions/site_permissions_by_site.html.ts",
     "site_permissions/site_permissions_by_site.ts",
     "site_permissions/site_permissions_edit_permissions_dialog.html.ts",
@@ -87,8 +89,6 @@
     "site_permissions/site_permissions_list.ts",
     "site_permissions/site_permissions_site_group.html.ts",
     "site_permissions/site_permissions_site_group.ts",
-    "site_permissions/site_permissions.html.ts",
-    "site_permissions/site_permissions.ts",
     "site_permissions/site_settings_mixin.ts",
     "toggle_row.html.ts",
     "toggle_row.ts",
@@ -123,9 +123,9 @@
     "pack_dialog.css",
     "pack_dialog_alert.css",
     "review_panel.css",
+    "runtime_host_permissions.css",
     "shared_style.css",
     "shared_vars.css",
-    "runtime_host_permissions.css",
     "shortcut_input.css",
     "sidebar.css",
     "site_permissions/site_permissions.css",
@@ -141,13 +141,13 @@
   ts_definitions = [
     "//tools/typescript/definitions/activity_log_private.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
+    "//tools/typescript/definitions/chrome_send.d.ts",
     "//tools/typescript/definitions/developer_private.d.ts",
     "//tools/typescript/definitions/management.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
     "//tools/typescript/definitions/pending.d.ts",
     "//tools/typescript/definitions/runtime.d.ts",
     "//tools/typescript/definitions/tabs.d.ts",
-    "//tools/typescript/definitions/chrome_send.d.ts",
   ]
 
   ts_deps = [
diff --git a/chrome/browser/resources/feedback/BUILD.gn b/chrome/browser/resources/feedback/BUILD.gn
index 8dbde1c62..c836c47 100644
--- a/chrome/browser/resources/feedback/BUILD.gn
+++ b/chrome/browser/resources/feedback/BUILD.gn
@@ -15,11 +15,11 @@
     "feedback.html",
     "html/autofill_metadata_info.html",
     "html/system_info.html",
-    "images/2x/button_butter_bar_close_hover.png",
     "images/2x/button_butter_bar_close.png",
+    "images/2x/button_butter_bar_close_hover.png",
     "images/2x/button_butter_bar_close_pressed.png",
-    "images/button_butter_bar_close_hover.png",
     "images/button_butter_bar_close.png",
+    "images/button_butter_bar_close_hover.png",
     "images/button_butter_bar_close_pressed.png",
   ]
 
@@ -50,8 +50,8 @@
 
   ts_composite = true
   ts_definitions = [
-    "//tools/typescript/definitions/feedback_private.d.ts",
     "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/feedback_private.d.ts",
   ]
   ts_deps = [
     "//chrome/browser/resources/key_value_pair_viewer_shared:build_ts",
diff --git a/chrome/browser/resources/glic/BUILD.gn b/chrome/browser/resources/glic/BUILD.gn
index d6dac62..67e9afd0 100644
--- a/chrome/browser/resources/glic/BUILD.gn
+++ b/chrome/browser/resources/glic/BUILD.gn
@@ -11,19 +11,19 @@
   grd_prefix = "glic"
 
   static_files = [
-    "glic.html",
     "glic.css",
+    "glic.html",
   ]
 
   non_web_component_files = [
     "browser_proxy.ts",
-    "main.ts",
-    "glic_api_impl/glic_api_host.ts",
+    "glic_api/glic_api.ts",
     "glic_api/glic_api_client.ts",
+    "glic_api/glic_api_injected_client.ts",
     "glic_api/post_message_transport.ts",
     "glic_api/request_types.ts",
-    "glic_api/glic_api.ts",
-    "glic_api/glic_api_injected_client.ts",
+    "glic_api_impl/glic_api_host.ts",
+    "main.ts",
   ]
 
   webui_context_type = "trusted"
@@ -42,12 +42,12 @@
 
   ts_definitions = [
     # These files are necessary for chrome.webviewTag:
-    "//tools/typescript/definitions/webview_tag.d.ts",
-    "//tools/typescript/definitions/tabs.d.ts",
-    "//tools/typescript/definitions/extension_types.d.ts",
-    "//tools/typescript/definitions/context_menus.d.ts",
-    "//tools/typescript/definitions/web_request.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
+    "//tools/typescript/definitions/context_menus.d.ts",
+    "//tools/typescript/definitions/extension_types.d.ts",
+    "//tools/typescript/definitions/tabs.d.ts",
+    "//tools/typescript/definitions/web_request.d.ts",
+    "//tools/typescript/definitions/webview_tag.d.ts",
   ]
 
   ts_composite = true
diff --git a/chrome/browser/resources/glic/glic_api/glic_api.ts b/chrome/browser/resources/glic/glic_api/glic_api.ts
index e9d44ef..e562406 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api.ts
@@ -128,6 +128,9 @@
   // Set the state of the tab context permission in settings. Returns a promise
   // that resolves when the browser has stored the new pref value.
   setTabContextPermissionState(enabled: boolean): Promise<void>;
+
+  // Returns the user profile information.
+  getUserProfileInfo?(): Promise<UserProfileInfo>;
 }
 
 // A panel can be in one of these three states.
@@ -259,6 +262,15 @@
   unsubscribe(): void;
 }
 
+export declare interface UserProfileInfo {
+  // Returns the avatar icon for the profile, if available.
+  avatarIcon(): Promise<Blob|undefined>;
+  // The name displayed for this profile.
+  displayName: string;
+  // The profile email.
+  email: string;
+}
+
 
 //
 // Types used in the boot process.
diff --git a/chrome/browser/resources/glic/glic_api/glic_api_client.ts b/chrome/browser/resources/glic/glic_api/glic_api_client.ts
index 96604582..1610eef 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api_client.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api_client.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import type {DraggableArea, ErrorWithReason, GlicBrowserHost, GlicHostRegistry, GlicWebClient, Observable, PanelState, Subscriber, TabContextResult, TabData} from '../glic_api/glic_api.js';
+import type {DraggableArea, ErrorWithReason, GlicBrowserHost, GlicHostRegistry, GlicWebClient, Observable, PanelState, Subscriber, TabContextResult, TabData, UserProfileInfo} from '../glic_api/glic_api.js';
 import {GetTabContextErrorReason, PanelStateKind} from '../glic_api/glic_api.js';
 
 import {PostMessageRequestReceiver, PostMessageRequestSender} from './post_message_transport.js';
@@ -212,6 +212,21 @@
     return this.sender.requestWithResponse(
         'glicBrowserSetTabContextPermissionState', {enabled});
   }
+
+  async getUserProfileInfo?(): Promise<UserProfileInfo> {
+    const {profileInfo} = await this.sender.requestWithResponse(
+        'glicBrowserGetUserProfileInfo', {});
+    if (!profileInfo) {
+      throw new Error('getUserProfileInfo failed');
+    }
+    const {displayName, email, avatarIconImage} = profileInfo;
+    return {
+      displayName,
+      email,
+      avatarIcon: async () =>
+          avatarIconImage && rgbaImageToBlob(avatarIconImage),
+    };
+  }
 }
 
 // Returns a promise which resolves to the `GlicHostRegistry`. This promise
@@ -261,16 +276,19 @@
         continue;
       }
       const alpha = alphaInt / 255.0;
-      pixelData[i] = pixelData[i + 2]! / alpha;
-      pixelData[i + 1] = pixelData[i + 1]! / alpha;
-      pixelData[i + 2] = pixelData[i]! / alpha;
+      const [B, G, R] = [pixelData[i]!, pixelData[i + 1]!, pixelData[i + 2]!];
+      pixelData[i] = R / alpha;
+      pixelData[i + 1] = G / alpha;
+      pixelData[i + 2] = B / alpha;
     }
   } else {
     for (let i = 0; i + 3 < pixelData.length; i += 4) {
-      pixelData[i] = pixelData[i + 2]!;
-      pixelData[i + 2] = pixelData[i]!;
+      const [B, R] = [pixelData[i]!, pixelData[i + 2]!];
+      pixelData[i] = R;
+      pixelData[i + 2] = B;
     }
   }
+
   ctx.putImageData(new ImageData(pixelData, image.width, image.height), 0, 0);
   return new Promise((resolve) => {
     canvas.toBlob((result) => {
diff --git a/chrome/browser/resources/glic/glic_api/request_types.ts b/chrome/browser/resources/glic/glic_api/request_types.ts
index 6a90dd5..6c59586 100644
--- a/chrome/browser/resources/glic/glic_api/request_types.ts
+++ b/chrome/browser/resources/glic/glic_api/request_types.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import type {DraggableArea, GetTabContextErrorReason, PanelState, TabContextResult, TabData} from '../glic_api/glic_api.js';
+import type {DraggableArea, GetTabContextErrorReason, PanelState, TabContextResult, TabData, UserProfileInfo} from '../glic_api/glic_api.js';
 
 /*
 This file defines messages sent over postMessage in-between the Glic WebUI
@@ -107,6 +107,12 @@
     },
     response: void,
   };
+  glicBrowserGetUserProfileInfo: {
+    request: {},
+    response: {
+      profileInfo?: UserProfileInfoPrivate,
+    },
+  };
 }
 
 // Types of requests to the GlicWebClient.
@@ -186,3 +192,8 @@
     Omit<TabContextResult, 'tabData'> {
   tabData: TabDataPrivate;
 }
+
+export declare interface UserProfileInfoPrivate extends
+    Omit<UserProfileInfo, 'avatarIcon'> {
+  avatarIconImage?: RgbaImage;
+}
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
index e32d5f7..c4764bc 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
@@ -22,7 +22,7 @@
 import {GetTabContextErrorReason} from '../glic_api/glic_api.js';
 import type {PostMessageRequestHandler} from '../glic_api/post_message_transport.js';
 import {PostMessageRequestReceiver, PostMessageRequestSender} from '../glic_api/post_message_transport.js';
-import type {HostRequestTypes, RgbaImage} from '../glic_api/request_types.js';
+import type {HostRequestTypes, RgbaImage, UserProfileInfoPrivate} from '../glic_api/request_types.js';
 import {ImageAlphaType, ImageColorType} from '../glic_api/request_types.js';
 
 // Turn everything except void into a promise.
@@ -235,6 +235,23 @@
   glicBrowserSetTabContextPermissionState(request: {enabled: boolean}) {
     return this.handler.setTabContextPermissionState(request.enabled);
   }
+
+  async glicBrowserGetUserProfileInfo(_request: {}, transfer: Transferable[]) {
+    const {profileInfo: mojoProfileInfo} =
+        await this.handler.getUserProfileInfo();
+    if (!mojoProfileInfo) {
+      return {};
+    }
+    const {displayName, email, avatarIcon} = mojoProfileInfo;
+    const profileInfo: UserProfileInfoPrivate = {displayName, email};
+    if (avatarIcon) {
+      profileInfo.avatarIconImage = bitmapN32ToRGBAImage(avatarIcon);
+      if (profileInfo.avatarIconImage) {
+        transfer.push(profileInfo.avatarIconImage.dataRGBA);
+      }
+    }
+    return {profileInfo};
+  }
 }
 
 export class GlicApiHost implements PostMessageRequestHandler {
diff --git a/chrome/browser/resources/glic/main.ts b/chrome/browser/resources/glic/main.ts
index 54f9fb6..3b4dceb6 100644
--- a/chrome/browser/resources/glic/main.ts
+++ b/chrome/browser/resources/glic/main.ts
@@ -4,8 +4,6 @@
 
 import '/strings.m.js';
 
-import {loadTimeData} from '//resources/js/load_time_data.js';
-
 import {BrowserProxyImpl} from './browser_proxy.js';
 import {GlicApiHost} from './glic_api_impl/glic_api_host.js';
 
@@ -18,8 +16,8 @@
 class GlicAppHostManager {
   host: GlicApiHost|undefined;
   constructor() {
-    webview.addEventListener('loadcommit', () => {
-      this.loadCommit();
+    webview.addEventListener('loadcommit', (e: any) => {
+      this.loadCommit(e.url, e.isTopLevel);
     });
     webview.addEventListener('contentload', () => {
       this.contentLoaded();
@@ -43,15 +41,17 @@
     event.stopPropagation();
   }
 
-  loadCommit() {
+  loadCommit(url: string, isTopLevel: boolean) {
+    if (!isTopLevel) {
+      return;
+    }
     if (this.host) {
       this.host.destroy();
       this.host = undefined;
     }
     if (webview.contentWindow) {
       this.host = new GlicApiHost(
-          browserProxy, webview.contentWindow,
-          new URL(loadTimeData.getString('glicGuestURL')).origin);
+          browserProxy, webview.contentWindow, new URL(url).origin);
     }
   }
 
diff --git a/chrome/browser/resources/history/BUILD.gn b/chrome/browser/resources/history/BUILD.gn
index 7b7b44c0..c10da83 100644
--- a/chrome/browser/resources/history/BUILD.gn
+++ b/chrome/browser/resources/history/BUILD.gn
@@ -10,13 +10,13 @@
 
   static_files = [
     "history.html",
+    "images/compare_sync_promo.svg",
+    "images/compare_sync_promo_dark.svg",
     "images/history_embeddings_promo.svg",
     "images/history_embeddings_promo_dark.svg",
     "images/list.svg",
-    "images/sign_in_promo_dark.svg",
     "images/sign_in_promo.svg",
-    "images/compare_sync_promo_dark.svg",
-    "images/compare_sync_promo.svg",
+    "images/sign_in_promo_dark.svg",
   ]
 
   # Files holding a Polymer element definition and have an equivalent .html file.
diff --git a/chrome/browser/resources/inline_login/BUILD.gn b/chrome/browser/resources/inline_login/BUILD.gn
index a5846f9..343197a 100644
--- a/chrome/browser/resources/inline_login/BUILD.gn
+++ b/chrome/browser/resources/inline_login/BUILD.gn
@@ -18,9 +18,9 @@
 
   ts_composite = true
   ts_definitions = [
-    "//tools/typescript/definitions/chrome_send.d.ts",
     "//chrome/browser/resources/gaia_auth_host/authenticator.d.ts",
     "//chrome/browser/resources/gaia_auth_host/saml_password_attributes.d.ts",
+    "//tools/typescript/definitions/chrome_send.d.ts",
   ]
   ts_deps = [
     "//third_party/polymer/v3_0:library",
diff --git a/chrome/browser/resources/intro/BUILD.gn b/chrome/browser/resources/intro/BUILD.gn
index 2ef0b8f8..6fe6db63 100644
--- a/chrome/browser/resources/intro/BUILD.gn
+++ b/chrome/browser/resources/intro/BUILD.gn
@@ -12,14 +12,14 @@
 
   static_files = [
     "default_browser/default_browser.html",
-    "intro.html",
     "images/default_browser_frame.svg",
     "images/default_browser_frame_dark.svg",
+    "intro.html",
   ]
 
   non_web_component_files = [
-    "default_browser/browser_proxy.ts",
     "browser_proxy.ts",
+    "default_browser/browser_proxy.ts",
   ]
 
   if (enable_dice_support) {
diff --git a/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn b/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn
index 589e984f..a7a2a43 100644
--- a/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn
+++ b/chrome/browser/resources/key_value_pair_viewer_shared/BUILD.gn
@@ -11,15 +11,15 @@
   grd_resource_path_prefix = "shared/key_value_pair_viewer"
 
   web_component_files = [
-    "key_value_pair_viewer.ts",
     "key_value_pair_entry.ts",
+    "key_value_pair_viewer.ts",
   ]
 
   non_web_component_files = [ "key_value_pair_parser.ts" ]
 
   css_files = [
-    "key_value_pair_viewer.css",
     "key_value_pair_entry.css",
+    "key_value_pair_viewer.css",
   ]
 
   html_to_wrapper_template = "detect"
diff --git a/chrome/browser/resources/lens/overlay/BUILD.gn b/chrome/browser/resources/lens/overlay/BUILD.gn
index 0cf8591..ce37bec 100644
--- a/chrome/browser/resources/lens/overlay/BUILD.gn
+++ b/chrome/browser/resources/lens/overlay/BUILD.gn
@@ -28,15 +28,15 @@
   grd_prefix = "lens_untrusted"
 
   static_files = [
+    "arrow_right.svg",
     "feedback.svg",
     "icon_clear.svg",
-    "arrow_right.svg",
     "learn_more.svg",
     "lens_overlay.html",
+    "side_panel/generic-error-icon-dark.png",
+    "side_panel/generic-error-icon.png",
     "side_panel/side_panel.html",
     "sparkles.svg",
-    "side_panel/generic-error-icon.png",
-    "side_panel/generic-error-icon-dark.png",
   ]
 
   if (is_chrome_branded) {
@@ -90,22 +90,22 @@
   ]
 
   ts_definitions = [
-    "paint_api.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
-    "//tools/typescript/definitions/metrics_private.d.ts",
     "//tools/typescript/definitions/language_settings_private.d.ts",
+    "//tools/typescript/definitions/metrics_private.d.ts",
+    "paint_api.d.ts",
   ]
 
   ts_composite = true
   mojo_files_deps =
       [ "//chrome/browser/lens/core/mojom:mojo_bindings_ts__generator" ]
   mojo_files = [
+    "$root_gen_dir/chrome/browser/lens/core/mojom/geometry.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/lens/core/mojom/lens.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/lens/core/mojom/lens_side_panel.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/lens/core/mojom/text.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/lens/core/mojom/overlay_object.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/lens/core/mojom/polygon.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/lens/core/mojom/geometry.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/lens/core/mojom/text.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/lens/core/mojom/translate.mojom-webui.ts",
   ]
 
diff --git a/chrome/browser/resources/media_router/cast_feedback/BUILD.gn b/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
index 64fe23b..7f20090 100644
--- a/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
+++ b/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
@@ -23,8 +23,8 @@
     "//ui/webui/resources/js:build_ts",
   ]
   ts_definitions = [
-    "//tools/typescript/definitions/feedback_private.d.ts",
     "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/feedback_private.d.ts",
   ]
   webui_context_type = "trusted"
 }
diff --git a/chrome/browser/resources/media_router/internals/BUILD.gn b/chrome/browser/resources/media_router/internals/BUILD.gn
index 98799668..40dcf52 100644
--- a/chrome/browser/resources/media_router/internals/BUILD.gn
+++ b/chrome/browser/resources/media_router/internals/BUILD.gn
@@ -10,8 +10,8 @@
   grd_prefix = "media_router_internals"
 
   static_files = [
-    "media_router_internals.html",
     "media_router_internals.css",
+    "media_router_internals.html",
   ]
   non_web_component_files = [ "media_router_internals.ts" ]
 
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index daa37f81..5daca8d8 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -24,8 +24,8 @@
 
   extra_grdp_files = [
     "$target_gen_dir/icons/resources.grdp",
-    "$target_gen_dir/modules/v2/calendar/icons/resources.grdp",
     "$target_gen_dir/modules/v2/authentication/icons/resources.grdp",
+    "$target_gen_dir/modules/v2/calendar/icons/resources.grdp",
   ]
 
   extra_grdp_deps = [
@@ -55,12 +55,12 @@
   mojo_files = [
     "$root_gen_dir/chrome/browser/new_tab_page/modules/file_suggestion/drive_suggestion.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/new_tab_page/modules/file_suggestion/file_suggestion.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/calendar_data.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/authentication/microsoft_auth.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/url_visit_types.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/calendar_data.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/url_visit_types.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom-webui.ts",
   ]
 
@@ -100,8 +100,8 @@
     ]
     optimize_webui_excludes = [
                                 "chrome://resources/cr_components/color_change_listener/color_change_listener.mojom-webui.js",
-                                "chrome://resources/cr_components/page_image_service/page_image_service.mojom-webui.js",
                                 "chrome://resources/cr_components/most_visited/most_visited.mojom-webui.js",
+                                "chrome://resources/cr_components/page_image_service/page_image_service.mojom-webui.js",
                                 "chrome://resources/cr_components/searchbox/searchbox.mojom-webui.js",
                                 "chrome://resources/js/browser_command/browser_command.mojom-webui.js",
                                 "chrome://resources/js/metrics_reporter/metrics_reporter.mojom-webui.js",
diff --git a/chrome/browser/resources/password_manager/BUILD.gn b/chrome/browser/resources/password_manager/BUILD.gn
index 7ec2ef22..42cb6f885 100644
--- a/chrome/browser/resources/password_manager/BUILD.gn
+++ b/chrome/browser/resources/password_manager/BUILD.gn
@@ -18,8 +18,8 @@
     "images/password_manager_logo.svg",
     "images/password_sharing_family_banner.svg",
     "images/password_sharing_family_banner_dark.svg",
-    "images/password_sharing_secure_lock.svg",
     "images/password_sharing_progress_bar.svg",
+    "images/password_sharing_secure_lock.svg",
     "password_manager.html",
   ]
   if (is_chrome_branded) {
@@ -27,6 +27,8 @@
       "chrome_branded_manifest.webmanifest",
       "images/access_on_any_device_promo.svg",
       "images/access_on_any_device_promo_dark.svg",
+      "images/move_passwords_promo.svg",
+      "images/move_passwords_promo_dark.svg",
       "images/password_checkup_promo.svg",
       "images/password_checkup_promo_dark.svg",
       "images/password_manager_screenshot_checkup_1x_en.png",
@@ -39,38 +41,36 @@
       "images/passwords_on_web_promo_dark.svg",
       "images/relaunch_chrome_promo.svg",
       "images/relaunch_chrome_promo_dark.svg",
-      "images/move_passwords_promo.svg",
-      "images/move_passwords_promo_dark.svg",
     ]
   } else {
     static_files += [
-      "manifest.webmanifest",
-      "images/relaunch_chrome_promo_non_branded.svg",
       "images/relaunch_chrome_promo_dark_non_branded.svg",
+      "images/relaunch_chrome_promo_non_branded.svg",
+      "manifest.webmanifest",
     ]
   }
 
   web_component_files = [
-    "checkup_section.ts",
     "checkup_details_section.ts",
     "checkup_list_item.ts",
+    "checkup_section.ts",
+    "credential_details/credential_field.ts",
+    "credential_details/credential_note.ts",
+    "credential_details/passkey_details_card.ts",
+    "credential_details/password_details_card.ts",
     "dialogs/add_password_dialog.ts",
     "dialogs/auth_timed_out_dialog.ts",
-    "dialogs/delete_password_disclaimer_dialog.ts",
     "dialogs/delete_passkey_dialog.ts",
+    "dialogs/delete_password_disclaimer_dialog.ts",
     "dialogs/disconnect_cloud_authenticator_dialog.ts",
     "dialogs/edit_passkey_dialog.ts",
     "dialogs/edit_password_dialog.ts",
     "dialogs/edit_password_disclaimer_dialog.ts",
-    "dialogs/multi_store_delete_password_dialog.ts",
     "dialogs/move_passwords_dialog.ts",
     "dialogs/move_single_password_dialog.ts",
+    "dialogs/multi_store_delete_password_dialog.ts",
     "dialogs/password_preview_item.ts",
     "full_data_reset.ts",
-    "credential_details/credential_note.ts",
-    "credential_details/credential_field.ts",
-    "credential_details/passkey_details_card.ts",
-    "credential_details/password_details_card.ts",
     "password_details_section.ts",
     "password_list_item.ts",
     "password_manager_app.ts",
@@ -78,42 +78,42 @@
     "passwords_importer.ts",
     "passwords_section.ts",
     "prefs/pref_toggle_button.ts",
+    "promo_cards/promo_card.ts",
     "settings_section.ts",
-    "sharing/share_password_flow.ts",
+    "sharing/share_password_confirmation_dialog.ts",
     "sharing/share_password_dialog_header.ts",
-    "sharing/share_password_group_avatar.ts",
-    "sharing/share_password_recipient.ts",
-    "sharing/share_password_family_picker_dialog.ts",
-    "sharing/share_password_loading_dialog.ts",
     "sharing/share_password_error_dialog.ts",
+    "sharing/share_password_family_picker_dialog.ts",
+    "sharing/share_password_flow.ts",
+    "sharing/share_password_group_avatar.ts",
+    "sharing/share_password_loading_dialog.ts",
     "sharing/share_password_no_other_family_members_dialog.ts",
     "sharing/share_password_not_family_member_dialog.ts",
-    "sharing/share_password_confirmation_dialog.ts",
+    "sharing/share_password_recipient.ts",
     "side_bar.ts",
     "site_favicon.ts",
     "toolbar.ts",
-    "promo_cards/promo_card.ts",
   ]
 
   non_web_component_files = [
-    "password_manager.ts",
-    "passkeys_browser_proxy.ts",
-    "password_manager_proxy.ts",
     "focus_config.ts",
+    "passkeys_browser_proxy.ts",
+    "password_manager.ts",
+    "password_manager_proxy.ts",
+    "promo_cards/promo_cards_browser_proxy.ts",
     "router.ts",
     "searchable_label.ts",
+    "sharing/metrics_utils.ts",
     "show_password_mixin.ts",
     "sync_browser_proxy.ts",
     "user_utils_mixin.ts",
-    "promo_cards/promo_cards_browser_proxy.ts",
-    "sharing/metrics_utils.ts",
   ]
 
   # Files that are passed as input to css_to_wrapper().
   css_files = [
     "credential_details/credential_details_card.css",
-    "shared_vars.css",
     "shared_style.css",
+    "shared_vars.css",
   ]
 
   icons_html_files = [ "icons.html" ]
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index 739ec22..3145368e 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -23,8 +23,8 @@
   # elements, once the bug with <if expr> breaking UIs when JS code coverage
   # is enabled has been fixed.
   web_component_files = [
-    "pdf_viewer.ts",
     "elements/viewer_toolbar.ts",
+    "pdf_viewer.ts",
   ]
 
   if (enable_ink) {
@@ -63,10 +63,10 @@
     "elements/viewer_pdf_sidenav.ts",
     "elements/viewer_properties_dialog.html.ts",
     "elements/viewer_properties_dialog.ts",
-    "elements/viewer_thumbnail_bar.html.ts",
-    "elements/viewer_thumbnail_bar.ts",
     "elements/viewer_thumbnail.html.ts",
     "elements/viewer_thumbnail.ts",
+    "elements/viewer_thumbnail_bar.html.ts",
+    "elements/viewer_thumbnail_bar.ts",
     "gesture_detector.ts",
     "internal_plugin.ts",
     "local_storage_proxy.ts",
@@ -75,13 +75,13 @@
     "metrics.ts",
     "navigator.ts",
     "open_pdf_params_parser.ts",
+    "pdf_internal_plugin_wrapper.ts",
     "pdf_print_wrapper.ts",
     "pdf_scripting_api.ts",
     "pdf_viewer_base.ts",
     "pdf_viewer_private_proxy.ts",
     "pdf_viewer_utils.ts",
     "pdf_viewer_wrapper.ts",
-    "pdf_internal_plugin_wrapper.ts",
     "swipe_detector.ts",
     "viewport.ts",
     "zoom_manager.ts",
@@ -109,18 +109,18 @@
 
   if (enable_pdf_ink2) {
     non_web_component_files += [
-      "elements/viewer_bottom_toolbar.html.ts",
-      "elements/viewer_bottom_toolbar.ts",
-      "elements/viewer_bottom_toolbar_dropdown.html.ts",
-      "elements/viewer_bottom_toolbar_dropdown.ts",
-      "elements/viewer_side_panel.html.ts",
-      "elements/viewer_side_panel.ts",
       "elements/ink_brush_selector.html.ts",
       "elements/ink_brush_selector.ts",
       "elements/ink_color_selector.html.ts",
       "elements/ink_color_selector.ts",
       "elements/ink_size_selector.html.ts",
       "elements/ink_size_selector.ts",
+      "elements/viewer_bottom_toolbar.html.ts",
+      "elements/viewer_bottom_toolbar.ts",
+      "elements/viewer_bottom_toolbar_dropdown.html.ts",
+      "elements/viewer_bottom_toolbar_dropdown.ts",
+      "elements/viewer_side_panel.html.ts",
+      "elements/viewer_side_panel.ts",
     ]
   }
 
@@ -151,12 +151,12 @@
 
   if (enable_pdf_ink2) {
     css_files += [
-      "elements/viewer_bottom_toolbar.css",
-      "elements/viewer_bottom_toolbar_dropdown.css",
-      "elements/viewer_side_panel.css",
       "elements/ink_brush_selector.css",
       "elements/ink_color_selector.css",
       "elements/ink_size_selector.css",
+      "elements/viewer_bottom_toolbar.css",
+      "elements/viewer_bottom_toolbar_dropdown.css",
+      "elements/viewer_side_panel.css",
     ]
   }
 
diff --git a/chrome/browser/resources/predictors/BUILD.gn b/chrome/browser/resources/predictors/BUILD.gn
index fceb85c..fbf3a9b 100644
--- a/chrome/browser/resources/predictors/BUILD.gn
+++ b/chrome/browser/resources/predictors/BUILD.gn
@@ -7,12 +7,12 @@
 build_webui("build") {
   grd_prefix = "predictors"
   static_files = [
-    "predictors.html",
     "predictors.css",
+    "predictors.html",
   ]
   non_web_component_files = [
-    "predictors.ts",
     "autocomplete_action_predictor.ts",
+    "predictors.ts",
     "resource_prefetch_predictor.ts",
   ]
 
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index 96395f3e..ab8597a 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -49,30 +49,26 @@
 
   if (is_chromeos) {
     web_component_files += [
+      "ui/destination_dialog_cros.ts",
       "ui/destination_dropdown_cros.ts",
       "ui/destination_list_item_cros.ts",
       "ui/destination_select_cros.ts",
       "ui/pin_settings.ts",
       "ui/printer_setup_info_cros.ts",
       "ui/provisional_destination_resolver.ts",
-      "ui/destination_dialog_cros.ts",
       "ui/searchable_drop_down_cros.ts",
     ]
   } else {
     web_component_files += [
-      "ui/destination_select.ts",
-      "ui/link_container.ts",
       "ui/destination_dialog.ts",
       "ui/destination_list_item.ts",
+      "ui/destination_select.ts",
+      "ui/link_container.ts",
     ]
   }
 
   non_web_component_files = [
     "dark_mode_mixin.ts",
-    "metrics.ts",
-    "native_layer.ts",
-    "print_preview.ts",
-    "print_preview_utils.ts",
     "data/cdd.ts",
     "data/coordinate2d.ts",
     "data/destination.ts",
@@ -87,6 +83,10 @@
     "data/scaling.ts",
     "data/size.ts",
     "data/state.ts",
+    "metrics.ts",
+    "native_layer.ts",
+    "print_preview.ts",
+    "print_preview_utils.ts",
     "ui/highlight_utils.ts",
     "ui/input_mixin.ts",
     "ui/plugin_proxy.ts",
diff --git a/chrome/browser/resources/privacy_sandbox/BUILD.gn b/chrome/browser/resources/privacy_sandbox/BUILD.gn
index 33f6b99..8b8c8274 100644
--- a/chrome/browser/resources/privacy_sandbox/BUILD.gn
+++ b/chrome/browser/resources/privacy_sandbox/BUILD.gn
@@ -11,43 +11,42 @@
   grd_prefix = "privacy_sandbox"
 
   static_files = [
-    "privacy_sandbox_dialog.html",
-    "privacy_sandbox_combined_dialog.html",
-    "privacy_sandbox_privacy_policy.html",
-    "privacy_sandbox_notice_dialog.html",
-    "privacy_sandbox_notice_restricted_dialog.html",
-    "images/privacy_sandbox_confirmation_banner.svg",
-    "images/privacy_sandbox_confirmation_banner_dark.svg",
-
-    "images/topics_banner.svg",
-    "images/topics_banner_dark.svg",
+    "images/chrome_logo.svg",
     "images/fledge_banner.svg",
     "images/fledge_banner_dark.svg",
-    "images/chrome_logo.svg",
+    "images/privacy_sandbox_confirmation_banner.svg",
+    "images/privacy_sandbox_confirmation_banner_dark.svg",
+    "images/topics_banner.svg",
+    "images/topics_banner_dark.svg",
+    "privacy_sandbox_combined_dialog.html",
+    "privacy_sandbox_dialog.html",
+    "privacy_sandbox_notice_dialog.html",
+    "privacy_sandbox_notice_restricted_dialog.html",
+    "privacy_sandbox_privacy_policy.html",
   ]
 
   web_component_files = [
-    "privacy_sandbox_dialog_app.ts",
     "privacy_sandbox_combined_dialog_app.ts",
+    "privacy_sandbox_dialog_app.ts",
+    "privacy_sandbox_dialog_consent_step.ts",
+    "privacy_sandbox_dialog_learn_more.ts",
+    "privacy_sandbox_dialog_notice_step.ts",
     "privacy_sandbox_notice_dialog_app.ts",
     "privacy_sandbox_notice_restricted_dialog_app.ts",
-    "privacy_sandbox_dialog_consent_step.ts",
-    "privacy_sandbox_dialog_notice_step.ts",
-    "privacy_sandbox_dialog_learn_more.ts",
   ]
 
   non_web_component_files = [
     "privacy_sandbox_dialog_browser_proxy.ts",
-    "privacy_sandbox_dialog_resize_mixin.ts",
     "privacy_sandbox_dialog_mixin.ts",
+    "privacy_sandbox_dialog_resize_mixin.ts",
     "privacy_sandbox_privacy_policy_dialog.html.ts",
     "privacy_sandbox_privacy_policy_dialog.ts",
   ]
 
   css_files = [
+    "privacy_sandbox_privacy_policy_dialog.css",
     "shared_style.css",
     "shared_vars.css",
-    "privacy_sandbox_privacy_policy_dialog.css",
   ]
 
   ts_composite = true
diff --git a/chrome/browser/resources/privacy_sandbox/internals/BUILD.gn b/chrome/browser/resources/privacy_sandbox/internals/BUILD.gn
index 097bd15f..0ec8da0 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/BUILD.gn
+++ b/chrome/browser/resources/privacy_sandbox/internals/BUILD.gn
@@ -10,11 +10,11 @@
 
   web_component_files = [
     "content_setting_pattern_source.ts",
-    "pref_display.ts",
-    "value_display.ts",
+    "cr_frame_list.ts",
     "mojo_timedelta.ts",
     "mojo_timestamp.ts",
-    "cr_frame_list.ts",
+    "pref_display.ts",
+    "value_display.ts",
   ]
   non_web_component_files = [ "index.ts" ]
   html_to_wrapper_template = "native"
@@ -26,10 +26,10 @@
     "//components/content_settings/core/common:mojo_bindings_ts__generator",
   ]
   mojo_files = [
+    "$root_gen_dir/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings_enums.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings_types.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom-webui.ts",
   ]
 
   ts_composite = true
@@ -42,12 +42,12 @@
   webui_context_type = "trusted"
   if (!is_android) {
     extra_grdp_files = [
-        "$target_gen_dir/private_state_tokens/resources.grdp",
-        "$target_gen_dir/related_website_sets/resources.grdp",
+      "$target_gen_dir/private_state_tokens/resources.grdp",
+      "$target_gen_dir/related_website_sets/resources.grdp",
     ]
     extra_grdp_deps = [
-        "private_state_tokens:build_grdp",
-        "related_website_sets:build_grdp",
+      "private_state_tokens:build_grdp",
+      "related_website_sets:build_grdp",
     ]
   }
 }
diff --git a/chrome/browser/resources/privacy_sandbox/internals/private_state_tokens/BUILD.gn b/chrome/browser/resources/privacy_sandbox/internals/private_state_tokens/BUILD.gn
index 4bc70e2c..867b0be 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/private_state_tokens/BUILD.gn
+++ b/chrome/browser/resources/privacy_sandbox/internals/private_state_tokens/BUILD.gn
@@ -12,22 +12,22 @@
   static_files = [ "private_state_tokens.html" ]
 
   non_web_component_files = [
-    "app.ts",
     "app.html.ts",
-    "list_container.ts",
-    "list_container.html.ts",
-    "navigation.ts",
-    "navigation.html.ts",
+    "app.ts",
     "browser_proxy.ts",
-    "list_item.ts",
+    "list_container.html.ts",
+    "list_container.ts",
     "list_item.html.ts",
-    "metadata.ts",
+    "list_item.ts",
     "metadata.html.ts",
+    "metadata.ts",
+    "navigation.html.ts",
+    "navigation.ts",
     "private_state_tokens.ts",
-    "sidebar.ts",
     "sidebar.html.ts",
-    "toolbar.ts",
+    "sidebar.ts",
     "toolbar.html.ts",
+    "toolbar.ts",
     "types.ts",
   ]
 
diff --git a/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/BUILD.gn b/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/BUILD.gn
index c16c8fc0..3f58b94c 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/BUILD.gn
+++ b/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/BUILD.gn
@@ -12,30 +12,30 @@
   static_files = [ "related_website_sets.html" ]
 
   non_web_component_files = [
-    "app.ts",
     "app.html.ts",
-    "related_website_sets.ts",
-    "list_container.ts",
+    "app.ts",
     "list_container.html.ts",
-    "list_item.ts",
+    "list_container.ts",
     "list_item.html.ts",
+    "list_item.ts",
+    "related_website_sets.ts",
+    "related_website_sets_api_proxy.ts",
+    "sidebar.html.ts",
+    "sidebar.ts",
+    "site_favicon.html.ts",
+    "site_favicon.ts",
     "toolbar.html.ts",
     "toolbar.ts",
-    "sidebar.ts",
-    "sidebar.html.ts",
-    "site_favicon.ts",
-    "site_favicon.html.ts",
-    "related_website_sets_api_proxy.ts",
   ]
 
   css_files = [
     "app.css",
     "list_container.css",
     "list_item.css",
-    "toolbar.css",
     "shared_vars.css",
     "sidebar.css",
     "site_favicon.css",
+    "toolbar.css",
   ]
 
   mojo_files_deps = [ "//chrome/browser/ui/webui/privacy_sandbox/related_website_sets:mojo_bindings_ts__generator" ]
diff --git a/chrome/browser/resources/search_engine_choice/BUILD.gn b/chrome/browser/resources/search_engine_choice/BUILD.gn
index d15d24c..9f090dc 100644
--- a/chrome/browser/resources/search_engine_choice/BUILD.gn
+++ b/chrome/browser/resources/search_engine_choice/BUILD.gn
@@ -8,10 +8,10 @@
   grd_prefix = "search_engine_choice"
 
   static_files = [
-    "search_engine_choice.html",
     "images/arrow_downward.svg",
     "images/info_dialog_illustration.svg",
     "images/info_dialog_illustration_dark.svg",
+    "search_engine_choice.html",
   ]
 
   non_web_component_files = [
diff --git a/chrome/browser/resources/segmentation_internals/BUILD.gn b/chrome/browser/resources/segmentation_internals/BUILD.gn
index 666de26ab..cb590669 100644
--- a/chrome/browser/resources/segmentation_internals/BUILD.gn
+++ b/chrome/browser/resources/segmentation_internals/BUILD.gn
@@ -12,8 +12,8 @@
   ]
   non_web_component_files = [
     "segmentation_internals.ts",
-    "segmentation_survey.ts",
     "segmentation_internals_browser_proxy.ts",
+    "segmentation_survey.ts",
   ]
   mojo_files_deps = [ "//chrome/browser/ui/webui/segmentation_internals:mojo_bindings_ts__generator" ]
   mojo_files = [ "$root_gen_dir/chrome/browser/ui/webui/segmentation_internals/segmentation_internals.mojom-webui.ts" ]
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 0c5164d1..af16cc0 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -18,36 +18,36 @@
     "images/cvc_amex.svg",
     "images/googleg_standard_clr_32px.svg",
     "images/iban.svg",
-    "images/password_check_neutral_dark.svg",
     "images/password_check_neutral.svg",
-    "images/password_check_positive_dark.svg",
+    "images/password_check_neutral_dark.svg",
     "images/password_check_positive.svg",
+    "images/password_check_positive_dark.svg",
     "images/privacy_guide/ad_topics_graphic.svg",
     "images/privacy_guide/ad_topics_graphic_dark.svg",
-    "images/privacy_guide/clouds_graphic_dark.svg",
     "images/privacy_guide/clouds_graphic.svg",
+    "images/privacy_guide/clouds_graphic_dark.svg",
     "images/privacy_guide/completion_banner_dark_v2.svg",
     "images/privacy_guide/completion_banner_v2.svg",
     "images/privacy_guide/cookies_graphic_dark_v2.svg",
     "images/privacy_guide/cookies_graphic_v2.svg",
-    "images/privacy_guide/hills_graphic_dark.svg",
     "images/privacy_guide/hills_graphic.svg",
+    "images/privacy_guide/hills_graphic_dark.svg",
     "images/privacy_guide/history_sync_graphic_dark_v2.svg",
     "images/privacy_guide/history_sync_graphic_v2.svg",
-    "images/privacy_guide/horizon_graphic_dark.svg",
     "images/privacy_guide/horizon_graphic.svg",
+    "images/privacy_guide/horizon_graphic_dark.svg",
     "images/privacy_guide/msbb_graphic_dark_v2.svg",
     "images/privacy_guide/msbb_graphic_v2.svg",
-    "images/privacy_guide/promo_banner_dark.svg",
     "images/privacy_guide/promo_banner.svg",
+    "images/privacy_guide/promo_banner_dark.svg",
     "images/privacy_guide/safe_browsing_graphic_dark_v2.svg",
     "images/privacy_guide/safe_browsing_graphic_v2.svg",
-    "images/privacy_guide/welcome_banner_dark.svg",
     "images/privacy_guide/welcome_banner.svg",
-    "images/sync_banner_dark.svg",
+    "images/privacy_guide/welcome_banner_dark.svg",
     "images/sync_banner.svg",
-    "images/tracking_protection_banner_dark.svg",
+    "images/sync_banner_dark.svg",
     "images/tracking_protection_banner.svg",
+    "images/tracking_protection_banner_dark.svg",
     "settings.html",
   ]
 
@@ -84,8 +84,8 @@
     "clear_browsing_data_dialog/passwords_deletion_dialog.ts",
     "controls/controlled_button.ts",
     "controls/controlled_radio_button.ts",
-    "controls/settings_checkbox_list_entry.ts",
     "controls/settings_checkbox.ts",
+    "controls/settings_checkbox_list_entry.ts",
     "controls/settings_dropdown_menu.ts",
     "controls/settings_radio_group.ts",
     "controls/settings_slider.ts",
@@ -95,6 +95,11 @@
     "on_startup_page/startup_url_dialog.ts",
     "on_startup_page/startup_url_entry.ts",
     "on_startup_page/startup_urls_page.ts",
+    "people_page/people_page.ts",
+    "people_page/signout_dialog.ts",
+    "people_page/sync_controls.ts",
+    "people_page/sync_encryption_options.ts",
+    "people_page/sync_page.ts",
     "performance_page/battery_page.ts",
     "performance_page/memory_page.ts",
     "performance_page/performance_page.ts",
@@ -106,16 +111,11 @@
     "performance_page/tab_discard/exception_entry.ts",
     "performance_page/tab_discard/exception_list.ts",
     "performance_page/tab_discard/exception_tabbed_add_dialog.ts",
-    "people_page/people_page.ts",
-    "people_page/signout_dialog.ts",
-    "people_page/sync_controls.ts",
-    "people_page/sync_encryption_options.ts",
-    "people_page/sync_page.ts",
     "privacy_page/anti_abuse_page.ts",
     "privacy_page/collapse_radio_button.ts",
     "privacy_page/cookies_page.ts",
-    "privacy_page/fingerprint_progress_arc.ts",
     "privacy_page/do_not_track_toggle.ts",
+    "privacy_page/fingerprint_progress_arc.ts",
     "privacy_page/personalization_options.ts",
     "privacy_page/privacy_guide/privacy_guide_ad_topics_fragment.ts",
     "privacy_page/privacy_guide/privacy_guide_completion_fragment.ts",
@@ -133,29 +133,29 @@
     "privacy_page/secure_dns_input.ts",
     "privacy_page/security_keys_bio_enroll_dialog.ts",
     "privacy_page/security_keys_credential_management_dialog.ts",
+    "privacy_page/security_keys_phones_dialog.ts",
+    "privacy_page/security_keys_phones_list.ts",
+    "privacy_page/security_keys_phones_subpage.ts",
     "privacy_page/security_keys_pin_field.ts",
     "privacy_page/security_keys_reset_dialog.ts",
     "privacy_page/security_keys_set_pin_dialog.ts",
     "privacy_page/security_keys_subpage.ts",
-    "privacy_page/security_keys_phones_subpage.ts",
-    "privacy_page/security_keys_phones_list.ts",
-    "privacy_page/security_keys_phones_dialog.ts",
     "privacy_page/security_page.ts",
     "privacy_sandbox/privacy_sandbox_ad_measurement_subpage.ts",
     "privacy_sandbox/privacy_sandbox_fledge_subpage.ts",
     "privacy_sandbox/privacy_sandbox_interest_item.ts",
-    "privacy_sandbox/privacy_sandbox_page.ts",
     "privacy_sandbox/privacy_sandbox_manage_topics_subpage.ts",
+    "privacy_sandbox/privacy_sandbox_page.ts",
     "privacy_sandbox/privacy_sandbox_topics_subpage.ts",
     "reset_page/reset_page.ts",
     "reset_page/reset_profile_banner.ts",
     "reset_page/reset_profile_dialog.ts",
+    "safety_hub/extensions_module.ts",
+    "safety_hub/notification_permissions_module.ts",
     "safety_hub/safety_hub_card.ts",
     "safety_hub/safety_hub_entry_point.ts",
     "safety_hub/safety_hub_module.ts",
-    "safety_hub/extensions_module.ts",
     "safety_hub/safety_hub_page.ts",
-    "safety_hub/notification_permissions_module.ts",
     "safety_hub/unused_site_permissions_module.ts",
     "search_engines_page/omnibox_extension_entry.ts",
     "search_engines_page/search_engine_edit_dialog.ts",
@@ -175,44 +175,44 @@
     "site_settings/add_site_dialog.ts",
     "site_settings/all_sites.ts",
     "site_settings/category_setting_exceptions.ts",
-    "site_settings/chooser_exception_list_entry.ts",
     "site_settings/chooser_exception_list.ts",
-    "site_settings/site_details_permission_device_entry.ts",
+    "site_settings/chooser_exception_list_entry.ts",
     "site_settings/edit_exception_dialog.ts",
     "site_settings/file_system_site_details.ts",
     "site_settings/file_system_site_entry.ts",
     "site_settings/file_system_site_entry_item.ts",
     "site_settings/file_system_site_list.ts",
     "site_settings/media_picker.ts",
-    "site_settings_page/recent_site_permissions.ts",
-    "site_settings_page/site_settings_list.ts",
-    "site_settings_page/site_settings_page.ts",
-    "site_settings/smart_card_readers_page.ts",
-    "site_settings/smart_card_reader_origin_entry.ts",
     "site_settings/pdf_documents.ts",
     "site_settings/protocol_handlers.ts",
     "site_settings/settings_category_default_radio_group.ts",
     "site_settings/site_data.ts",
-    "site_settings/site_details_permission.ts",
     "site_settings/site_details.ts",
+    "site_settings/site_details_permission.ts",
+    "site_settings/site_details_permission_device_entry.ts",
     "site_settings/site_entry.ts",
-    "site_settings/site_list_entry.ts",
     "site_settings/site_list.ts",
-    "site_settings/storage_access_static_site_list_entry.ts",
-    "site_settings/storage_access_site_list_entry.ts",
+    "site_settings/site_list_entry.ts",
+    "site_settings/smart_card_reader_origin_entry.ts",
+    "site_settings/smart_card_readers_page.ts",
     "site_settings/storage_access_site_list.ts",
+    "site_settings/storage_access_site_list_entry.ts",
+    "site_settings/storage_access_static_site_list_entry.ts",
     "site_settings/zoom_levels.ts",
+    "site_settings_page/recent_site_permissions.ts",
+    "site_settings_page/site_settings_list.ts",
+    "site_settings_page/site_settings_page.ts",
   ]
 
   if (!is_chromeos_ash) {
     web_component_files += [
-      "people_page/manage_profile.ts",
-      "people_page/sync_account_control.ts",
-      "relaunch_confirmation_dialog.ts",
       "languages_page/add_languages_dialog.ts",
       "languages_page/languages_page.ts",
       "languages_page/spell_check_page.ts",
       "languages_page/translate_page.ts",
+      "people_page/manage_profile.ts",
+      "people_page/sync_account_control.ts",
+      "relaunch_confirmation_dialog.ts",
       "system_page/system_page.ts",
     ]
   }
@@ -289,8 +289,8 @@
     "privacy_page/privacy_guide/constants.ts",
     "privacy_page/privacy_guide/privacy_guide_availability_mixin.ts",
     "privacy_page/privacy_guide/privacy_guide_browser_proxy.ts",
-    "privacy_sandbox/privacy_sandbox_browser_proxy.ts",
     "privacy_page/security_keys_browser_proxy.ts",
+    "privacy_sandbox/privacy_sandbox_browser_proxy.ts",
     "relaunch_mixin.ts",
     "reset_page/reset_browser_proxy.ts",
     "route.ts",
@@ -316,9 +316,9 @@
   } else {
     non_web_component_files += [
       "default_browser_page/default_browser_browser_proxy.ts",
+      "languages_page/languages.ts",
       "languages_page/languages_browser_proxy.ts",
       "languages_page/languages_settings_metrics_proxy.ts",
-      "languages_page/languages.ts",
       "languages_page/languages_types.ts",
       "people_page/import_data_browser_proxy.ts",
       "people_page/manage_profile_browser_proxy.ts",
@@ -356,8 +356,8 @@
     "settings_vars.css",
 
     # subfolder files
-    "autofill_page/screen_reader_only.css",
     "autofill_page/passwords_shared.css",
+    "autofill_page/screen_reader_only.css",
     "privacy_page/cr_lottie.css",
     "privacy_page/privacy_guide/privacy_guide_fragment_shared.css",
     "search_engines_page/search_engine_entry.css",
diff --git a/chrome/browser/resources/settings_shared/BUILD.gn b/chrome/browser/resources/settings_shared/BUILD.gn
index 52c6030..9fca5d3d 100644
--- a/chrome/browser/resources/settings_shared/BUILD.gn
+++ b/chrome/browser/resources/settings_shared/BUILD.gn
@@ -20,21 +20,20 @@
   ]
 
   non_web_component_files = [
-    "extension_control_browser_proxy.ts",
-    "lifetime_browser_proxy.ts",
-
     "a11y_page/ax_annotations_browser_proxy.ts",
     "a11y_page/captions_browser_proxy.ts",
     "appearance_page/fonts_browser_proxy.ts",
     "controls/cr_policy_pref_mixin.ts",
     "controls/pref_control_mixin.ts",
     "controls/settings_boolean_control_mixin.ts",
+    "extension_control_browser_proxy.ts",
+    "lifetime_browser_proxy.ts",
     "people_page/profile_info_browser_proxy.ts",
     "people_page/sync_browser_proxy.ts",
-    "prefs/prefs_mixin.ts",
-    "prefs/prefs.ts",
-    "prefs/prefs_types.ts",
     "prefs/pref_util.ts",
+    "prefs/prefs.ts",
+    "prefs/prefs_mixin.ts",
+    "prefs/prefs_types.ts",
     "privacy_page/privacy_page_browser_proxy.ts",
   ]
 
@@ -47,9 +46,9 @@
   ]
   if (is_chromeos) {
     ts_definitions += [
-      "//tools/typescript/definitions/tabs.d.ts",
-      "//tools/typescript/definitions/runtime.d.ts",
       "//tools/typescript/definitions/quick_unlock_private.d.ts",
+      "//tools/typescript/definitions/runtime.d.ts",
+      "//tools/typescript/definitions/tabs.d.ts",
     ]
   }
   ts_deps = [
diff --git a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn b/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
index 5ad1fd3..da5c583 100644
--- a/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/side_panel/bookmarks/BUILD.gn
@@ -10,8 +10,8 @@
   grd_prefix = "side_panel_bookmarks"
 
   static_files = [
-    "images/bookmarks_empty_dark.svg",
     "images/bookmarks_empty.svg",
+    "images/bookmarks_empty_dark.svg",
     "power_bookmarks.html",
   ]
 
@@ -26,11 +26,11 @@
 
   non_web_component_files = [
     "bookmarks_api_proxy.ts",
-    "power_bookmarks_drag_manager.ts",
     "power_bookmark_row.html.ts",
     "power_bookmark_row.ts",
-    "power_bookmarks_utils.ts",
+    "power_bookmarks_drag_manager.ts",
     "power_bookmarks_service.ts",
+    "power_bookmarks_utils.ts",
   ]
 
   css_files = [ "power_bookmark_row.css" ]
@@ -45,9 +45,9 @@
 
   ts_composite = true
   ts_definitions = [
-    "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/bookmark_manager_private.d.ts",
     "//tools/typescript/definitions/bookmarks.d.ts",
+    "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
     "//tools/typescript/definitions/tabs.d.ts",
   ]
diff --git a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
index 18dbcd9..59d9352 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
+++ b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
@@ -15,10 +15,10 @@
   extra_grdp_files = [ "$target_gen_dir/icons/resources.grdp" ]
 
   non_web_component_files = [
-    "appearance.html.ts",
-    "appearance.ts",
     "app.html.ts",
     "app.ts",
+    "appearance.html.ts",
+    "appearance.ts",
     "button_label.html.ts",
     "button_label.ts",
     "cards.html.ts",
@@ -29,26 +29,25 @@
     "check_mark_wrapper.ts",
     "common.ts",
     "customize_chrome_api_proxy.ts",
+    "customize_toolbar/customize_toolbar_api_proxy.ts",
+    "customize_toolbar/toolbar.html.ts",
+    "customize_toolbar/toolbar.ts",
     "hover_button.html.ts",
     "hover_button.ts",
     "shortcuts.html.ts",
     "shortcuts.ts",
-    "themes.html.ts",
     "theme_snapshot.html.ts",
     "theme_snapshot.ts",
+    "themes.html.ts",
     "themes.ts",
-    "window_proxy.ts",
-
-    "customize_toolbar/customize_toolbar_api_proxy.ts",
-    "customize_toolbar/toolbar.html.ts",
-    "customize_toolbar/toolbar.ts",
     "wallpaper_search/combobox/customize_chrome_combobox.html.ts",
     "wallpaper_search/combobox/customize_chrome_combobox.ts",
     "wallpaper_search/wallpaper_search.html.ts",
+    "wallpaper_search/wallpaper_search.ts",
     "wallpaper_search/wallpaper_search_proxy.ts",
     "wallpaper_search/wallpaper_search_tile.html.ts",
     "wallpaper_search/wallpaper_search_tile.ts",
-    "wallpaper_search/wallpaper_search.ts",
+    "window_proxy.ts",
   ]
 
   css_files = [
@@ -61,8 +60,8 @@
     "customize_toolbar/toolbar.css",
     "hover_button.css",
     "shortcuts.css",
-    "themes.css",
     "theme_snapshot.css",
+    "themes.css",
     "wallpaper_search/combobox/customize_chrome_combobox.css",
     "wallpaper_search/wallpaper_search.css",
     "wallpaper_search/wallpaper_search_tile.css",
diff --git a/chrome/browser/resources/side_panel/history_clusters/BUILD.gn b/chrome/browser/resources/side_panel/history_clusters/BUILD.gn
index 2116f7e4..3075b8c 100644
--- a/chrome/browser/resources/side_panel/history_clusters/BUILD.gn
+++ b/chrome/browser/resources/side_panel/history_clusters/BUILD.gn
@@ -12,8 +12,8 @@
   static_files = [ "history_clusters.html" ]
 
   non_web_component_files = [
-    "app.ts",
     "app.html.ts",
+    "app.ts",
     "history_clusters.ts",
   ]
   css_files = [ "app.css" ]
diff --git a/chrome/browser/resources/side_panel/read_anything/BUILD.gn b/chrome/browser/resources/side_panel/read_anything/BUILD.gn
index 6ca49c3d..9a847ad 100644
--- a/chrome/browser/resources/side_panel/read_anything/BUILD.gn
+++ b/chrome/browser/resources/side_panel/read_anything/BUILD.gn
@@ -10,38 +10,38 @@
   grd_prefix = "side_panel_read_anything"
 
   static_files = [
-    "read_anything.html",
     "images/empty_state.svg",
+    "read_anything.html",
   ]
 
   web_component_files = [
     "app.ts",
     "language_menu.ts",
     "language_toast.ts",
-    "read_anything_toolbar.ts",
-    "voice_selection_menu.ts",
-    "menus/simple_action_menu.ts",
     "menus/color_menu.ts",
     "menus/highlight_menu.ts",
-    "menus/line_spacing_menu.ts",
     "menus/letter_spacing_menu.ts",
+    "menus/line_spacing_menu.ts",
+    "menus/simple_action_menu.ts",
+    "read_anything_toolbar.ts",
+    "voice_selection_menu.ts",
   ]
   non_web_component_files = [
-    "read_anything.ts",
+    "app_style_updater.ts",
     "common.ts",
+    "menus/menu_util.ts",
     "metrics_browser_proxy.ts",
+    "read_anything.ts",
     "read_anything_logger.ts",
     "voice_language_util.ts",
-    "app_style_updater.ts",
-    "menus/menu_util.ts",
     "voice_notification_manager.ts",
   ]
   css_files = [
     "app.css",
     "language_menu.css",
     "language_toast.css",
-    "voice_selection_menu.css",
     "read_anything_toolbar.css",
+    "voice_selection_menu.css",
   ]
   icons_html_files = [ "icons.html" ]
   html_to_wrapper_template = "detect"
@@ -57,9 +57,9 @@
     "//ui/webui/resources/mojo:build_ts",
   ]
   ts_definitions = [
-    "read_anything.d.ts",
-    "//tools/typescript/definitions/pending.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
+    "//tools/typescript/definitions/pending.d.ts",
+    "read_anything.d.ts",
   ]
   ts_path_mappings =
       [ "//read-anything-side-panel.top-chrome/shared/*|" +
diff --git a/chrome/browser/resources/side_panel/reading_list/BUILD.gn b/chrome/browser/resources/side_panel/reading_list/BUILD.gn
index 2d0a7eb..dac4b99 100644
--- a/chrome/browser/resources/side_panel/reading_list/BUILD.gn
+++ b/chrome/browser/resources/side_panel/reading_list/BUILD.gn
@@ -10,9 +10,9 @@
   grd_prefix = "side_panel_reading_list"
 
   static_files = [
-    "reading_list.html",
-    "images/read_later_empty_dark.svg",
     "images/read_later_empty.svg",
+    "images/read_later_empty_dark.svg",
+    "reading_list.html",
   ]
 
   non_web_component_files = [
diff --git a/chrome/browser/resources/signin/BUILD.gn b/chrome/browser/resources/signin/BUILD.gn
index 466ce2d..2618758 100644
--- a/chrome/browser/resources/signin/BUILD.gn
+++ b/chrome/browser/resources/signin/BUILD.gn
@@ -21,18 +21,18 @@
     "images/shared_left_banner_dark.svg",
     "images/shared_right_banner.svg",
     "images/shared_right_banner_dark.svg",
+    "managed_user_profile_notice/images/data_handling.svg",
+    "managed_user_profile_notice/images/enrollment_failure.svg",
+    "managed_user_profile_notice/images/enrollment_failure_dark.svg",
+    "managed_user_profile_notice/images/enrollment_success.svg",
+    "managed_user_profile_notice/images/enrollment_success_dark.svg",
+    "managed_user_profile_notice/images/enrollment_timeout.svg",
+    "managed_user_profile_notice/images/enrollment_timeout_dark.svg",
     "profile_customization/images/profile_customization_illustration.svg",
     "profile_customization/images/profile_customization_illustration_dark.svg",
     "sync_confirmation/sync_confirmation.html",
     "sync_confirmation/sync_disabled_confirmation.html",
     "sync_confirmation/sync_loading_confirmation.html",
-    "managed_user_profile_notice/images/data_handling.svg",
-    "managed_user_profile_notice/images/enrollment_failure.svg",
-    "managed_user_profile_notice/images/enrollment_success.svg",
-    "managed_user_profile_notice/images/enrollment_timeout.svg",
-    "managed_user_profile_notice/images/enrollment_failure_dark.svg",
-    "managed_user_profile_notice/images/enrollment_success_dark.svg",
-    "managed_user_profile_notice/images/enrollment_timeout_dark.svg",
   ]
   if (!is_chromeos_ash) {
     static_files += [
@@ -40,8 +40,8 @@
       "profile_customization/profile_customization.html",
       "signin_email_confirmation/signin_email_confirmation.html",
       "signin_error/signin_error.html",
-      "signin_reauth/images/account_passwords_reauth_illustration_dark.svg",
       "signin_reauth/images/account_passwords_reauth_illustration.svg",
+      "signin_reauth/images/account_passwords_reauth_illustration_dark.svg",
       "signin_reauth/signin_reauth.html",
     ]
   }
@@ -54,10 +54,10 @@
   }
 
   non_web_component_files = [
+    "sync_confirmation/sync_confirmation.ts",
     "sync_confirmation/sync_confirmation_app.html.ts",
     "sync_confirmation/sync_confirmation_app.ts",
     "sync_confirmation/sync_confirmation_browser_proxy.ts",
-    "sync_confirmation/sync_confirmation.ts",
     "sync_confirmation/sync_disabled_confirmation_app.html.ts",
     "sync_confirmation/sync_disabled_confirmation_app.ts",
   ]
@@ -73,18 +73,18 @@
       "managed_user_profile_notice/managed_user_profile_notice_data_handling.ts",
       "managed_user_profile_notice/managed_user_profile_notice_disclosure.html.ts",
       "managed_user_profile_notice/managed_user_profile_notice_disclosure.ts",
-      "managed_user_profile_notice/managed_user_profile_notice_value_prop.html.ts",
-      "managed_user_profile_notice/managed_user_profile_notice_value_prop.ts",
       "managed_user_profile_notice/managed_user_profile_notice_state.html.ts",
       "managed_user_profile_notice/managed_user_profile_notice_state.ts",
+      "managed_user_profile_notice/managed_user_profile_notice_value_prop.html.ts",
+      "managed_user_profile_notice/managed_user_profile_notice_value_prop.ts",
       "profile_customization/profile_customization_app.html.ts",
       "profile_customization/profile_customization_app.ts",
       "profile_customization/profile_customization_browser_proxy.ts",
       "signin_email_confirmation/signin_email_confirmation_app.html.ts",
       "signin_email_confirmation/signin_email_confirmation_app.ts",
+      "signin_error/signin_error.ts",
       "signin_error/signin_error_app.html.ts",
       "signin_error/signin_error_app.ts",
-      "signin_error/signin_error.ts",
       "signin_reauth/signin_reauth_app.html.ts",
       "signin_reauth/signin_reauth_app.ts",
       "signin_reauth/signin_reauth_browser_proxy.ts",
diff --git a/chrome/browser/resources/signin/batch_upload/BUILD.gn b/chrome/browser/resources/signin/batch_upload/BUILD.gn
index efd4a6e..3919236 100644
--- a/chrome/browser/resources/signin/batch_upload/BUILD.gn
+++ b/chrome/browser/resources/signin/batch_upload/BUILD.gn
@@ -6,12 +6,12 @@
   static_files = [ "batch_upload.html" ]
 
   non_web_component_files = [
-    "batch_upload_app.ts",
-    "batch_upload_app.html.ts",
     "batch_upload.ts",
+    "batch_upload_app.html.ts",
+    "batch_upload_app.ts",
     "browser_proxy.ts",
-    "data_section.ts",
     "data_section.html.ts",
+    "data_section.ts",
   ]
 
   css_files = [
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 5b0f5b0..5244ffe5 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -42,8 +42,8 @@
     "profile_card.css",
     "profile_card_menu.css",
     "profile_creation_flow/profile_type_choice.css",
-    "profile_picker_main_view.css",
     "profile_picker_app.css",
+    "profile_picker_main_view.css",
     "profile_picker_shared.css",
     "profile_switch.css",
   ]
diff --git a/chrome/browser/resources/tab_search/BUILD.gn b/chrome/browser/resources/tab_search/BUILD.gn
index ad79bca1..e643dd7 100644
--- a/chrome/browser/resources/tab_search/BUILD.gn
+++ b/chrome/browser/resources/tab_search/BUILD.gn
@@ -24,11 +24,6 @@
   non_web_component_files = [
     "app.html.ts",
     "app.ts",
-    "lazy_list.ts",
-    "selectable_lazy_list.ts",
-    "search.ts",
-    "tab_data.ts",
-    "tab_group_color_helper.ts",
     "auto_tab_groups/auto_tab_groups_failure.html.ts",
     "auto_tab_groups/auto_tab_groups_failure.ts",
     "auto_tab_groups/auto_tab_groups_group.html.ts",
@@ -38,21 +33,27 @@
     "auto_tab_groups/auto_tab_groups_new_badge.html.ts",
     "auto_tab_groups/auto_tab_groups_new_badge.ts",
     "auto_tab_groups/auto_tab_groups_not_started.html.ts",
+    "auto_tab_groups/auto_tab_groups_not_started.ts",
     "auto_tab_groups/auto_tab_groups_not_started_image.html.ts",
     "auto_tab_groups/auto_tab_groups_not_started_image.ts",
-    "auto_tab_groups/auto_tab_groups_not_started.ts",
     "auto_tab_groups/auto_tab_groups_page.html.ts",
     "auto_tab_groups/auto_tab_groups_page.ts",
-    "auto_tab_groups/auto_tab_groups_results_actions.html.ts",
-    "auto_tab_groups/auto_tab_groups_results_actions.ts",
     "auto_tab_groups/auto_tab_groups_results.html.ts",
     "auto_tab_groups/auto_tab_groups_results.ts",
+    "auto_tab_groups/auto_tab_groups_results_actions.html.ts",
+    "auto_tab_groups/auto_tab_groups_results_actions.ts",
     "declutter/declutter_page.html.ts",
     "declutter/declutter_page.ts",
-    "tab_organization_selector_button.html.ts",
-    "tab_organization_selector_button.ts",
+    "lazy_list.ts",
+    "search.ts",
+    "selectable_lazy_list.ts",
+    "tab_data.ts",
+    "tab_group_color_helper.ts",
     "tab_organization_selector.html.ts",
     "tab_organization_selector.ts",
+    "tab_organization_selector_button.html.ts",
+    "tab_organization_selector_button.ts",
+    "tab_search.ts",
     "tab_search_api_proxy.ts",
     "tab_search_group_item.html.ts",
     "tab_search_group_item.ts",
@@ -61,17 +62,12 @@
     "tab_search_page.html.ts",
     "tab_search_page.ts",
     "tab_search_sync_browser_proxy.ts",
-    "tab_search.ts",
     "tab_search_utils.ts",
     "title_item.ts",
   ]
 
   css_files = [
     "app.css",
-    "lazy_list.css",
-    "selectable_lazy_list.css",
-    "tab_search_page.css",
-    "tab_group_shared_vars.css",
     "auto_tab_groups/auto_tab_groups_failure.css",
     "auto_tab_groups/auto_tab_groups_group.css",
     "auto_tab_groups/auto_tab_groups_in_progress.css",
@@ -79,14 +75,18 @@
     "auto_tab_groups/auto_tab_groups_not_started.css",
     "auto_tab_groups/auto_tab_groups_not_started_image.css",
     "auto_tab_groups/auto_tab_groups_page.css",
-    "auto_tab_groups/auto_tab_groups_results_actions.css",
     "auto_tab_groups/auto_tab_groups_results.css",
+    "auto_tab_groups/auto_tab_groups_results_actions.css",
     "auto_tab_groups/auto_tab_groups_shared_style.css",
     "declutter/declutter_page.css",
-    "tab_organization_selector_button.css",
+    "lazy_list.css",
+    "selectable_lazy_list.css",
+    "tab_group_shared_vars.css",
     "tab_organization_selector.css",
+    "tab_organization_selector_button.css",
     "tab_search_group_item.css",
     "tab_search_item.css",
+    "tab_search_page.css",
   ]
 
   mojo_files_deps = [
@@ -104,8 +104,8 @@
 
   ts_composite = true
   ts_definitions = [
-    "//tools/typescript/definitions/pending.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
+    "//tools/typescript/definitions/pending.d.ts",
   ]
   ts_deps = [
     "//third_party/lit/v3_0:build_ts",
diff --git a/chrome/browser/resources/tab_strip/BUILD.gn b/chrome/browser/resources/tab_strip/BUILD.gn
index 3222a38..886a86f6 100644
--- a/chrome/browser/resources/tab_strip/BUILD.gn
+++ b/chrome/browser/resources/tab_strip/BUILD.gn
@@ -29,16 +29,16 @@
   web_component_files = [
     "alert_indicator.ts",
     "alert_indicators.ts",
+    "tab.ts",
     "tab_group.ts",
     "tab_list.ts",
-    "tab.ts",
   ]
   html_to_wrapper_template = "native"
 
   non_web_component_files = [
     "drag_manager.ts",
-    "tabs_api_proxy.ts",
     "tab_swiper.ts",
+    "tabs_api_proxy.ts",
   ]
 
   mojo_files_deps = [
diff --git a/chrome/browser/resources/webui_gallery/BUILD.gn b/chrome/browser/resources/webui_gallery/BUILD.gn
index f7e55ae..b5a40f22c 100644
--- a/chrome/browser/resources/webui_gallery/BUILD.gn
+++ b/chrome/browser/resources/webui_gallery/BUILD.gn
@@ -48,12 +48,12 @@
   non_web_component_files = [
     "app.html.ts",
     "app.ts",
-    "demos/cr_a11y_announcer/cr_a11y_announcer_demo.html.ts",
-    "demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts",
     "demos/buttons/buttons_demo.html.ts",
     "demos/buttons/buttons_demo.ts",
     "demos/card/card_demo.html.ts",
     "demos/card/card_demo.ts",
+    "demos/cr_a11y_announcer/cr_a11y_announcer_demo.html.ts",
+    "demos/cr_a11y_announcer/cr_a11y_announcer_demo.ts",
     "demos/cr_action_menu/cr_action_menu_demo.html.ts",
     "demos/cr_action_menu/cr_action_menu_demo.ts",
     "demos/cr_checkbox/cr_checkbox_demo.html.ts",
@@ -85,10 +85,10 @@
     "demos/cr_url_list_item/cr_url_list_item_demo.ts",
     "demos/md_select/md_select_demo.html.ts",
     "demos/md_select/md_select_demo.ts",
-    "demos/nav_menu/nav_menu_demo.html.ts",
-    "demos/nav_menu/nav_menu_demo.ts",
     "demos/nav_menu/nav_menu.html.ts",
     "demos/nav_menu/nav_menu.ts",
+    "demos/nav_menu/nav_menu_demo.html.ts",
+    "demos/nav_menu/nav_menu_demo.ts",
     "demos/progress_indicators/progress_indicator_demo.html.ts",
     "demos/progress_indicators/progress_indicator_demo.ts",
     "demos/scroll_view/scroll_view_demo.html.ts",
diff --git a/chrome/browser/segmentation_platform/android/home_modules_ranking_helper.cc b/chrome/browser/segmentation_platform/android/home_modules_ranking_helper.cc
index 27edbd2..e97b7ae 100644
--- a/chrome/browser/segmentation_platform/android/home_modules_ranking_helper.cc
+++ b/chrome/browser/segmentation_platform/android/home_modules_ranking_helper.cc
@@ -69,8 +69,6 @@
     JNIEnv* env,
     Profile* profile,
     const JavaParamRef<jstring>& card_label) {
-  // TODO(https://crbug.com/382803396): this should only update once per
-  // sessions.
   DCHECK(profile);
   segmentation_platform::home_modules::HomeModulesCardRegistry* registry =
       segmentation_platform::SegmentationPlatformServiceFactory::
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 293b2e9..7a234383 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -422,7 +422,6 @@
     "//chrome/browser/ui/tab_contents",
     "//chrome/browser/ui/tab_contents:impl",
     "//chrome/browser/ui/webui",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/bluetooth_internals",
     "//chrome/browser/ui/zoom",
     "//chrome/browser/updates/announcement_notification",
@@ -1741,6 +1740,7 @@
       "//chrome/browser/ui/user_education:impl",
       "//chrome/browser/ui/views/side_panel:side_panel_enums",
       "//chrome/browser/ui/views/toolbar",
+      "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/commerce",
       "//chrome/browser/ui/webui/commerce:impl",
       "//chrome/browser/ui/webui/cr_components/theme_color_picker",
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediator.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediator.java
index 4059a50..df3f6e3 100644
--- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediator.java
+++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediator.java
@@ -50,6 +50,9 @@
     // by viz instead of the browser.
     private int mRendererOffset;
 
+    private int mNavigationBarColor;
+    private int mDividerColor;
+
     /**
      * Tracks the latest value for layer visibility to watch for any changes to communicate to the
      * {@link BottomControlsStacker}.
@@ -191,6 +194,7 @@
     @Override
     public void onNavigationBarColorChanged(int color) {
         if (!isVisible()) {
+            mNavigationBarColor = color;
             return;
         }
 
@@ -201,6 +205,7 @@
     @Override
     public void onNavigationBarDividerChanged(int dividerColor) {
         if (!isVisible()) {
+            mDividerColor = dividerColor;
             return;
         }
 
@@ -257,6 +262,15 @@
 
         mRendererOffset = layerYOffset;
 
+        if (isVisible()) {
+            // If the chin isn't visible, cache the color and update it when the chin is visible.
+            // This is done to reduce the number of compositor frames submitted while scrolling.
+            // The color is unnecessarily set to null when the chin gets scrolled off screen, and
+            // gets set back to what it was before it was scrolled off.
+            onNavigationBarColorChanged(mNavigationBarColor);
+            onNavigationBarDividerChanged(mDividerColor);
+        }
+
         if (!mBottomControlsStacker.isMoveableByViz()) {
             mModel.set(Y_OFFSET, layerYOffset);
         }
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/junit/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediatorTest.java b/chrome/browser/ui/android/edge_to_edge/internal/junit/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediatorTest.java
index 97b0e614..ffc4a0f 100644
--- a/chrome/browser/ui/android/edge_to_edge/internal/junit/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediatorTest.java
+++ b/chrome/browser/ui/android/edge_to_edge/internal/junit/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeBottomChinMediatorTest.java
@@ -132,8 +132,13 @@
         // scroll view offscreen
         mMediator.onBrowserControlsOffsetUpdate(mModel.get(HEIGHT), false);
 
+        // color shouldn't be applied, but should be cached
         mMediator.onNavigationBarColorChanged(Color.WHITE);
         assertEquals("The color should have not been updated.", Color.RED, mModel.get(COLOR));
+
+        // scroll view back on screen, should apply cached color
+        mMediator.onBrowserControlsOffsetUpdate(0, false);
+        assertEquals("The cached color should be applied.", Color.WHITE, mModel.get(COLOR));
     }
 
     @Test
@@ -159,11 +164,16 @@
         // scroll view offscreen
         mMediator.onBrowserControlsOffsetUpdate(mModel.get(HEIGHT), false);
 
+        // color shouldn't be applied, but should be cached
         mMediator.onNavigationBarDividerChanged(Color.WHITE);
         assertEquals(
                 "The color should not have not been updated.",
                 Color.TRANSPARENT,
                 mModel.get(DIVIDER_COLOR));
+
+        // scroll view back on screen, should apply cached color
+        mMediator.onBrowserControlsOffsetUpdate(0, false);
+        assertEquals("The cached color should be applied.", Color.WHITE, mModel.get(DIVIDER_COLOR));
     }
 
     @Test
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_keyed_service_unittest.cc b/chrome/browser/ui/ash/glanceables/glanceables_keyed_service_unittest.cc
index 69d6054..10ec6ae 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/glanceables/glanceables_keyed_service_unittest.cc
@@ -25,7 +25,9 @@
 class GlanceablesKeyedServiceTest : public BrowserWithTestWindowTest {
  public:
   // BrowserWithTestWindowTest:
-  std::string GetDefaultProfileName() override { return kPrimaryProfileName; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kPrimaryProfileName;
+  }
 
   // BrowserWithTestWindowTest:
   TestingProfile* CreateProfile(const std::string& profile_name) override {
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
index e5bde22..05ac94d 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -770,7 +770,7 @@
     HoldingSpaceKeyedServiceWithExperimentalFeatureTest::TearDown();
   }
 
-  std::string GetDefaultProfileName() override {
+  std::optional<std::string> GetDefaultProfileName() override {
     return user_manager::kGuestUserName;
   }
 
diff --git a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc
index 203d112c..77f56825 100644
--- a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc
@@ -90,6 +90,7 @@
 #include "chrome/browser/ui/ash/shell_init/ash_shell_init.h"
 #include "chrome/browser/ui/ash/system/system_tray_client_impl.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
+#include "chrome/browser/ui/ash/wallpaper/wallpaper_ash.h"
 #include "chrome/browser/ui/ash/wallpaper/wallpaper_controller_client_impl.h"
 #include "chrome/browser/ui/ash/web_view/ash_web_view_factory_impl.h"
 #include "chrome/browser/ui/ash/wm/tab_cluster_ui_client.h"
@@ -180,7 +181,8 @@
   return g_instance;
 }
 
-ChromeBrowserMainExtraPartsAsh::ChromeBrowserMainExtraPartsAsh() {
+ChromeBrowserMainExtraPartsAsh::ChromeBrowserMainExtraPartsAsh()
+    : wallpaper_ash_(std::make_unique<WallpaperAsh>()) {
   CHECK(!g_instance);
   g_instance = this;
 }
diff --git a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.h
index 6c036be..30fc53bf 100644
--- a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.h
@@ -83,6 +83,7 @@
 class TabClusterUIClient;
 class TabletModePageBehavior;
 class VpnListForwarder;
+class WallpaperAsh;
 class WallpaperControllerClientImpl;
 
 namespace internal {
@@ -125,6 +126,7 @@
   class UserProfileLoadedObserver;
 
   std::unique_ptr<UserProfileLoadedObserver> user_profile_loaded_observer_;
+  std::unique_ptr<WallpaperAsh> wallpaper_ash_;
 
   // Initialized in PreProfileInit in all configs before Shell init:
   std::unique_ptr<NetworkConnectDelegate> network_connect_delegate_;
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index 9a34ad2..e03f6e2 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -1619,7 +1619,9 @@
   }
 
   // Override BrowserWithTestWindowTest:
-  std::string GetDefaultProfileName() override { return "user0@example.com"; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return "user0@example.com";
+  }
 
   void LogIn(const std::string& email) override {
     // TODO(crbug.com/40286020): Merge into BrowserWithTestWindowTest.
diff --git a/chrome/browser/ui/ash/wallpaper/BUILD.gn b/chrome/browser/ui/ash/wallpaper/BUILD.gn
index 6845c0b..1dd5ed8 100644
--- a/chrome/browser/ui/ash/wallpaper/BUILD.gn
+++ b/chrome/browser/ui/ash/wallpaper/BUILD.gn
@@ -8,11 +8,16 @@
 
 static_library("wallpaper") {
   sources = [
+    "wallpaper_ash.cc",
+    "wallpaper_ash.h",
     "wallpaper_controller_client_impl.cc",
     "wallpaper_controller_client_impl.h",
   ]
 
-  public_deps = [ "//chrome/browser:browser_public_dependencies" ]
+  public_deps = [
+    "//ash/public/mojom",
+    "//chrome/browser:browser_public_dependencies",
+  ]
 
   deps = [
     "//ash/constants",
@@ -33,6 +38,7 @@
     "//chrome/browser/ash/system_web_apps/apps/personalization_app",
     "//chrome/browser/ash/wallpaper",
     "//chrome/browser/ash/wallpaper_handlers",
+    "//chrome/browser/chromeos/extensions/wallpaper",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/sync",
     "//chrome/browser/ui/ash/login",
@@ -53,6 +59,7 @@
   ]
 
   allow_circular_includes_from = [
+    "//chrome/browser/chromeos/extensions/wallpaper",
     "//chrome/browser/ash/arc/wallpaper",
     "//chrome/browser/ash/login/lock",
     "//chrome/browser/ash/policy/external_data/handlers",
@@ -82,7 +89,10 @@
 source_set("unit_tests") {
   testonly = true
 
-  sources = [ "wallpaper_controller_client_impl_unittest.cc" ]
+  sources = [
+    "wallpaper_ash_unittest.cc",
+    "wallpaper_controller_client_impl_unittest.cc",
+  ]
 
   deps = [
     ":test_support",
@@ -93,6 +103,7 @@
     "//chrome/browser/ash/settings:test_support",
     "//chrome/browser/ash/wallpaper_handlers:test_support",
     "//chrome/test:test_support",
+    "//chromeos/ash/components/browser_context_helper",
     "//chromeos/ash/components/cryptohome",
     "//components/user_manager",
     "//components/value_store:test_support",
diff --git a/chrome/browser/ui/ash/wallpaper/DEPS b/chrome/browser/ui/ash/wallpaper/DEPS
index 81669e5..8b311804 100644
--- a/chrome/browser/ui/ash/wallpaper/DEPS
+++ b/chrome/browser/ui/ash/wallpaper/DEPS
@@ -15,6 +15,7 @@
   "+chrome/browser/ash/drive",
   "+chrome/browser/ash/file_manager",
   "+chrome/browser/ash/login",
+  "+chrome/browser/ash/profiles/profile_helper.h",
   "+chrome/browser/ash/settings",
   "+chrome/browser/ash/wallpaper_handlers",
   "+chrome/browser/ash/wallpaper",
diff --git a/chrome/browser/ash/crosapi/wallpaper_ash.cc b/chrome/browser/ui/ash/wallpaper/wallpaper_ash.cc
similarity index 86%
rename from chrome/browser/ash/crosapi/wallpaper_ash.cc
rename to chrome/browser/ui/ash/wallpaper/wallpaper_ash.cc
index cd78126f..0cceae1 100644
--- a/chrome/browser/ash/crosapi/wallpaper_ash.cc
+++ b/chrome/browser/ui/ash/wallpaper/wallpaper_ash.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/crosapi/wallpaper_ash.h"
+#include "chrome/browser/ui/ash/wallpaper/wallpaper_ash.h"
 
 #include <string>
 #include <vector>
 
+#include "ash/public/mojom/wallpaper.mojom.h"
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
@@ -15,7 +16,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/wallpaper/wallpaper_controller_client_impl.h"
 #include "chromeos/ash/components/login/login_state/login_state.h"
-#include "chromeos/crosapi/mojom/wallpaper.mojom.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user.h"
 #include "content/public/browser/browser_thread.h"
@@ -28,13 +28,16 @@
 using content::BrowserThread;
 
 namespace {
-ash::WallpaperLayout GetLayoutEnum(crosapi::mojom::WallpaperLayout layout) {
+
+WallpaperAsh* g_instance = nullptr;
+
+ash::WallpaperLayout GetLayoutEnum(ash::mojom::WallpaperLayout layout) {
   switch (layout) {
-    case crosapi::mojom::WallpaperLayout::kStretch:
+    case ash::mojom::WallpaperLayout::kStretch:
       return ash::WALLPAPER_LAYOUT_STRETCH;
-    case crosapi::mojom::WallpaperLayout::kCenter:
+    case ash::mojom::WallpaperLayout::kCenter:
       return ash::WALLPAPER_LAYOUT_CENTER;
-    case crosapi::mojom::WallpaperLayout::kCenterCropped:
+    case ash::mojom::WallpaperLayout::kCenterCropped:
       return ash::WALLPAPER_LAYOUT_CENTER_CROPPED;
     default:
       return ash::WALLPAPER_LAYOUT_CENTER;
@@ -81,17 +84,26 @@
 
 }  // namespace
 
-namespace crosapi {
+// static
+WallpaperAsh* WallpaperAsh::Get() {
+  return g_instance;
+}
 
-WallpaperAsh::WallpaperAsh() = default;
+WallpaperAsh::WallpaperAsh() {
+  CHECK(!g_instance);
+  g_instance = this;
+}
 
-WallpaperAsh::~WallpaperAsh() = default;
+WallpaperAsh::~WallpaperAsh() {
+  CHECK_EQ(g_instance, this);
+  g_instance = nullptr;
+}
 
 void WallpaperAsh::SetWallpaper(
-    mojom::WallpaperSettingsPtr wallpaper_settings,
+    ash::mojom::WallpaperSettingsPtr wallpaper_settings,
     const std::string& extension_id,
     const std::string& extension_name,
-    base::OnceCallback<void(mojom::SetWallpaperResultPtr)> callback) {
+    base::OnceCallback<void(ash::mojom::SetWallpaperResultPtr)> callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   CHECK(ash::LoginState::Get()->IsUserLoggedIn());
   // Prevent any in progress decodes from changing wallpaper.
@@ -116,7 +128,7 @@
 }
 
 void WallpaperAsh::OnWallpaperDecoded(
-    mojom::WallpaperSettingsPtr wallpaper_settings,
+    ash::mojom::WallpaperSettingsPtr wallpaper_settings,
     const SkBitmap& bitmap) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (bitmap.isNull()) {
@@ -165,7 +177,7 @@
 
 void WallpaperAsh::SendErrorResult(const std::string& response) {
   std::move(pending_callback_)
-      .Run(crosapi::mojom::SetWallpaperResult::NewErrorMessage(response));
+      .Run(ash::mojom::SetWallpaperResult::NewErrorMessage(response));
   extensions::extension_function_crash_keys::EndExtensionFunctionCall(
       extension_id_);
   extension_id_.clear();
@@ -174,11 +186,8 @@
 void WallpaperAsh::SendSuccessResult(
     const std::vector<uint8_t>& thumbnail_data) {
   std::move(pending_callback_)
-      .Run(
-          crosapi::mojom::SetWallpaperResult::NewThumbnailData(thumbnail_data));
+      .Run(ash::mojom::SetWallpaperResult::NewThumbnailData(thumbnail_data));
   extensions::extension_function_crash_keys::EndExtensionFunctionCall(
       extension_id_);
   extension_id_.clear();
 }
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/wallpaper_ash.h b/chrome/browser/ui/ash/wallpaper/wallpaper_ash.h
similarity index 63%
rename from chrome/browser/ash/crosapi/wallpaper_ash.h
rename to chrome/browser/ui/ash/wallpaper/wallpaper_ash.h
index 4dd2fd0c..6e4fa24e 100644
--- a/chrome/browser/ash/crosapi/wallpaper_ash.h
+++ b/chrome/browser/ui/ash/wallpaper/wallpaper_ash.h
@@ -2,48 +2,48 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ASH_CROSAPI_WALLPAPER_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_WALLPAPER_ASH_H_
+#ifndef CHROME_BROWSER_UI_ASH_WALLPAPER_WALLPAPER_ASH_H_
+#define CHROME_BROWSER_UI_ASH_WALLPAPER_WALLPAPER_ASH_H_
 
 #include <string>
 
+#include "ash/public/mojom/wallpaper.mojom.h"
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "chromeos/crosapi/mojom/wallpaper.mojom.h"
 #include "extensions/common/extension_id.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image_skia.h"
 
-namespace crosapi {
-
 // Ash implementation of the wallpaper extension API.
 class WallpaperAsh {
  public:
+  // Returns the single instance. Used to avoid circular dependencies with the
+  // owning object ChromeBrowserMainExtraPartsAsh.
+  static WallpaperAsh* Get();
+
   WallpaperAsh();
   WallpaperAsh(const WallpaperAsh&) = delete;
   WallpaperAsh& operator=(const WallpaperAsh&) = delete;
   ~WallpaperAsh();
 
   void SetWallpaper(
-      mojom::WallpaperSettingsPtr wallpaper_settings,
+      ash::mojom::WallpaperSettingsPtr wallpaper_settings,
       const std::string& extension_id,
       const std::string& extension_name,
-      base::OnceCallback<void(mojom::SetWallpaperResultPtr)> callback);
+      base::OnceCallback<void(ash::mojom::SetWallpaperResultPtr)> callback);
 
  private:
-  void OnWallpaperDecoded(mojom::WallpaperSettingsPtr wallpaper_settings,
+  void OnWallpaperDecoded(ash::mojom::WallpaperSettingsPtr wallpaper_settings,
                           const SkBitmap& bitmap);
   void SendErrorResult(const std::string& response);
   void SendSuccessResult(const std::vector<uint8_t>& thumbnail_data);
 
   // The ID of the extension making the current SetWallpaper() call.
   extensions::ExtensionId extension_id_;
-  base::OnceCallback<void(mojom::SetWallpaperResultPtr)> pending_callback_;
+  base::OnceCallback<void(ash::mojom::SetWallpaperResultPtr)> pending_callback_;
   data_decoder::DataDecoder data_decoder_;
   base::WeakPtrFactory<WallpaperAsh> weak_ptr_factory_{this};
 };
 
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_WALLPAPER_ASH_H_
+#endif  // CHROME_BROWSER_UI_ASH_WALLPAPER_WALLPAPER_ASH_H_
diff --git a/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc b/chrome/browser/ui/ash/wallpaper/wallpaper_ash_unittest.cc
similarity index 88%
rename from chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc
rename to chrome/browser/ui/ash/wallpaper/wallpaper_ash_unittest.cc
index ab30803..5b11fc3 100644
--- a/chrome/browser/ash/crosapi/wallpaper_ash_unittest.cc
+++ b/chrome/browser/ui/ash/wallpaper/wallpaper_ash_unittest.cc
@@ -2,27 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/crosapi/wallpaper_ash.h"
+#include "chrome/browser/ui/ash/wallpaper/wallpaper_ash.h"
 
 #include <memory>
 
+#include "ash/public/mojom/wallpaper.mojom.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/bind.h"
 #include "base/test/test_future.h"
-#include "chrome/browser/ash/crosapi/wallpaper_ash.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/wallpaper_handlers/test_wallpaper_fetcher_delegate.h"
 #include "chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.h"
+#include "chrome/browser/ui/ash/wallpaper/wallpaper_ash.h"
 #include "chrome/browser/ui/ash/wallpaper/wallpaper_controller_client_impl.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/ash/components/browser_context_helper/annotated_account_id.h"
 #include "chromeos/ash/components/login/login_state/login_state.h"
-#include "chromeos/crosapi/mojom/wallpaper.mojom-forward.h"
-#include "chromeos/crosapi/mojom/wallpaper.mojom.h"
 #include "components/crash/core/common/crash_key.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user_manager.h"
@@ -33,8 +32,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 
-namespace crosapi {
-
 std::vector<uint8_t> CreateJpeg(int width = 100, int height = 100) {
   const SkColor kRed = SkColorSetRGB(255, 0, 0);
   constexpr int kQuality = 80;
@@ -53,7 +50,7 @@
   return jpg_data.value();
 }
 
-using crosapi::mojom::SetWallpaperResultPtr;
+using ash::mojom::SetWallpaperResultPtr;
 
 class WallpaperAshTest : public testing::Test {
  public:
@@ -90,7 +87,7 @@
   }
 
   SetWallpaperResultPtr SetWallpaper(
-      mojom::WallpaperSettingsPtr wallpaper_settings,
+      ash::mojom::WallpaperSettingsPtr wallpaper_settings,
       const std::string& extension_id,
       const std::string& extension_name) {
     base::test::TestFuture<SetWallpaperResultPtr> future;
@@ -113,8 +110,8 @@
 };
 
 TEST_F(WallpaperAshTest, SetWallpaper) {
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   settings->data = CreateJpeg();
   test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId());
 
@@ -128,8 +125,8 @@
 }
 
 TEST_F(WallpaperAshTest, SetWallpaper1x1) {
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   settings->data = CreateJpeg(1, 1);
   test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId());
 
@@ -143,8 +140,8 @@
 }
 
 TEST_F(WallpaperAshTest, SetWallpaper_InvalidWallpaper) {
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId());
   // Created invalid data by not adding a wallpaper image to the settings data.
 
@@ -158,8 +155,8 @@
 }
 
 TEST_F(WallpaperAshTest, SetWallpaper_InvalidUser) {
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   settings->data = CreateJpeg();
   // Setting the wallpaper fails because we haven't set the current user.
 
@@ -177,8 +174,8 @@
   test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId());
 
   // Create valid settings.
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
   settings->data = CreateJpeg();
 
   // Invoke SetWallpaper(). It will respond with success.
@@ -200,8 +197,8 @@
   test_wallpaper_controller_.SetCurrentUser(user_manager::StubAccountId());
 
   // Create invalid data by not adding a wallpaper image to the settings data.
-  crosapi::mojom::WallpaperSettingsPtr settings =
-      crosapi::mojom::WallpaperSettings::New();
+  ash::mojom::WallpaperSettingsPtr settings =
+      ash::mojom::WallpaperSettings::New();
 
   // Invoke SetWallpaper(). It will respond with an error.
   base::test::TestFuture<SetWallpaperResultPtr> future;
@@ -217,5 +214,3 @@
   ASSERT_TRUE(result->is_error_message());
   EXPECT_EQ(GetCrashKeyValue("extension-function-caller-1"), "");
 }
-
-}  // namespace crosapi
diff --git a/chrome/browser/ui/browser_finder_chromeos_unittest.cc b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
index bc31a8c..3198b96 100644
--- a/chrome/browser/ui/browser_finder_chromeos_unittest.cc
+++ b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
@@ -57,7 +57,9 @@
   }
 
   // BrowserWithTestWindow:
-  std::string GetDefaultProfileName() override { return kTestAccount1; }
+  std::optional<std::string> GetDefaultProfileName() override {
+    return kTestAccount1;
+  }
 
   TestingProfile* CreateProfile(const std::string& profile_name) override {
     auto* profile = BrowserWithTestWindowTest::CreateProfile(profile_name);
diff --git a/chrome/browser/ui/media_router/media_router_ui.cc b/chrome/browser/ui/media_router/media_router_ui.cc
index 2d17d915..af57fed4 100644
--- a/chrome/browser/ui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/media_router/media_router_ui.cc
@@ -417,12 +417,18 @@
 }
 
 void MediaRouterUI::UpdateSinks() {
-  if (base::FeatureList::IsEnabled(kShowCastPermissionRejectedError) &&
-      issue_.has_value() && issue_->is_permission_rejected_issue()) {
-    // Clean up the discovered sinks if the permission is rejected.
-    model_.set_media_sinks({});
-    model_.set_is_permission_rejected(true);
-  } else {
+  bool permission_rejected =
+      base::FeatureList::IsEnabled(kShowCastPermissionRejectedError) &&
+      issue_.has_value() && issue_->is_permission_rejected_issue();
+  // Speculative fix for crbug.com/374131711. Clear `issue_` when new sinks are
+  // discovered.
+  if (permission_rejected && !GetEnabledSinks().empty()) {
+    auto id = issue_->id();
+    issue_.reset();
+    ClearIssue(id);
+    permission_rejected = false;
+  }
+
     std::vector<UIMediaSink> media_sinks;
     for (const MediaSinkWithCastModes& sink : GetEnabledSinks()) {
       auto route_it = base::ranges::find(routes(), sink.sink.id(),
@@ -432,10 +438,11 @@
       media_sinks.push_back(ConvertToUISink(sink, route, issue_));
     }
     model_.set_media_sinks(std::move(media_sinks));
-  }
+    model_.set_is_permission_rejected(permission_rejected);
 
-  for (CastDialogController::Observer& observer : observers_)
-    observer.OnModelUpdated(model_);
+    for (CastDialogController::Observer& observer : observers_) {
+      observer.OnModelUpdated(model_);
+    }
 }
 
 void MediaRouterUI::SendIssueForRouteTimeout(
diff --git a/chrome/browser/ui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/media_router/media_router_ui_unittest.cc
index 170ac8f..57448d4b 100644
--- a/chrome/browser/ui/media_router/media_router_ui_unittest.cc
+++ b/chrome/browser/ui/media_router/media_router_ui_unittest.cc
@@ -577,6 +577,35 @@
   mock_router_->GetIssueManager()->AddPermissionRejectedIssue();
 }
 
+TEST_F(MediaRouterViewsUITest, SinksUpdatedAfterPermissionRejectedIssue) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      media_router::kShowCastPermissionRejectedError);
+
+  MockControllerObserver observer(ui_.get());
+  // Receives a permission rejected issue.
+  EXPECT_CALL(observer, OnModelUpdated(_))
+      .WillOnce(WithArg<0>(Invoke([](const CastDialogModel& model) {
+        EXPECT_TRUE(model.is_permission_rejected());
+        EXPECT_TRUE(model.media_sinks().empty());
+      })));
+
+  mock_router_->GetIssueManager()->AddPermissionRejectedIssue();
+  Mock::VerifyAndClearExpectations(&observer);
+
+  // After getting sink updates, MediaRouterUI clears the issue and sends sink
+  // updates.
+  EXPECT_CALL(observer, OnModelUpdated(_))
+      .Times(2)
+      .WillRepeatedly(WithArg<0>(Invoke([](const CastDialogModel& model) {
+        EXPECT_FALSE(model.is_permission_rejected());
+        EXPECT_EQ(2u, model.media_sinks().size());
+      })));
+
+  NotifyUiOnSinksUpdated({{CreateCastSink("sink1", "B sink"), {}},
+                          {CreateCastSink("sink2", "A sink"), {}}});
+}
+
 TEST_F(MediaRouterViewsUITest, SortedSinks) {
   NotifyUiOnSinksUpdated({{CreateCastSink("sink3", "B sink"), {}},
                           {CreateCastSink("sink2", "A sink"), {}},
diff --git a/chrome/browser/ui/messages/android/BUILD.gn b/chrome/browser/ui/messages/android/BUILD.gn
index 16d9a702..ccd18607d 100644
--- a/chrome/browser/ui/messages/android/BUILD.gn
+++ b/chrome/browser/ui/messages/android/BUILD.gn
@@ -6,7 +6,9 @@
 
 android_resources("java_resources") {
   sources = [
+    "java/res/drawable/snackbar_background.xml",
     "java/res/drawable/snackbar_background_tablet.xml",
+    "java/res/layout/floating_snackbar.xml",
     "java/res/layout/snackbar.xml",
     "java/res/values-night/dimens.xml",
     "java/res/values/dimens.xml",
@@ -89,6 +91,7 @@
     ":test_java_resources",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//chrome/browser/flags:java",
     "//chrome/browser/util:java",
     "//chrome/test/android:chrome_java_integration_test_support",
     "//content/public/android:content_java",
diff --git a/chrome/browser/ui/messages/android/java/res/drawable/snackbar_background.xml b/chrome/browser/ui/messages/android/java/res/drawable/snackbar_background.xml
new file mode 100644
index 0000000..ff00eaf
--- /dev/null
+++ b/chrome/browser/ui/messages/android/java/res/drawable/snackbar_background.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<org.chromium.components.browser_ui.widget.SurfaceColorDrawable
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:shape="rectangle"
+    app:surfaceElevation="@dimen/snackbar_surface_elevation">
+  <corners
+      android:radius="@dimen/snackbar_rounded_corner_radius"/>
+</org.chromium.components.browser_ui.widget.SurfaceColorDrawable>
diff --git a/chrome/browser/ui/messages/android/java/res/layout/floating_snackbar.xml b/chrome/browser/ui/messages/android/java/res/layout/floating_snackbar.xml
new file mode 100644
index 0000000..c4f31ae0
--- /dev/null
+++ b/chrome/browser/ui/messages/android/java/res/layout/floating_snackbar.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@id/snackbar"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom|start"
+    android:layout_marginTop="@dimen/snackbar_margin"
+    android:layout_marginBottom="@dimen/snackbar_margin"
+    android:layout_marginStart="@dimen/snackbar_margin"
+    android:layout_marginEnd="@dimen/snackbar_margin"
+    android:elevation="@dimen/snackbar_elevation"
+    android:minHeight="@dimen/snackbar_min_height"
+    android:orientation="horizontal" >
+
+  <ImageView android:id="@+id/snackbar_profile_image"
+      android:layout_width="@dimen/snackbar_profile_image_width"
+      android:layout_height="@dimen/snackbar_profile_image_height"
+      android:layout_gravity="center_vertical"
+      android:layout_marginStart="@dimen/snackbar_profile_image_margin_start"
+      android:layout_marginEnd="@dimen/snackbar_profile_image_margin_end"
+      android:scaleType="fitCenter"
+      android:visibility="visible"
+      tools:ignore="ContentDescription"/>
+
+  <org.chromium.components.browser_ui.widget.text.TemplatePreservingTextView
+      android:id="@+id/snackbar_message"
+      android:layout_width="0dp"
+      android:layout_height="wrap_content"
+      android:layout_gravity="start|center_vertical"
+      android:layout_marginStart="@dimen/snackbar_text_view_margin"
+      android:layout_marginTop="@dimen/snackbar_message_margin"
+      android:layout_marginBottom="@dimen/snackbar_message_margin"
+      android:layout_weight="1"
+      android:textAlignment="viewStart"
+      android:textAppearance="@style/TextAppearance.TextMedium.Primary.Baseline.Light" />
+
+  <org.chromium.ui.widget.ButtonCompat
+      android:id="@+id/snackbar_button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center_vertical"
+      android:paddingEnd="@dimen/snackbar_button_padding"
+      android:paddingStart="@dimen/snackbar_button_padding"
+      style="@style/TextButton" />
+</LinearLayout>
+
diff --git a/chrome/browser/ui/messages/android/java/res/layout/snackbar.xml b/chrome/browser/ui/messages/android/java/res/layout/snackbar.xml
index 54e3cfbd..034f8ebb 100644
--- a/chrome/browser/ui/messages/android/java/res/layout/snackbar.xml
+++ b/chrome/browser/ui/messages/android/java/res/layout/snackbar.xml
@@ -53,11 +53,11 @@
         android:orientation="horizontal" >
 
         <ImageView android:id="@+id/snackbar_profile_image"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="@dimen/snackbar_profile_image_width"
+            android:layout_height="@dimen/snackbar_profile_image_height"
             android:layout_gravity="center_vertical"
-            android:layout_marginStart="12dp"
-            android:layout_marginEnd="-12dp"
+            android:layout_marginStart="@dimen/snackbar_profile_image_margin_start"
+            android:layout_marginEnd="@dimen/snackbar_profile_image_margin_end"
             android:scaleType="fitCenter"
             android:visibility="visible"
             tools:ignore="ContentDescription"/>
@@ -68,8 +68,8 @@
             android:layout_height="wrap_content"
             android:layout_gravity="start|center_vertical"
             android:layout_marginStart="@dimen/snackbar_text_view_margin"
-            android:layout_marginTop="14dp"
-            android:layout_marginBottom="14dp"
+            android:layout_marginTop="@dimen/snackbar_message_margin"
+            android:layout_marginBottom="@dimen/snackbar_message_margin"
             android:layout_weight="1"
             android:textAlignment="viewStart"
             android:textAppearance="@style/TextAppearance.TextMedium.Primary.Baseline.Light" />
@@ -79,8 +79,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
-            android:paddingEnd="24dp"
-            android:paddingStart="24dp"
+            android:paddingEnd="@dimen/snackbar_button_padding"
+            android:paddingStart="@dimen/snackbar_button_padding"
             style="@style/TextButton" />
     </LinearLayout>
 </RelativeLayout>
diff --git a/chrome/browser/ui/messages/android/java/res/values-night/dimens.xml b/chrome/browser/ui/messages/android/java/res/values-night/dimens.xml
index a6ef7b8..a63a7152 100644
--- a/chrome/browser/ui/messages/android/java/res/values-night/dimens.xml
+++ b/chrome/browser/ui/messages/android/java/res/values-night/dimens.xml
@@ -8,4 +8,5 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
   <!-- Snackbars -->
   <dimen name="snackbar_background_tablet_elev">@dimen/default_elevation_4</dimen>
+  <dimen name="snackbar_surface_elevation">@dimen/default_elevation_5</dimen>
 </resources>
diff --git a/chrome/browser/ui/messages/android/java/res/values/dimens.xml b/chrome/browser/ui/messages/android/java/res/values/dimens.xml
index 3161951..b5cea99 100644
--- a/chrome/browser/ui/messages/android/java/res/values/dimens.xml
+++ b/chrome/browser/ui/messages/android/java/res/values/dimens.xml
@@ -10,7 +10,17 @@
     <dimen name="snackbar_min_height">48dp</dimen>
     <dimen name="snackbar_width_tablet">450dp</dimen>
     <dimen name="snackbar_margin_tablet">24dp</dimen>
+    <dimen name="snackbar_margin">8dp</dimen>
+    <dimen name="snackbar_rounded_corner_radius">16dp</dimen>
+    <dimen name="snackbar_elevation">2dp</dimen>
+    <dimen name="snackbar_surface_elevation">@dimen/default_elevation_0</dimen>
     <dimen name="snackbar_shadow_height">8dp</dimen>
     <dimen name="snackbar_text_view_margin">24dp</dimen>
     <dimen name="snackbar_background_tablet_elev">@dimen/default_elevation_0</dimen>
+    <dimen name="snackbar_profile_image_width">24dp</dimen>
+    <dimen name="snackbar_profile_image_height">24dp</dimen>
+    <dimen name="snackbar_profile_image_margin_start">12dp</dimen>
+    <dimen name="snackbar_profile_image_margin_end">-12dp</dimen>
+    <dimen name="snackbar_message_margin">14dp</dimen>
+    <dimen name="snackbar_button_padding">24dp</dimen>
 </resources>
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarTest.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarTest.java
index 0fe98ae..4ae0854 100644
--- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarTest.java
+++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarTest.java
@@ -27,6 +27,8 @@
 import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarController;
 import org.chromium.chrome.browser.ui.messages.test.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -352,6 +354,30 @@
 
     @Test
     @SmallTest
+    @EnableFeatures(ChromeFeatureList.FLOATING_SNACKBAR)
+    public void testOverrideParent_BeforeShowing_FloatingSnackbar() {
+        final Snackbar snackbar =
+                Snackbar.make(
+                        "stack",
+                        mDismissController,
+                        Snackbar.TYPE_ACTION,
+                        Snackbar.UMA_TEST_SNACKBAR);
+        PostTask.runOrPostTask(
+                TaskTraits.UI_DEFAULT,
+                () -> {
+                    mManager.overrideParent(sAlternateParent1);
+                    mManager.showSnackbar(snackbar);
+                });
+        pollSnackbarCondition(
+                "Snackbar's parent should not have been overridden, but was.",
+                () ->
+                        mManager.isShowing()
+                                && mManager.getCurrentSnackbarViewForTesting().mParent
+                                        == sMainParent);
+    }
+
+    @Test
+    @SmallTest
     public void testOverrideParent_WhileShowing() {
         final Snackbar snackbar =
                 Snackbar.make(
@@ -375,6 +401,30 @@
 
     @Test
     @SmallTest
+    @EnableFeatures(ChromeFeatureList.FLOATING_SNACKBAR)
+    public void testOverrideParent_WhileShowing_FloatingSnackbar() {
+        final Snackbar snackbar =
+                Snackbar.make(
+                        "stack",
+                        mDismissController,
+                        Snackbar.TYPE_ACTION,
+                        Snackbar.UMA_TEST_SNACKBAR);
+        PostTask.runOrPostTask(
+                TaskTraits.UI_DEFAULT,
+                () -> {
+                    mManager.showSnackbar(snackbar);
+                    mManager.overrideParent(sAlternateParent1);
+                });
+        pollSnackbarCondition(
+                "Snackbar's parent should have been overridden, but wasn't.",
+                () ->
+                        mManager.isShowing()
+                                && mManager.getCurrentSnackbarViewForTesting().mParent
+                                        == sAlternateParent1);
+    }
+
+    @Test
+    @SmallTest
     public void testPushParentViewToOverrideStack_BeforeShowing() {
         final Snackbar snackbar =
                 Snackbar.make(
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java
index 65202f5..4e55a24e 100644
--- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java
+++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java
@@ -131,9 +131,15 @@
 
         mRootContentView = activity.findViewById(android.R.id.content);
         mParent = mOriginalParent;
+
+        int snackbarLayout =
+                SnackbarManager.isFloatingSnackbarEnabled()
+                        ? R.layout.floating_snackbar
+                        : R.layout.snackbar;
+
         mContainerView =
-                (ViewGroup)
-                        LayoutInflater.from(activity).inflate(R.layout.snackbar, mParent, false);
+                (ViewGroup) LayoutInflater.from(activity).inflate(snackbarLayout, mParent, false);
+
         mSnackbarView = mContainerView.findViewById(R.id.snackbar);
         mAnimationDuration =
                 mContainerView.getResources().getInteger(android.R.integer.config_mediumAnimTime);
@@ -143,11 +149,14 @@
         mActionButtonView.setOnClickListener(listener);
         mProfileImageView = (ImageView) mContainerView.findViewById(R.id.snackbar_profile_image);
         mEdgeToEdgeSupplier = edgeToEdgeSupplier;
-        mEdgeToEdgePadAdjuster =
-                edgeToEdgeSupplier != null
-                        ? EdgeToEdgeControllerFactory.createForView(mSnackbarView)
-                        : null;
-
+        if (SnackbarManager.isFloatingSnackbarEnabled()) {
+            mEdgeToEdgePadAdjuster = null;
+        } else {
+            mEdgeToEdgePadAdjuster =
+                    edgeToEdgeSupplier != null
+                            ? EdgeToEdgeControllerFactory.createForView(mSnackbarView)
+                            : null;
+        }
         updateInternal(snackbar, false);
     }
 
@@ -175,8 +184,12 @@
                         startAnimatorOnSurfaceView(animator);
                     }
                 });
-        if (mEdgeToEdgeSupplier != null) {
-            mEdgeToEdgeSupplier.registerAdjuster(mEdgeToEdgePadAdjuster);
+
+        if (!SnackbarManager.isFloatingSnackbarEnabled()) {
+            // We do not use mEdgeToEdgePadAdjuster if FloatingSnackbar is enabled.
+            if (mEdgeToEdgeSupplier != null) {
+                mEdgeToEdgeSupplier.registerAdjuster(mEdgeToEdgePadAdjuster);
+            }
         }
     }
 
@@ -354,13 +367,26 @@
         mActionButtonView.setTextAppearance(getButtonTextAppearance(snackbar));
 
         mBackgroundColor = calculateBackgroundColor(mContainerView, snackbar);
-        if (mIsTablet) {
+
+        if (SnackbarManager.isFloatingSnackbarEnabled()) {
+            // Round the corners for snackbars in both tablets and non-tablets.
+            mSnackbarView.setBackgroundResource(R.drawable.snackbar_background);
+
+            GradientDrawable backgroundDrawable =
+                    (GradientDrawable) mSnackbarView.getBackground().mutate();
+            backgroundDrawable.setColor(mBackgroundColor);
+        } else if (mIsTablet) {
+            // isFloatingSnackbarEnabled == false, mIsTablet == true
             // On tablet, snackbars have rounded corners.
             mSnackbarView.setBackgroundResource(R.drawable.snackbar_background_tablet);
             GradientDrawable backgroundDrawable =
                     (GradientDrawable) mSnackbarView.getBackground().mutate();
             backgroundDrawable.setColor(mBackgroundColor);
+
+            mContainerView.findViewById(R.id.snackbar_shadow_left).setVisibility(View.VISIBLE);
+            mContainerView.findViewById(R.id.snackbar_shadow_right).setVisibility(View.VISIBLE);
         } else {
+            // isFloatingSnackbarEnabled == false, mIsTablet == false
             mSnackbarView.setBackgroundColor(mBackgroundColor);
         }
 
@@ -392,12 +418,6 @@
         } else {
             mProfileImageView.setVisibility(View.GONE);
         }
-
-        if (mIsTablet) {
-            mContainerView.findViewById(R.id.snackbar_shadow_left).setVisibility(View.VISIBLE);
-            mContainerView.findViewById(R.id.snackbar_shadow_right).setVisibility(View.VISIBLE);
-        }
-
         return true;
     }
 
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn
index 972471eb..eee851c 100644
--- a/chrome/browser/ui/tabs/BUILD.gn
+++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -350,6 +350,7 @@
       "//components/sessions",
       "//components/sync_sessions",
       "//components/tab_groups",
+      "//ui/webui",
     ]
   }
 
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
index 6ae20dad..e8cc4ef 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
@@ -278,7 +278,7 @@
   // profile. On ChromeOS (i.e. Ash-Chrome), profile won't be delete by that
   // because even if all browsers are closed Profile is expected to be kept
   // for system. Explicitly delete it here.
-  DeleteProfile(GetDefaultProfileName());
+  DeleteProfile(*GetDefaultProfileName());
   base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(widget_);
diff --git a/chrome/browser/ui/views/bubble/BUILD.gn b/chrome/browser/ui/views/bubble/BUILD.gn
index 50628fd0..944cb77 100644
--- a/chrome/browser/ui/views/bubble/BUILD.gn
+++ b/chrome/browser/ui/views/bubble/BUILD.gn
@@ -19,6 +19,7 @@
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/browser_window:browser_window",
+    "//chrome/browser/ui/webui:webui_util",
     "//content/public/browser",
     "//skia",
     "//ui/base",
@@ -33,9 +34,9 @@
   ]
   deps = [
     "//chrome/browser/ui:browser_list",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/top_chrome",
     "//components/input",
+    "//ui/webui",
   ]
 
   if (use_aura) {
diff --git a/chrome/browser/ui/views/controls/rich_hover_button.cc b/chrome/browser/ui/views/controls/rich_hover_button.cc
index 02064d90..3253ea1 100644
--- a/chrome/browser/ui/views/controls/rich_hover_button.cc
+++ b/chrome/browser/ui/views/controls/rich_hover_button.cc
@@ -24,7 +24,8 @@
 
 namespace {
 
-std::unique_ptr<views::View> CreateIconView(const ui::ImageModel& icon_image) {
+std::unique_ptr<views::ImageView> CreateIconView(
+    const ui::ImageModel& icon_image) {
   auto icon = std::make_unique<NonAccessibleImageView>();
   icon->SetImage(icon_image);
   // Make sure hovering over the icon also hovers the `RichHoverButton`.
@@ -73,57 +74,18 @@
     : HoverButton(std::move(callback), std::u16string()) {
   label()->SetHandlesTooltips(false);
 
-  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
-  const int icon_label_spacing = layout_provider->GetDistanceMetric(
-      DISTANCE_RICH_HOVER_BUTTON_ICON_HORIZONTAL);
-  views::style::TextContext text_context =
-      views::style::CONTEXT_DIALOG_BODY_TEXT;
-
-  views::TableLayout* table_layout =
-      SetLayoutManager(std::make_unique<views::TableLayout>());
-  table_layout
-      // Column for |main_image_icon|.
-      ->AddColumn(views::LayoutAlignment::kCenter,
-                  views::LayoutAlignment::kCenter,
-                  views::TableLayout::kFixedSize,
-                  views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
-      .AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
-      // Column for title.
-      .AddColumn(views::LayoutAlignment::kStretch,
-                 views::LayoutAlignment::kCenter, 1.0f,
-                 views::TableLayout::ColumnSize::kUsePreferred, 0, 0);
-
-  if (state_icon.has_value()) {
-    has_state_icon_ = true;
-    table_layout
-        // Column for |state_icon|.
-        ->AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
-        .AddColumn(views::LayoutAlignment::kCenter,
-                   views::LayoutAlignment::kCenter,
-                   views::TableLayout::kFixedSize,
-                   views::TableLayout::ColumnSize::kFixed, 16, 0);
-  }
-  table_layout
-      // Column for |action_icon|.
-      ->AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
-      .AddColumn(views::LayoutAlignment::kCenter,
-                 views::LayoutAlignment::kCenter,
-                 views::TableLayout::kFixedSize,
-                 views::TableLayout::ColumnSize::kFixed, 16, 0)
-      .AddRows(1, views::TableLayout::kFixedSize,
-               // Force row to have sufficient height for full line-height of
-               // the title.
-               views::TypographyProvider::Get().GetLineHeight(
-                   text_context, views::style::STYLE_PRIMARY));
-
   // TODO(pkasting): This class should subclass Button, not HoverButton.
   image_container_view()->SetProperty(views::kViewIgnoredByLayoutKey, true);
   label()->SetProperty(views::kViewIgnoredByLayoutKey, true);
   ink_drop_container()->SetProperty(views::kViewIgnoredByLayoutKey, true);
 
+  SetBorder(
+      views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
+          ChromeInsetsMetric::INSETS_PAGE_INFO_HOVER_BUTTON)));
+
   AddChildView(CreateIconView(main_image_icon));
   auto title_label = std::make_unique<views::Label>();
-  title_label->SetTextContext(text_context);
+  title_label->SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT);
 
   title_ = AddChildView(std::move(title_label));
   title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -132,7 +94,7 @@
 
   // State icon is optional and column is created only when it is set.
   if (state_icon.has_value()) {
-    AddChildView(CreateIconView(state_icon.value()));
+    state_icon_ = AddChildView(CreateIconView(state_icon.value()));
   }
 
   if (action_image_icon.has_value()) {
@@ -142,44 +104,46 @@
     AddChildView(std::make_unique<views::View>());
   }
 
-  if (!title_text.empty()) {
-    SetTitleText(title_text);
-  }
+  custom_view_row_start_ = children().size();
 
-  if (!subtitle_text.empty()) {
-    table_layout->AddRows(1, views::TableLayout::kFixedSize);
-    AddChildView(std::make_unique<views::View>());  // main icon column
-    auto subtitle = std::make_unique<views::Label>(
-        subtitle_text, views::style::CONTEXT_LABEL,
-        views::style::STYLE_SECONDARY);
-    subtitle_ = subtitle.get();
+  RecreateLayout();
 
-    AddChildView(std::make_unique<SubtitleLabelWrapper>(std::move(subtitle)));
-    subtitle_->SetTextStyle(views::style::STYLE_BODY_5);
-    subtitle_->SetEnabledColorId(ui::kColorLabelForegroundSecondary);
-    subtitle_->SetMultiLine(true);
-    subtitle_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    subtitle_->SetAutoColorReadabilityEnabled(false);
-    AddFillerViews();
-  }
-
-  SetBorder(views::CreateEmptyBorder(layout_provider->GetInsetsMetric(
-      ChromeInsetsMetric::INSETS_PAGE_INFO_HOVER_BUTTON)));
-
-  UpdateAccessibleName();
-
-  DeprecatedLayoutImmediately();
+  SetTitleText(title_text);
+  SetSubtitleText(subtitle_text);
 }
 
+RichHoverButton::~RichHoverButton() = default;
+
 void RichHoverButton::SetTitleText(const std::u16string& title_text) {
-  DCHECK(title_);
   title_->SetText(title_text);
   UpdateAccessibleName();
 }
 
 void RichHoverButton::SetSubtitleText(const std::u16string& subtitle_text) {
-  DCHECK(subtitle_);
-  subtitle_->SetText(subtitle_text);
+  if (subtitle_text.empty()) {
+    subtitle_ = nullptr;
+    for (const auto& v : subtitle_row_views_) {
+      RemoveChildViewT(v);
+    }
+    subtitle_row_views_.clear();
+  } else {
+    if (subtitle_row_views_.empty()) {
+      subtitle_row_views_.push_back(AddChildView(
+          std::make_unique<views::View>()));  // Skip main icon column.
+      auto subtitle = std::make_unique<views::Label>();
+      subtitle_ = subtitle.get();
+      subtitle_row_views_.push_back(AddChildView(
+          std::make_unique<SubtitleLabelWrapper>(std::move(subtitle))));
+      subtitle_->SetTextStyle(views::style::STYLE_BODY_5);
+      subtitle_->SetEnabledColorId(ui::kColorLabelForegroundSecondary);
+      subtitle_->SetMultiLine(true);
+      subtitle_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+      subtitle_->SetAutoColorReadabilityEnabled(false);
+      base::Extend(subtitle_row_views_, AddFillerViews(children().size()));
+    }
+    subtitle_->SetText(subtitle_text);
+  }
+  RecreateLayout();
   UpdateAccessibleName();
 }
 
@@ -209,6 +173,68 @@
   return subtitle_;
 }
 
+void RichHoverButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  return Button::OnBoundsChanged(previous_bounds);
+}
+
+views::View* RichHoverButton::GetTooltipHandlerForPoint(
+    const gfx::Point& point) {
+  return Button::GetTooltipHandlerForPoint(point);
+}
+
+gfx::Size RichHoverButton::CalculatePreferredSize(
+    const views::SizeBounds& available_size) const {
+  return Button::CalculatePreferredSize(available_size);
+}
+
+void RichHoverButton::RecreateLayout() {
+  const int icon_label_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_RICH_HOVER_BUTTON_ICON_HORIZONTAL);
+  views::TableLayout* table_layout =
+      SetLayoutManager(std::make_unique<views::TableLayout>());
+  table_layout
+      // Column for main image.
+      ->AddColumn(views::LayoutAlignment::kCenter,
+                  views::LayoutAlignment::kCenter,
+                  views::TableLayout::kFixedSize,
+                  views::TableLayout::ColumnSize::kUsePreferred, 0, 0)
+      .AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
+      // Column for title.
+      .AddColumn(views::LayoutAlignment::kStretch,
+                 views::LayoutAlignment::kCenter, 1.0f,
+                 views::TableLayout::ColumnSize::kUsePreferred, 0, 0);
+  if (state_icon_) {
+    table_layout
+        // Column for state icon.
+        ->AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
+        .AddColumn(views::LayoutAlignment::kCenter,
+                   views::LayoutAlignment::kCenter,
+                   views::TableLayout::kFixedSize,
+                   views::TableLayout::ColumnSize::kFixed, 16, 0);
+  }
+  table_layout
+      // Column for action icon.
+      ->AddPaddingColumn(views::TableLayout::kFixedSize, icon_label_spacing)
+      .AddColumn(views::LayoutAlignment::kCenter,
+                 views::LayoutAlignment::kCenter,
+                 views::TableLayout::kFixedSize,
+                 views::TableLayout::ColumnSize::kFixed, 16, 0)
+      .AddRows(1, views::TableLayout::kFixedSize,
+               // Force row to have sufficient height for full line-height of
+               // the title.
+               views::TypographyProvider::Get().GetLineHeight(
+                   views::style::CONTEXT_DIALOG_BODY_TEXT,
+                   views::style::STYLE_PRIMARY));
+  if (!custom_view_row_views_.empty()) {
+    // Row for custom view.
+    table_layout->AddRows(1, views::TableLayout::kFixedSize);
+  }
+  if (!subtitle_row_views_.empty()) {
+    // Row for subtitle.
+    table_layout->AddRows(1, views::TableLayout::kFixedSize);
+  }
+}
+
 void RichHoverButton::UpdateAccessibleName() {
   const std::u16string title_text = title_->GetText();
   const std::u16string accessible_name =
@@ -218,25 +244,14 @@
   HoverButton::GetViewAccessibility().SetName(accessible_name);
 }
 
-void RichHoverButton::AddFillerViews() {
-  if (has_state_icon_) {
-    AddChildView(std::make_unique<views::View>());
+std::vector<raw_ptr<views::View>> RichHoverButton::AddFillerViews(
+    size_t start) {
+  std::vector<raw_ptr<views::View>> vec;
+  if (state_icon_) {
+    vec.push_back(AddChildViewAt(std::make_unique<views::View>(), start++));
   }
-  AddChildView(std::make_unique<views::View>());
-}
-
-gfx::Size RichHoverButton::CalculatePreferredSize(
-    const views::SizeBounds& available_size) const {
-  return Button::CalculatePreferredSize(available_size);
-}
-
-void RichHoverButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  return Button::OnBoundsChanged(previous_bounds);
-}
-
-views::View* RichHoverButton::GetTooltipHandlerForPoint(
-    const gfx::Point& point) {
-  return Button::GetTooltipHandlerForPoint(point);
+  vec.push_back(AddChildViewAt(std::make_unique<views::View>(), start));
+  return vec;
 }
 
 BEGIN_METADATA(RichHoverButton)
diff --git a/chrome/browser/ui/views/controls/rich_hover_button.h b/chrome/browser/ui/views/controls/rich_hover_button.h
index 6d6c50f..cbfaa4e 100644
--- a/chrome/browser/ui/views/controls/rich_hover_button.h
+++ b/chrome/browser/ui/views/controls/rich_hover_button.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_
 
+#include <algorithm>
 #include <string>
+#include <vector>
 
+#include "base/containers/extend.h"
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/ui/views/controls/hover_button.h"
 #include "ui/views/layout/table_layout.h"
@@ -24,22 +27,23 @@
 class View;
 }  // namespace views
 
-// Hoverable button containing icon, styled title, and (multi-line) subtitle.
+// Hoverable button containing various components:
+// *--------------------------------------------------------*
+// | Icon | Title               | State image | Action icon |
+// |--------------------------------------------------------|
+// |      | Custom view         |             |             |
+// |--------------------------------------------------------|
+// |      | Subtitle            |             |             |
+// |      | (multiline)         |             |             |
+// *--------------------------------------------------------*
+//
 // 'RichHoverButton' inherits the interaction behavior from 'HoverButton'
 // but sets up its own layout and content.
+// TODO(pkasting): This class should subclass Button, not HoverButton.
 class RichHoverButton : public HoverButton {
   METADATA_HEADER(RichHoverButton, HoverButton)
 
  public:
-  // Creates a hoverable button that has an icon on the left side, followed by
-  // |title_text| label. Optional |action_image_icon| and |state_icon| are shown
-  // on right side. |subtile_text| is positioned directly under the
-  // |title_text|.
-  // *-------------------------------------------------------------------------*
-  // | Icon | |title_text|                         | State image | Action icon |
-  // |-------------------------------------------------------------------------|
-  // |      | |subtitle_text|                                                  |
-  // *-------------------------------------------------------------------------*
   RichHoverButton(
       views::Button::PressedCallback callback,
       const ui::ImageModel& main_image_icon,
@@ -51,7 +55,7 @@
   RichHoverButton(const RichHoverButton&) = delete;
   RichHoverButton& operator=(const RichHoverButton&) = delete;
 
-  ~RichHoverButton() override = default;
+  ~RichHoverButton() override;
 
   void SetTitleText(const std::u16string& title_text);
 
@@ -65,18 +69,32 @@
   void SetTitleTextStyleAndColor(int style, ui::ColorId);
   void SetSubtitleTextStyleAndColor(int style, ui::ColorId);
 
-  // Add custom view under the |title_text|.
-  // ...
-  // |-------------------------------------------------------------------------|
-  // |      | |custom_view|                                                    |
-  // *-------------------------------------------------------------------------*
+  // Sets the custom view. Pass an empty `std::unique_ptr<views::View>` to
+  // reset.
   template <typename T>
-  T* AddCustomSubtitle(std::unique_ptr<T> custom_view) {
-    static_cast<views::TableLayout*>(GetLayoutManager())
-        ->AddRows(1, views::TableLayout::kFixedSize);
-    AddChildView(std::make_unique<views::View>());  // main icon column
-    auto* view = AddChildView(std::move(custom_view));
-    AddFillerViews();
+  T* SetCustomView(std::unique_ptr<T> custom_view) {
+    T* view = nullptr;
+    if (!custom_view) {
+      for (const auto& v : custom_view_row_views_) {
+        RemoveChildViewT(v);
+      }
+      custom_view_row_views_.clear();
+    } else if (custom_view_row_views_.empty()) {
+      size_t start = custom_view_row_start_;
+      custom_view_row_views_.push_back(AddChildViewAt(
+          std::make_unique<views::View>(), start++));  // Skip main icon column.
+      view = AddChildViewAt(std::move(custom_view), start++);
+      custom_view_row_views_.push_back(view);
+      base::Extend(custom_view_row_views_, AddFillerViews(start));
+    } else {
+      CHECK_GT(custom_view_row_views_.size(), 1u);
+      const size_t index = *GetIndexOf(custom_view_row_views_[1]);
+      RemoveChildViewT(custom_view_row_views_[1]);
+      view = AddChildViewAt(std::move(custom_view), index);
+      custom_view_row_views_[1] = view;
+    }
+
+    RecreateLayout();
     return view;
   }
 
@@ -91,16 +109,27 @@
       const views::SizeBounds& available_size) const override;
 
  private:
+  // Recreates the table layout, which must be done any time the custom view
+  // changes between empty and non-empty (since its row is not filled with
+  // placeholder `View`s when absent).
+  // TODO(pkasting): This class should lay out using box, not table, with
+  // top-aligned children, and add enough padding to the
+  // icons/custom view/subtitle to properly align with the title. That would
+  // obviate the need to recreate the layout after construction.
+  void RecreateLayout();
+
   void UpdateAccessibleName();
 
   // Add filler views for state icon (if set) and action icon columns. Used for
   // the table rows after the first one.
-  void AddFillerViews();
+  std::vector<raw_ptr<views::View>> AddFillerViews(size_t start);
 
   raw_ptr<views::Label> title_ = nullptr;
+  raw_ptr<views::ImageView> state_icon_ = nullptr;
+  size_t custom_view_row_start_;
+  std::vector<raw_ptr<views::View>> custom_view_row_views_;
+  std::vector<raw_ptr<views::View>> subtitle_row_views_;
   raw_ptr<views::Label> subtitle_ = nullptr;
-
-  bool has_state_icon_ = false;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_
diff --git a/chrome/browser/ui/views/frame/browser_frame_view_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_frame_view_browsertest_win.cc
index fe702c50..a96380a2 100644
--- a/chrome/browser/ui/views/frame/browser_frame_view_browsertest_win.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_view_browsertest_win.cc
@@ -33,6 +33,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 #include "ui/base/pointer/touch_ui_controller.h"
 #include "ui/color/color_id.h"
@@ -205,6 +206,11 @@
     if (theme_color_) {
       web_app_info->theme_color = *theme_color_;
     }
+    if (!display_override_.empty()) {
+      web_app_info->user_display_mode =
+          web_app::mojom::UserDisplayMode::kStandalone;
+      web_app_info->display_override = display_override_;
+    }
 
     webapps::AppId app_id = web_app::test::InstallWebApp(
         browser()->profile(), std::move(web_app_info));
@@ -225,6 +231,7 @@
   }
 
   std::optional<SkColor> theme_color_ = SK_ColorBLUE;
+  std::vector<blink::mojom::DisplayMode> display_override_ = {};
   raw_ptr<Browser, AcrossTasksDanglingUntriaged> app_browser_ = nullptr;
   raw_ptr<BrowserView, AcrossTasksDanglingUntriaged> browser_view_ = nullptr;
   raw_ptr<BrowserFrameViewWin, AcrossTasksDanglingUntriaged> frame_view_ =
@@ -308,6 +315,31 @@
   ASSERT_EQ(true, frame_view_->window_icon_for_testing()->GetVisible());
 }
 
+class TabbedWebAppBrowserFrameViewWinTest
+    : public WebAppBrowserFrameViewWinTest {
+ public:
+  TabbedWebAppBrowserFrameViewWinTest() = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      blink::features::kDesktopPWAsTabStrip};
+};
+
+IN_PROC_BROWSER_TEST_F(TabbedWebAppBrowserFrameViewWinTest,
+                       TabbedWebAppIconInTitlebar) {
+  display_override_ = {blink::mojom::DisplayMode::kTabbed};
+  InstallAndLaunchWebApp();
+
+  ASSERT_FALSE(frame_view_->window_icon_for_testing()->GetVisible());
+}
+
+IN_PROC_BROWSER_TEST_F(TabbedWebAppBrowserFrameViewWinTest,
+                       NonTabbedWebAppIconInTitlebar) {
+  InstallAndLaunchWebApp();
+
+  ASSERT_TRUE(frame_view_->window_icon_for_testing()->GetVisible());
+}
+
 class WebAppBrowserFrameViewWinWindowControlsOverlayTest
     : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 543037b..5f57604 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -529,12 +529,17 @@
 END_METADATA
 
 bool ShouldShowWindowIcon(const Browser* browser,
-                          bool app_uses_window_controls_overlay) {
+                          bool app_uses_window_controls_overlay,
+                          bool app_uses_tabbed) {
 #if BUILDFLAG(IS_CHROMEOS)
   // For Chrome OS only, trusted windows (apps and settings) do not show a
   // window icon, crbug.com/119411. Child windows (i.e. popups) do show an icon.
   if (browser->is_trusted_source() || app_uses_window_controls_overlay)
     return false;
+#else
+  if (app_uses_tabbed) {
+    return false;
+  }
 #endif
   return browser->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
 }
@@ -909,8 +914,8 @@
       browser_(std::move(browser)),
       accessibility_mode_observer_(
           std::make_unique<AccessibilityModeObserver>(this)) {
-  SetShowIcon(
-      ::ShouldShowWindowIcon(browser_.get(), AppUsesWindowControlsOverlay()));
+  SetShowIcon(::ShouldShowWindowIcon(
+      browser_.get(), AppUsesWindowControlsOverlay(), AppUsesTabbed()));
 
   // In forced app mode, all size controls are always disabled. Otherwise, use
   // `create_params` to enable/disable specific size controls.
@@ -2352,6 +2357,11 @@
          browser()->app_controller()->AppUsesWindowControlsOverlay();
 }
 
+bool BrowserView::AppUsesTabbed() const {
+  return browser()->app_controller() &&
+         browser()->app_controller()->AppUsesTabbed();
+}
+
 bool BrowserView::IsWindowControlsOverlayEnabled() const {
   return window_controls_overlay_enabled_;
 }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 37ccc8d..46fb69a 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -413,6 +413,9 @@
   // window-controls-overlay.
   bool AppUsesWindowControlsOverlay() const;
 
+  // Returns true when an app's effective display mode is tabbed.
+  bool AppUsesTabbed() const;
+
   // Returns true when an app's effective display mode is borderless.
   bool AppUsesBorderlessMode() const;
 
diff --git a/chrome/browser/ui/views/glic/border/border_view.cc b/chrome/browser/ui/views/glic/border/border_view.cc
index e0c18890..74abf0de 100644
--- a/chrome/browser/ui/views/glic/border/border_view.cc
+++ b/chrome/browser/ui/views/glic/border/border_view.cc
@@ -17,7 +17,7 @@
 
 // static
 BorderView* BorderView::FindBorderForWebContents(
-    content::WebContents* web_contents) {
+    const content::WebContents* web_contents) {
   Browser* browser = chrome::FindBrowserWithTab(web_contents);
   if (!browser || !browser->window()) {
     // We might not have a browser or browser window in unittests.
@@ -29,22 +29,19 @@
 }
 
 // static.
-//
-// TODO(liuwilliam): Currently there is only one border animation per Profile,
-// and that's for the last active web contents, whose contents was requested by
-// glic. We might expand the animation scope to multiple WebContents. Update the
-// impl correspondingly.
 void BorderView::CancelAllAnimationsForProfile(Profile* profile) {
-  Browser* browser = chrome::FindBrowserWithProfile(profile);
-  if (!browser || !browser->window()) {
-    // Unittests, or the View tree is torn down.
-    return;
+  std::vector<Browser*> browsers = chrome::FindAllBrowsersWithProfile(profile);
+  for (auto* browser : browsers) {
+    if (!browser || !browser->window()) {
+      // Unittests, or the View tree is torn down.
+      continue;
+    }
+    CHECK(browser->GetBrowserView().contents_web_view());
+    browser->GetBrowserView()
+        .contents_web_view()
+        ->glic_border()
+        ->CancelAnimation();
   }
-  CHECK(browser->GetBrowserView().contents_web_view());
-  browser->GetBrowserView()
-      .contents_web_view()
-      ->glic_border()
-      ->CancelAnimation();
 }
 
 BorderView::BorderView() = default;
diff --git a/chrome/browser/ui/views/glic/border/border_view.h b/chrome/browser/ui/views/glic/border/border_view.h
index 239fa31..4482929 100644
--- a/chrome/browser/ui/views/glic/border/border_view.h
+++ b/chrome/browser/ui/views/glic/border/border_view.h
@@ -31,7 +31,7 @@
   // Helper function to find the `BorderView` for `web_contents`. Returns null
   // if there isn't a browser / browser view for `web_contents`.
   static BorderView* FindBorderForWebContents(
-      content::WebContents* web_contents);
+      const content::WebContents* web_contents);
 
   static void CancelAllAnimationsForProfile(Profile* profile);
 
diff --git a/chrome/browser/ui/views/glic/glic_view.cc b/chrome/browser/ui/views/glic/glic_view.cc
index 12c312e..53fbae92 100644
--- a/chrome/browser/ui/views/glic/glic_view.cc
+++ b/chrome/browser/ui/views/glic/glic_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/glic/glic_view.h"
 
 #include "base/command_line.h"
+#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -23,9 +24,13 @@
 namespace glic {
 
 GlicView::GlicView(Profile* profile, const gfx::Size& initial_size) {
+  profile_keep_alive_ = std::make_unique<ScopedProfileKeepAlive>(
+      profile, ProfileKeepAliveOrigin::kGlicView);
   auto web_view = std::make_unique<GlicWebView>(profile);
   web_view_ = web_view.get();
   web_view->SetSize(initial_size);
+  web_view->LoadInitialURL(GURL("chrome://glic"));
+  web_view->GetWebContents()->SetPageBaseBackgroundColor(SK_ColorTRANSPARENT);
   AddChildView(std::move(web_view));
 }
 
diff --git a/chrome/browser/ui/views/glic/glic_view.h b/chrome/browser/ui/views/glic/glic_view.h
index 88c38a048..34ecf4d3 100644
--- a/chrome/browser/ui/views/glic/glic_view.h
+++ b/chrome/browser/ui/views/glic/glic_view.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_GLIC_GLIC_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_GLIC_GLIC_VIEW_H_
 
+#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
 #include "chrome/browser/ui/views/glic/glic_web_view.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/view.h"
@@ -56,6 +57,10 @@
   // Animates programmatic changes to bounds (e.g. via `resizeTo()`
   // `resizeBy()` and `setContentsSize()` calls).
   std::unique_ptr<BrowserFrameBoundsChangeAnimation> bounds_change_animation_;
+
+  // Ensures that the profile associated with this view isn't destroyed while
+  // it is visible.
+  std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
 };
 
 }  // namespace glic
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
index 9a84680..061a291c 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -44,7 +44,7 @@
         keyword, &is_extension_keyword, &is_gemini_keyword);
     if (is_gemini_keyword) {
       names.full_name = l10n_util::GetStringFUTF16(
-          IDS_OMNIBOX_SELECTED_KEYWORD_CHAT_TEXT, names.short_name);
+          IDS_OMNIBOX_SELECTED_KEYWORD_ASK_TEXT, names.short_name);
     } else if (is_extension_keyword) {
       names.full_name = names.short_name;
     } else {
diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chrome/browser/ui/views/page_info/page_info_main_view.cc
index 41ed69f..1d6b8df 100644
--- a/chrome/browser/ui/views/page_info/page_info_main_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_main_view.cc
@@ -696,8 +696,8 @@
       views::style::STYLE_BODY_3_MEDIUM, kColorPageInfoForeground);
   merchant_trust_button->SetProperty(views::kElementIdentifierKey,
                                      kMerchantTrustElementId);
-  auto* star_rating_view = merchant_trust_button->AddCustomSubtitle(
-      std::make_unique<StarRatingView>());
+  auto* star_rating_view =
+      merchant_trust_button->SetCustomView(std::make_unique<StarRatingView>());
   star_rating_view->SetRating(value.star_rating);
   return merchant_trust_button;
 }
diff --git a/chrome/browser/ui/views/page_info/page_info_merchant_trust_content_view.cc b/chrome/browser/ui/views/page_info/page_info_merchant_trust_content_view.cc
index b74ff939..d350e12 100644
--- a/chrome/browser/ui/views/page_info/page_info_merchant_trust_content_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_merchant_trust_content_view.cc
@@ -139,8 +139,8 @@
       views::style::STYLE_BODY_3_MEDIUM, kColorPageInfoForeground);
   merchant_trust_button->SetProperty(views::kElementIdentifierKey,
                                      kViewReviewsId);
-  star_rating_view_ = merchant_trust_button->AddCustomSubtitle(
-      std::make_unique<StarRatingView>());
+  star_rating_view_ =
+      merchant_trust_button->SetCustomView(std::make_unique<StarRatingView>());
   return merchant_trust_button;
 }
 
diff --git a/chrome/browser/ui/views/side_panel/side_panel_entry_key.cc b/chrome/browser/ui/views/side_panel/side_panel_entry_key.cc
index 3837e9b..5b86d30 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_entry_key.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_entry_key.cc
@@ -38,13 +38,13 @@
   return false;
 }
 
-bool SidePanelEntryKey::operator<(const SidePanelEntryKey& other) const {
+auto SidePanelEntryKey::operator<=>(const SidePanelEntryKey& other) const {
   if (id_ == other.id_ && id_ == SidePanelEntryId::kExtension) {
     CHECK(extension_id_.has_value() && other.extension_id_.has_value());
     // TODO(corising): Updating extension sorting
-    return extension_id_.value() < other.extension_id_.value();
+    return extension_id_.value() <=> other.extension_id_.value();
   }
-  return id_ < other.id_;
+  return id_ <=> other.id_;
 }
 
 std::string SidePanelEntryKey::ToString() const {
diff --git a/chrome/browser/ui/views/side_panel/side_panel_entry_key.h b/chrome/browser/ui/views/side_panel/side_panel_entry_key.h
index 9438b9f..a1af0c54 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_entry_key.h
+++ b/chrome/browser/ui/views/side_panel/side_panel_entry_key.h
@@ -21,7 +21,7 @@
 
   SidePanelEntryKey& operator=(const SidePanelEntryKey& other);
   bool operator==(const SidePanelEntryKey& other) const;
-  bool operator<(const SidePanelEntryKey& other) const;
+  auto operator<=>(const SidePanelEntryKey& other) const;
 
   SidePanelEntryId id() const { return id_; }
   std::optional<extensions::ExtensionId> extension_id() const {
diff --git a/chrome/browser/ui/views/tabs/tab_glic_container.cc b/chrome/browser/ui/views/tabs/tab_glic_container.cc
index 7e5f89f..76228b2 100644
--- a/chrome/browser/ui/views/tabs/tab_glic_container.cc
+++ b/chrome/browser/ui/views/tabs/tab_glic_container.cc
@@ -30,6 +30,7 @@
 
 #if BUILDFLAG(ENABLE_GLIC)
 #include "chrome/browser/glic/glic_enabling.h"
+#include "chrome/browser/glic/glic_profile_manager.h"
 #include "chrome/browser/ui/views/tabs/glic_button.h"
 #endif  // BUILDFLAG(ENABLE_GLIC)
 namespace {
@@ -194,7 +195,9 @@
   }
 
 #if BUILDFLAG(ENABLE_GLIC)
-  if (GlicEnabling::IsEnabledByFlags()) {
+  if (GlicEnabling::IsEnabledByFlags() &&
+      glic::GlicProfileManager::IsProfileSupported(
+          tab_strip_controller->GetProfile())) {
     std::unique_ptr<glic::GlicButton> glic_button =
         std::make_unique<glic::GlicButton>(tab_strip_controller);
     glic_button->SetProperty(views::kCrossAxisAlignmentKey,
diff --git a/chrome/browser/ui/views/tabs/tab_glic_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_glic_container_unittest.cc
index 8efe2db..f7c23411 100644
--- a/chrome/browser/ui/views/tabs/tab_glic_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_glic_container_unittest.cc
@@ -21,12 +21,25 @@
 #include "ui/views/test/views_test_utils.h"
 #include "ui/views/widget/widget.h"
 
-class FakeBaseTabStripControllerWithProfile
-    : public FakeBaseTabStripController {
+class FakeGlicTabStripController : public FakeBaseTabStripController {
  public:
-  Profile* GetProfile() const override { return profile_.get(); }
+  Profile* GetProfile() const override {
+    if (use_otr_profile_) {
+      TestingProfile* otr_profile = TestingProfile::Builder().BuildOffTheRecord(
+          profile_.get(), Profile::OTRProfileID::CreateUniqueForTesting());
+
+      return otr_profile;
+    }
+
+    return profile_.get();
+  }
+
+  void ShouldUseOtrProfile(bool use_otr_profile) {
+    use_otr_profile_ = use_otr_profile;
+  }
 
  private:
+  bool use_otr_profile_ = false;
   std::unique_ptr<TestingProfile> profile_ = std::make_unique<TestingProfile>();
 };
 
@@ -43,17 +56,18 @@
     ChromeViewsTestBase::SetUp();
     scoped_feature_list_.InitWithFeatures(
         {features::kGlic, features::kTabstripComboButton}, {});
-
-    BuildGlicContainer();
   }
 
   void TearDown() override {
     ChromeViewsTestBase::TearDown();
     tab_glic_container_.reset();
   }
-  void BuildGlicContainer() {
-    tab_strip_ = std::make_unique<TabStrip>(
-        std::make_unique<FakeBaseTabStripControllerWithProfile>());
+
+  void BuildGlicContainer(bool use_otr_profile) {
+    controller_ = std::make_unique<FakeGlicTabStripController>();
+    controller_->ShouldUseOtrProfile(use_otr_profile);
+
+    tab_strip_ = std::make_unique<TabStrip>(std::move(controller_));
 
     tab_strip_model_ = std::make_unique<TabStripModel>(
         &tab_strip_model_delegate_, tab_strip_->controller()->GetProfile());
@@ -84,6 +98,7 @@
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<views::View> locked_expansion_view_;
   std::unique_ptr<TabGlicContainer> tab_glic_container_;
+  std::unique_ptr<FakeGlicTabStripController> controller_;
 
  private:
   // Owned by TabStrip.
@@ -92,12 +107,19 @@
 
 #if BUILDFLAG(ENABLE_GLIC)
 TEST_F(TabGlicContainerTest, GlicButtonDrawing) {
-  EXPECT_NE(tab_glic_container_->GetGlicButton(), nullptr);
+  BuildGlicContainer(/*use_otr_profile=*/false);
+  EXPECT_TRUE(tab_glic_container_->GetGlicButton());
+}
+
+TEST_F(TabGlicContainerTest, GlicButtonUnsupportedProfile) {
+  BuildGlicContainer(/*use_otr_profile=*/true);
+  EXPECT_FALSE(tab_glic_container_->GetGlicButton());
 }
 
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
 TEST_F(TabGlicContainerTest, OrdersButtonsCorrectly) {
+  BuildGlicContainer(/*use_otr_profile=*/false);
   ASSERT_EQ(tab_glic_container_->tab_declutter_button(),
             tab_glic_container_->children()[0]);
 
diff --git a/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h b/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h
index 7d61424..8227da3 100644
--- a/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h
+++ b/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h
@@ -24,8 +24,9 @@
   // `view`.
   static bool CanOrderView(views::View* view);
 
-  bool operator<(const ZOrderableTabContainerElement& rhs) const {
-    return z_value_ < rhs.z_value_;
+  friend auto operator<=>(const ZOrderableTabContainerElement& lhs,
+                          const ZOrderableTabContainerElement& rhs) {
+    return lhs.z_value_ <=> rhs.z_value_;
   }
 
   views::View* view() const { return child_; }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index c03a5d9..a8d957e 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -217,6 +217,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ToolbarView, public:
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToolbarView, kToolbarElementId);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToolbarView, kToolbarContainerElementId);
+
 ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view)
     : AnimationDelegateViews(this),
       browser_(browser),
@@ -224,8 +227,11 @@
       app_menu_icon_controller_(browser->profile(), this),
       display_mode_(GetDisplayMode(browser)) {
   SetID(VIEW_ID_TOOLBAR);
+  SetProperty(views::kElementIdentifierKey, kToolbarElementId);
 
   container_view_ = AddChildView(std::make_unique<ContainerView>());
+  container_view_->SetProperty(views::kElementIdentifierKey,
+                               kToolbarContainerElementId);
 
   GetViewAccessibility().SetRole(ax::mojom::Role::kToolbar);
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index cf442c3..3761d83 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -25,6 +25,7 @@
 #include "chrome/browser/ui/views/toolbar/overflow_button.h"
 #include "components/prefs/pref_member.h"
 #include "ui/base/accelerators/accelerator.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/pointer/touch_ui_controller.h"
 #include "ui/views/accessible_pane_view.h"
@@ -92,6 +93,9 @@
                 // needs to be displayed.
   };
 
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kToolbarElementId);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kToolbarContainerElementId);
+
   ToolbarView(Browser* browser, BrowserView* browser_view);
   ToolbarView(const ToolbarView&) = delete;
   ToolbarView& operator=(const ToolbarView&) = delete;
diff --git a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.cc b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.cc
index 8e98eb8..b9b91785 100644
--- a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.cc
+++ b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.cc
@@ -4,9 +4,15 @@
 
 #include "chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h"
 
+#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
+#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h"
+#include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service.h"
+#include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service_factory.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_controller.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #include "components/omnibox/browser/omnibox_view.h"
@@ -22,6 +28,12 @@
 
 DEFINE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(kWindowActivePrecondition);
 DEFINE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(kOmniboxNotOpenPrecondition);
+DEFINE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kToolbarNotCollapsedPrecondition);
+DEFINE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kBrowserNotClosingPrecondition);
+DEFINE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kNoCriticalNoticeShowingPrecondition);
 
 WindowActivePrecondition::WindowActivePrecondition()
     : FeaturePromoPreconditionBase(kWindowActivePrecondition,
@@ -63,3 +75,71 @@
              ? user_education::FeaturePromoResult::kBlockedByUi
              : user_education::FeaturePromoResult::Success();
 }
+
+ToolbarNotCollapsedPrecondition::ToolbarNotCollapsedPrecondition(
+    BrowserView& browser_view)
+    : FeaturePromoPreconditionBase(kToolbarNotCollapsedPrecondition,
+                                   "Toolbar is not collapsed"),
+      browser_view_(browser_view) {}
+ToolbarNotCollapsedPrecondition::~ToolbarNotCollapsedPrecondition() = default;
+
+user_education::FeaturePromoResult
+ToolbarNotCollapsedPrecondition::CheckPrecondition(ComputedData&) const {
+  if (const auto* const controller =
+          browser_view_->toolbar()->toolbar_controller()) {
+    if (controller->InOverflowMode()) {
+      return user_education::FeaturePromoResult::kBlockedByUi;
+    }
+  }
+  return user_education::FeaturePromoResult::Success();
+}
+
+BrowserNotClosingPrecondition::BrowserNotClosingPrecondition(
+    BrowserView& browser_view)
+    : FeaturePromoPreconditionBase(kBrowserNotClosingPrecondition,
+                                   "Browser is not closing"),
+      browser_view_(browser_view) {}
+BrowserNotClosingPrecondition::~BrowserNotClosingPrecondition() = default;
+
+user_education::FeaturePromoResult
+BrowserNotClosingPrecondition::CheckPrecondition(ComputedData&) const {
+  if (browser_view_->browser()->IsBrowserClosing() ||
+      browser_view_->GetWidget()->IsClosed()) {
+    return user_education::FeaturePromoResult::kBlockedByUi;
+  }
+  return user_education::FeaturePromoResult::Success();
+}
+
+NoCriticalNoticeShowingPrecondition::NoCriticalNoticeShowingPrecondition(
+    BrowserView& browser_view)
+    : FeaturePromoPreconditionBase(kNoCriticalNoticeShowingPrecondition,
+                                   "No critical notice is showing"),
+      browser_view_(browser_view) {}
+NoCriticalNoticeShowingPrecondition::~NoCriticalNoticeShowingPrecondition() =
+    default;
+
+user_education::FeaturePromoResult
+NoCriticalNoticeShowingPrecondition::CheckPrecondition(ComputedData&) const {
+  // Turn off IPH while a required privacy interstitial is visible or pending.
+  auto* const privacy_sandbox_service =
+      PrivacySandboxServiceFactory::GetForProfile(browser_view_->GetProfile());
+  if (privacy_sandbox_service &&
+      privacy_sandbox_service->GetRequiredPromptType(
+          PrivacySandboxService::SurfaceType::kDesktop) !=
+          PrivacySandboxService::PromptType::kNone) {
+    return user_education::FeaturePromoResult::kBlockedByUi;
+  }
+
+  // Turn off IPH while a required search engine choice dialog is visible or
+  // pending.
+  SearchEngineChoiceDialogService* const search_engine_choice_dialog_service =
+      SearchEngineChoiceDialogServiceFactory::GetForProfile(
+          browser_view_->GetProfile());
+  if (search_engine_choice_dialog_service &&
+      search_engine_choice_dialog_service->HasPendingDialog(
+          *browser_view_->browser())) {
+    return user_education::FeaturePromoResult::kBlockedByUi;
+  }
+
+  return user_education::FeaturePromoResult::Success();
+}
diff --git a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h
index e9871c9..74c36b9 100644
--- a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h
+++ b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h
@@ -13,6 +13,12 @@
 DECLARE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(kWindowActivePrecondition);
 DECLARE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
     kOmniboxNotOpenPrecondition);
+DECLARE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kToolbarNotCollapsedPrecondition);
+DECLARE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kBrowserNotClosingPrecondition);
+DECLARE_FEATURE_PROMO_PRECONDITION_IDENTIFIER_VALUE(
+    kNoCriticalNoticeShowingPrecondition);
 
 // Requires that the window a promo will be shown in is active.
 class WindowActivePrecondition
@@ -41,4 +47,53 @@
   const raw_ref<const BrowserView> browser_view_;
 };
 
+class ToolbarNotCollapsedPrecondition
+    : public user_education::FeaturePromoPreconditionBase {
+ public:
+  explicit ToolbarNotCollapsedPrecondition(BrowserView& browser_view);
+  ~ToolbarNotCollapsedPrecondition() override;
+
+  // FeaturePromoPreconditionBase:
+  user_education::FeaturePromoResult CheckPrecondition(
+      ComputedData& data) const override;
+
+ private:
+  const raw_ref<BrowserView> browser_view_;
+};
+
+// Trying to show an IPH while the browser is closing can cause problems; see
+// https://crbug.com/346461762 for an example. This can also crash unit_tests
+// that use a BrowserWindow but not a browser, so also check if the browser
+// view's widget is closing.
+class BrowserNotClosingPrecondition
+    : public user_education::FeaturePromoPreconditionBase {
+ public:
+  explicit BrowserNotClosingPrecondition(BrowserView& browser_view);
+  ~BrowserNotClosingPrecondition() override;
+
+  // FeaturePromoPreconditionBase:
+  user_education::FeaturePromoResult CheckPrecondition(
+      ComputedData& data) const override;
+
+ private:
+  const raw_ref<BrowserView> browser_view_;
+};
+
+// Certain critical notices do not (yet) use the Product Messaging Service.
+// TODO(https://crbug.com/324785292): When the migration is done, remove this
+// precondition.
+class NoCriticalNoticeShowingPrecondition
+    : public user_education::FeaturePromoPreconditionBase {
+ public:
+  explicit NoCriticalNoticeShowingPrecondition(BrowserView& browser_view);
+  ~NoCriticalNoticeShowingPrecondition() override;
+
+  // FeaturePromoPreconditionBase:
+  user_education::FeaturePromoResult CheckPrecondition(
+      ComputedData& data) const override;
+
+ private:
+  const raw_ref<BrowserView> browser_view_;
+};
+
 #endif  // CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_IMPL_BROWSER_FEATURE_PROMO_PRECONDITIONS_H_
diff --git a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions_interactive_uitest.cc b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions_interactive_uitest.cc
index 762984c..50aacfa 100644
--- a/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions_interactive_uitest.cc
+++ b/chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions_interactive_uitest.cc
@@ -4,9 +4,13 @@
 
 #include <memory>
 
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/toolbar_controller_util.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_controller.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/ui/views/user_education/impl/browser_feature_promo_preconditions.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
@@ -19,6 +23,11 @@
 #include "components/user_education/common/feature_promo/impl/common_preconditions.h"
 #include "content/public/test/browser_test.h"
 #include "ui/base/interaction/element_identifier.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/interaction/element_tracker_views.h"
+#include "ui/views/test/views_test_utils.h"
+#include "ui/views/view.h"
 #include "url/gurl.h"
 
 namespace {
@@ -59,8 +68,9 @@
   std::unique_ptr<TestAnchorProvider> anchor_element_provider_;
 };
 
-IN_PROC_BROWSER_TEST_F(BrowserFeaturePromoPreconditionsUiTest,
-                       WindowActivePrecondition_ElementInActiveBrowser) {
+using WindowActivePreconditionUiTest = BrowserFeaturePromoPreconditionsUiTest;
+
+IN_PROC_BROWSER_TEST_F(WindowActivePreconditionUiTest, ElementInActiveBrowser) {
   RunTestSequence(
       WaitForShow(kToolbarAppMenuButtonElementId),
       CheckResult(
@@ -76,8 +86,8 @@
           user_education::FeaturePromoResult::Success()));
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserFeaturePromoPreconditionsUiTest,
-                       WindowActivePrecondition_ElementInInactiveBrowser) {
+IN_PROC_BROWSER_TEST_F(WindowActivePreconditionUiTest,
+                       ElementInInactiveBrowser) {
   auto* const incog = CreateIncognitoBrowser();
   RunTestSequence(
       WaitForShow(kToolbarAppMenuButtonElementId),
@@ -102,8 +112,7 @@
           user_education::FeaturePromoResult::kBlockedByUi));
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserFeaturePromoPreconditionsUiTest,
-                       WindowActivePrecondition_PageInActiveTab) {
+IN_PROC_BROWSER_TEST_F(WindowActivePreconditionUiTest, PageInActiveTab) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTabId);
   RunTestSequence(
       InstrumentTab(kTabId),
@@ -123,8 +132,7 @@
           user_education::FeaturePromoResult::Success()));
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserFeaturePromoPreconditionsUiTest,
-                       WindowActivePrecondition_PageInInactiveTab) {
+IN_PROC_BROWSER_TEST_F(WindowActivePreconditionUiTest, PageInInactiveTab) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTabId1);
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTabId2);
   RunTestSequence(
@@ -167,8 +175,10 @@
           user_education::FeaturePromoResult::Success()));
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserFeaturePromoPreconditionsUiTest,
-                       OmniboxNotOpenPrecondition) {
+using OmniboxNotOpenPreconditionUiTest = BrowserFeaturePromoPreconditionsUiTest;
+
+IN_PROC_BROWSER_TEST_F(OmniboxNotOpenPreconditionUiTest,
+                       CheckOmniboxClosedAndOpen) {
   RunTestSequence(
       CheckView(
           kBrowserViewElementId,
@@ -199,3 +209,92 @@
           },
           user_education::FeaturePromoResult::kBlockedByUi));
 }
+
+class ToolbarNotCollapsedPreconditionUiTest
+    : public BrowserFeaturePromoPreconditionsUiTest {
+ public:
+  ToolbarNotCollapsedPreconditionUiTest() {
+    ToolbarControllerUtil::SetPreventOverflowForTesting(false);
+  }
+  ~ToolbarNotCollapsedPreconditionUiTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ToolbarNotCollapsedPreconditionUiTest,
+                       ToolbarExpandedAndCollapsed) {
+  RunTestSequence(
+      CheckView(
+          kBrowserViewElementId,
+          [](BrowserView* browser_view) {
+            ToolbarNotCollapsedPrecondition precond(*browser_view);
+            user_education::FeaturePromoPrecondition::ComputedData data;
+            return precond.CheckPrecondition(data);
+          },
+          user_education::FeaturePromoResult::Success()),
+
+      // Add elements to the toolbar until something collapses.
+      WithView(
+          kBrowserViewElementId,
+          [](BrowserView* browser_view) {
+            const ToolbarController* const controller =
+                browser_view->toolbar()->toolbar_controller();
+            CHECK(controller);
+            auto* const forward_button =
+                views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
+                    kToolbarForwardButtonElementId,
+                    browser_view->GetElementContext());
+            auto* const container_view =
+                views::ElementTrackerViews::GetInstance()->GetFirstMatchingView(
+                    ToolbarView::kToolbarContainerElementId,
+                    browser_view->GetElementContext());
+            constexpr gfx::Size kButtonSize{16, 16};
+            while (forward_button->GetVisible()) {
+              auto* const button = container_view->AddChildView(
+                  std::make_unique<ToolbarButton>());
+              button->SetPreferredSize(kButtonSize);
+              button->SetMinSize(kButtonSize);
+              button->GetViewAccessibility().SetName(u"dummy");
+              button->SetVisible(true);
+              views::test::RunScheduledLayout(browser_view);
+            }
+          }),
+      WaitForShow(kToolbarOverflowButtonElementId),
+
+      CheckView(
+          kBrowserViewElementId,
+          [](BrowserView* browser_view) {
+            ToolbarNotCollapsedPrecondition precond(*browser_view);
+            user_education::FeaturePromoPrecondition::ComputedData data;
+            return precond.CheckPrecondition(data);
+          },
+          user_education::FeaturePromoResult::kBlockedByUi));
+}
+
+using BrowserNotClosingPreconditionUiTest =
+    BrowserFeaturePromoPreconditionsUiTest;
+
+IN_PROC_BROWSER_TEST_F(BrowserNotClosingPreconditionUiTest,
+                       BrowserClosingOrNotClosing) {
+  RunTestSequence(
+      WaitForShow(kBrowserViewElementId),
+      CheckView(
+          kBrowserViewElementId,
+          [](BrowserView* browser_view) {
+            BrowserNotClosingPrecondition precond(*browser_view);
+            user_education::FeaturePromoPrecondition::ComputedData data;
+            return precond.CheckPrecondition(data);
+          },
+          user_education::FeaturePromoResult::Success()),
+      CheckView(
+          kBrowserViewElementId,
+          [](BrowserView* browser_view) {
+            BrowserNotClosingPrecondition precond(*browser_view);
+            user_education::FeaturePromoPrecondition::ComputedData data;
+            browser_view->GetWidget()->Close();
+            return precond.CheckPrecondition(data);
+          },
+          user_education::FeaturePromoResult::kBlockedByUi)
+          .SetMustRemainVisible(false));
+}
diff --git a/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc b/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc
index 31cbed9..1d7ed0fb 100644
--- a/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/simple_install_dialog_bubble_view_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/functional/callback_helpers.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_browsertest_base.h"
 #include "chrome/browser/ui/web_applications/web_app_dialogs.h"
@@ -281,6 +283,62 @@
       views::Widget::ClosedReason::kCloseButtonClicked, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(SimpleInstallDialogBubbleViewBrowserTest,
+                       WindowSizeLoweringClosesDialog) {
+  std::unique_ptr<webapps::MlInstallOperationTracker> install_tracker =
+      GetInstallTracker(browser());
+
+  views::NamedWidgetShownWaiter widget_waiter(
+      views::test::AnyWidgetTestPasskey{}, kInstallDialogName);
+  base::test::TestFuture<bool, std::unique_ptr<WebAppInstallInfo>> test_future;
+  ShowSimpleInstallDialogForWebApps(
+      browser()->tab_strip_model()->GetActiveWebContents(), GetAppInfo(),
+      std::move(install_tracker), test_future.GetCallback());
+
+  views::Widget* widget = widget_waiter.WaitIfNeededAndGet();
+  ASSERT_NE(widget, nullptr);
+  EXPECT_FALSE(test_future.IsReady());
+
+  base::HistogramTester histograms;
+  views::test::WidgetDestroyedWaiter destroy_waiter(widget);
+  // Make the size of the browser window too small for the dialog.
+  browser()->GetBrowserView().SetBounds(gfx::Rect(100, 100));
+  destroy_waiter.Wait();
+
+  ASSERT_TRUE(test_future.Wait());
+  EXPECT_FALSE(test_future.Get<bool>());
+
+  histograms.ExpectUniqueSample(
+      "WebApp.InstallConfirmation.CloseReason",
+      views::Widget::ClosedReason::kCloseButtonClicked, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(SimpleInstallDialogBubbleViewBrowserTest,
+                       SmallWindowClosesDialogAutomatically) {
+  std::unique_ptr<webapps::MlInstallOperationTracker> install_tracker =
+      GetInstallTracker(browser());
+
+  base::HistogramTester histograms;
+  views::AnyWidgetObserver widget_observer(views::test::AnyWidgetTestPasskey{});
+  browser()->GetBrowserView().SetBounds(gfx::Rect(100, 100));
+
+  base::RunLoop run_loop;
+  widget_observer.set_closing_callback(
+      base::BindLambdaForTesting([&](views::Widget* widget) {
+        if (widget->GetName() == kInstallDialogName) {
+          run_loop.Quit();
+        }
+      }));
+  ShowSimpleInstallDialogForWebApps(
+      browser()->tab_strip_model()->GetActiveWebContents(), GetAppInfo(),
+      std::move(install_tracker), base::DoNothing());
+  run_loop.Run();
+
+  histograms.ExpectUniqueSample(
+      "WebApp.InstallConfirmation.CloseReason",
+      views::Widget::ClosedReason::kCloseButtonClicked, 1);
+}
+
 class PictureInPictureSimpleInstallDialogOcclusionTest
     : public MixinBasedInProcessBrowserTest {
  protected:
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn
index 817809f7..5ea207b 100644
--- a/chrome/browser/ui/webui/BUILD.gn
+++ b/chrome/browser/ui/webui/BUILD.gn
@@ -63,24 +63,6 @@
   }
 }
 
-source_set("webui_util") {
-  sources = [ "webui_util.h" ]
-
-  public_deps = [ "//ui/webui" ]
-
-  if (!is_android) {
-    sources += [
-      "webui_embedding_context.cc",
-      "webui_embedding_context.h",
-    ]
-
-    deps = [
-      "//chrome/browser/ui/browser_window:browser_window",
-      "//chrome/browser/ui/tabs:tabs_public",
-    ]
-  }
-}
-
 source_set("webui") {
   sources = [
     "constrained_web_dialog_ui.cc",
@@ -103,3 +85,17 @@
     deps += [ "//ui/web_dialogs" ]
   }
 }
+
+if (!is_android) {
+  source_set("webui_util") {
+    sources = [
+      "webui_embedding_context.cc",
+      "webui_embedding_context.h",
+    ]
+
+    deps = [
+      "//chrome/browser/ui/browser_window:browser_window",
+      "//chrome/browser/ui/tabs:tabs_public",
+    ]
+  }
+}
diff --git a/chrome/browser/ui/webui/ash/account_manager/BUILD.gn b/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
index 6f083e4c..3f106629 100644
--- a/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/account_manager/BUILD.gn
@@ -34,7 +34,6 @@
     "//chrome/browser:resources",
     "//chrome/browser:resources_grit",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/signin/ash",
     "//chrome/common:constants",
     "//components/account_manager_core",
@@ -45,6 +44,7 @@
     "//ui/strings:ui_strings",
     "//ui/strings:ui_strings_grit",
     "//ui/views",
+    "//ui/webui",
     "//ui/wm",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn b/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
index 8e74c13..28a2d3e2 100644
--- a/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/add_supervision/BUILD.gn
@@ -55,7 +55,6 @@
     "//chrome/browser/resources/chromeos/add_supervision:resources_grit",
     "//chrome/browser/resources/chromeos/supervision:resources",
     "//chrome/browser/resources/chromeos/supervision:resources_grit",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/constrained_window",
     "//components/google/core/common",
     "//components/services/app_service/public/cpp:app_types",
@@ -66,6 +65,7 @@
     "//ui/resources:ui_resources_grd",
     "//ui/resources:ui_resources_grd_grit",
     "//ui/web_dialogs",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/app_install/BUILD.gn b/chrome/browser/ui/webui/ash/app_install/BUILD.gn
index 55296052..2b50f308 100644
--- a/chrome/browser/ui/webui/ash/app_install/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/app_install/BUILD.gn
@@ -54,7 +54,6 @@
     "//chrome/browser/apps/app_service/app_icon",
     "//chrome/browser/resources/chromeos/app_install:resources",
     "//chrome/browser/ui",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/web_applications",
     "//chrome/common",
     "//chromeos/constants",
diff --git a/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn b/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
index b4aaaa3..5dc259c 100644
--- a/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/assistant_optin/BUILD.gn
@@ -40,7 +40,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/assistant_optin:resources",
     "//chrome/browser/ui/ash/login",
-    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/components/assistant:buildflags",
     "//chromeos/ash/components/audio",
     "//chromeos/ash/services/assistant/public/cpp",
@@ -56,6 +55,7 @@
     "//ui/display",
     "//ui/gfx/geometry",
     "//ui/views",
+    "//ui/webui",
     "//ui/wm",
   ]
 
diff --git a/chrome/browser/ui/webui/ash/audio/BUILD.gn b/chrome/browser/ui/webui/ash/audio/BUILD.gn
index e70a362..9d7acad 100644
--- a/chrome/browser/ui/webui/ash/audio/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/audio/BUILD.gn
@@ -35,6 +35,6 @@
     "//ash/constants",
     "//chrome/browser/resources/chromeos/audio:resources",
     "//chrome/browser/ui",
-    "//chrome/browser/ui/webui:webui_util",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn b/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
index 95424e4..cb2b89b 100644
--- a/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/bluetooth/BUILD.gn
@@ -20,7 +20,6 @@
     "//base",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/bluetooth_pairing_dialog:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/network",
diff --git a/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn b/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
index 1e0e1c4..bad6952 100644
--- a/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/borealis_installer/BUILD.gn
@@ -47,11 +47,11 @@
     "//chrome/browser/resources/chromeos/borealis_installer:resources",
     "//chrome/browser/ui",
     "//chrome/browser/ui/views/borealis",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/strings:components_strings",
     "//ui/aura",
     "//ui/base",
     "//ui/strings:ui_strings",
+    "//ui/webui",
   ]
 
   allow_circular_includes_from = [ "//chrome/browser/ash/borealis" ]
diff --git a/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn b/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
index 2c37984d..cee5eb4 100644
--- a/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/cellular_setup/BUILD.gn
@@ -30,7 +30,6 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/mobile",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chromeos/ash/components/network",
     "//components/login",
@@ -41,6 +40,7 @@
     "//ui/chromeos",
     "//ui/gfx/geometry",
     "//ui/views",
+    "//ui/webui",
     "//url",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn b/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
index 542c470..5fadbb0 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/cloud_upload/BUILD.gn
@@ -88,7 +88,6 @@
     "//chrome/browser/extensions",
     "//chrome/browser/resources/chromeos/cloud_upload:resources",
     "//chrome/browser/ui/ash/system_web_apps",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/files",
     "//chrome/common:chrome_features",
     "//chromeos/ash/components/browser_context_helper",
diff --git a/chrome/browser/ui/webui/ash/config/BUILD.gn b/chrome/browser/ui/webui/ash/config/BUILD.gn
index 27cb98e..4fd5a9996 100644
--- a/chrome/browser/ui/webui/ash/config/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/config/BUILD.gn
@@ -62,7 +62,6 @@
     "//chrome/browser/ash/system_web_apps/apps/vc_background_ui",
     "//chrome/browser/ui",
     "//chrome/browser/ui/ash/holding_space",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/account_manager",
     "//chrome/browser/ui/webui/ash/add_supervision",
     "//chrome/browser/ui/webui/ash/app_install",
@@ -111,6 +110,7 @@
     "//chrome/browser/ui/webui/nearby_share",
     "//chromeos/ash/components/kiosk/vision/webui",
     "//components/cross_device/logging",
+    "//ui/webui",
   ]
 
   if (!is_official_build) {
diff --git a/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn b/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
index fce77a5..4e6e3bb 100644
--- a/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/crostini_installer/BUILD.gn
@@ -26,7 +26,6 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/crostini:crostini_installer_types_mojom",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/dbus/spaced",
diff --git a/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn b/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
index 91b9325..e3b1cc9 100644
--- a/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/crostini_upgrader/BUILD.gn
@@ -26,7 +26,6 @@
     "//chrome/browser:resources",
     "//chrome/browser/ash/crostini",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//components/strings:components_strings",
diff --git a/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn b/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
index d5e8aa9b..33815a8 100644
--- a/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/curtain_ui/BUILD.gn
@@ -17,7 +17,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/remote_maintenance_curtain:resources",
     "//chrome/browser/resources/chromeos/remote_maintenance_curtain:resources_grit",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/emoji/BUILD.gn b/chrome/browser/ui/webui/ash/emoji/BUILD.gn
index 4410604..166490e 100644
--- a/chrome/browser/ui/webui/ash/emoji/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/emoji/BUILD.gn
@@ -77,7 +77,6 @@
     "//chrome/app:generated_resources",
     "//chrome/browser/resources/chromeos/emoji_picker:resources",
     "//chrome/browser/resources/chromeos/seal:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/components/emoji:resources",
     "//components/prefs",
     "//net",
diff --git a/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn b/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
index 645d151..77693712 100644
--- a/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/enterprise_reporting/BUILD.gn
@@ -42,10 +42,10 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/profiles:profile_util",
     "//chrome/browser/resources/chromeos/enterprise_reporting:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/reporting/util:status",
     "//components/version_info",
     "//content/public/browser",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn b/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
index 1d60b76..6fad037b 100644
--- a/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/extended_updates/BUILD.gn
@@ -42,7 +42,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/extended_updates:resources",
     "//chrome/browser/ui/ash/login",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common",
     "//components/services/app_service",
diff --git a/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn b/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
index d02cff0..6f0ee98 100644
--- a/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/healthd_internals/BUILD.gn
@@ -27,7 +27,7 @@
   deps = [
     "//ash/constants",
     "//chrome/browser/resources/chromeos/healthd_internals:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/services/cros_healthd/public/cpp",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn b/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
index f9b25b4c..723784bd 100644
--- a/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/BUILD.gn
@@ -41,7 +41,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/password_change:resources",
     "//chrome/browser/resources/gaia_auth_host:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common:constants",
     "//chromeos/ash/components/login/auth/public:authpublic",
     "//chromeos/strings",
@@ -52,6 +51,7 @@
     "//ui/base",
     "//ui/display",
     "//ui/strings:ui_strings",
+    "//ui/webui",
   ]
 
   allow_circular_includes_from = [ "//chrome/browser/ash/login/saml" ]
diff --git a/chrome/browser/ui/webui/ash/internet/BUILD.gn b/chrome/browser/ui/webui/ash/internet/BUILD.gn
index 33ac368d..be6bbae 100644
--- a/chrome/browser/ui/webui/ash/internet/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/internet/BUILD.gn
@@ -19,7 +19,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/internet_config_dialog:resources",
     "//chrome/browser/resources/chromeos/internet_detail_dialog:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
diff --git a/chrome/browser/ui/webui/ash/kerberos/BUILD.gn b/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
index f0f73c8..ea4bbde 100644
--- a/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/kerberos/BUILD.gn
@@ -30,13 +30,13 @@
     "//chrome/app:generated_resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/kerberos:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//content/public/browser",
     "//net",
     "//ui/aura",
     "//ui/base:types",
     "//ui/display",
     "//ui/views",
+    "//ui/webui",
     "//url",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn b/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
index be80efe..0e602f47 100644
--- a/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/launcher_internals/BUILD.gn
@@ -35,6 +35,6 @@
     "//chrome/browser/ash/app_list",
     "//chrome/browser/ash/app_list/search/common",
     "//chrome/browser/resources/chromeos/launcher_internals:resources",
-    "//chrome/browser/ui/webui:webui_util",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
index bec5e325..bc8a0c1 100644
--- a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
@@ -66,7 +66,6 @@
     "//chrome/browser/resources/chromeos/lock_screen_reauth:resources",
     "//chrome/browser/resources/gaia_auth_host:resources",
     "//chrome/browser/ui/ash/login",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/internet",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/common:chrome_features",
@@ -89,6 +88,7 @@
     "//ui/chromeos/strings:strings_provider",
     "//ui/display",
     "//ui/strings:ui_strings",
+    "//ui/webui",
   ]
 
   allow_circular_includes_from = [
diff --git a/chrome/browser/ui/webui/ash/mako/BUILD.gn b/chrome/browser/ui/webui/ash/mako/BUILD.gn
index d31b1303..e75cbd5 100644
--- a/chrome/browser/ui/webui/ash/mako/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/mako/BUILD.gn
@@ -49,7 +49,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/mako:resources",
     "//chrome/browser/ui/views/bubble",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/lobster:lobster",
     "//chrome/common:mojo_bindings",
     "//chromeos/constants",
@@ -62,6 +61,7 @@
     "//ui/aura",
     "//ui/base/ime/ash",
     "//ui/display",
+    "//ui/webui",
   ]
 
   allow_circular_includes_from = [
diff --git a/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn b/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
index 30e1708b..bb9ff809 100644
--- a/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/manage_mirrorsync/BUILD.gn
@@ -44,7 +44,6 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/manage_mirrorsync:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//ui/aura",
     "//ui/base:types",
     "//ui/webui",
diff --git a/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn b/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
index 78141ed..86987d96 100644
--- a/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/multidevice_internals/BUILD.gn
@@ -33,12 +33,12 @@
     "//chrome/browser/ash/phonehub",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/multidevice_internals:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/ash/components/phonehub:debug",
     "//chromeos/ash/components/phonehub/proto",
     "//components/prefs",
     "//skia:skia_core_public_headers",
     "//ui/base",
     "//ui/gfx",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn b/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
index 40087f5..ac1a6fc 100644
--- a/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/multidevice_setup/BUILD.gn
@@ -43,7 +43,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos:multidevice_setup_resources",
     "//chrome/browser/ui/ash/login",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/login",
     "//chrome/browser/ui/webui/ash/user_image",
     "//chromeos/ash/services/multidevice_setup",
diff --git a/chrome/browser/ui/webui/ash/network_ui/BUILD.gn b/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
index d801880..0cbd7bb 100644
--- a/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/network_ui/BUILD.gn
@@ -34,7 +34,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/network_ui:resources",
     "//chrome/browser/ui/ash/system",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/internet",
     "//chromeos/ash/components/dbus/debug_daemon",
diff --git a/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn b/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
index 0ffd903..be04dbf 100644
--- a/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/notification_tester/BUILD.gn
@@ -30,12 +30,12 @@
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/notification_tester:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chromeos/constants",
     "//ui/base",
     "//ui/chromeos/styles:cros_tokens_color_mappings",
     "//ui/gfx",
     "//ui/message_center",
     "//ui/message_center/public/cpp",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn b/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
index cb39fa6b..3edf51a 100644
--- a/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/office_fallback/BUILD.gn
@@ -44,7 +44,6 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/chromeos/upload_office_to_cloud",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cloud_upload",
     "//chromeos/constants",
     "//ui/base",
diff --git a/chrome/browser/ui/webui/ash/parent_access/BUILD.gn b/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
index 59c391b..4c1413e 100644
--- a/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/parent_access/BUILD.gn
@@ -62,7 +62,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/parent_access:resources",
     "//chrome/browser/resources/chromeos/supervision:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/google/core/common",
     "//components/signin/public/base",
     "//google_apis",
diff --git a/chrome/browser/ui/webui/ash/power_ui/BUILD.gn b/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
index a93b3e0..284c338 100644
--- a/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/power_ui/BUILD.gn
@@ -16,10 +16,10 @@
     "//base",
     "//chrome/browser/ash/power",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
     "//content/public/common",
     "//ui/base",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn b/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
index c68b4f26..4e6837a 100644
--- a/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/sensor_info/BUILD.gn
@@ -36,7 +36,7 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/sensor_info:resources",
-    "//chrome/browser/ui/webui:webui_util",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/set_time/BUILD.gn b/chrome/browser/ui/webui/ash/set_time/BUILD.gn
index 4ae8a96f..d571a59 100644
--- a/chrome/browser/ui/webui/ash/set_time/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/set_time/BUILD.gn
@@ -22,7 +22,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/set_time_dialog:resources",
     "//chrome/browser/resources/chromeos/set_time_dialog:resources_grit",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/system_web_dialog",
     "//chrome/common",
     "//chromeos/ash/components/dbus/system_clock",
diff --git a/chrome/browser/ui/webui/ash/settings/BUILD.gn b/chrome/browser/ui/webui/ash/settings/BUILD.gn
index be39684a..4812675 100644
--- a/chrome/browser/ui/webui/ash/settings/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/BUILD.gn
@@ -76,7 +76,6 @@
     "//chrome/browser/resources/ash/settings:resources",
     "//chrome/browser/resources/settings_shared:resources",
     "//chrome/browser/ui/ash/wallpaper",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/apps",
     "//chrome/browser/ui/webui/ash/settings/pages/date_time",
     "//chrome/browser/ui/webui/ash/settings/pages/device",
@@ -105,6 +104,7 @@
     "//ui/base/ime/ash",
     "//ui/gfx",
     "//ui/views",
+    "//ui/webui",
   ]
 
   allow_circular_includes_from = [
diff --git a/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc b/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
index 10c7ac5d..4e155280 100644
--- a/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/ash/settings/os_settings_ui.cc
@@ -407,7 +407,6 @@
 
 void OSSettingsUI::BindInterface(
     mojo::PendingReceiver<::ash::common::mojom::AcceleratorFetcher> receiver) {
-  CHECK(::features::IsShortcutCustomizationEnabled());
   OsSettingsManagerFactory::GetForProfile(Profile::FromWebUI(web_ui()))
       ->accelerator_fetcher()
       ->BindInterface(std::move(receiver));
diff --git a/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
index 3ea76411..4de0b6fb 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/a11y/BUILD.gn
@@ -47,7 +47,6 @@
     "//chrome/browser/ash/accessibility",
     "//chrome/browser/ash/crosapi:browser_util",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chromeos/components/kiosk",
@@ -67,6 +66,7 @@
     "//ui/events/ash",
     "//ui/events/devices",
     "//ui/events/ozone/layout",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
index e832aa9..07d25a1 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/about/BUILD.gn
@@ -34,7 +34,6 @@
     "//chrome/browser/ash/arc",
     "//chrome/browser/ash/arc:arc_util",
     "//chrome/browser/ash/policy/core",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:channel_info",
@@ -48,6 +47,7 @@
     "//content/public/browser",
     "//ui/base",
     "//ui/chromeos",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
index 9c590fe8..d2b5bae 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/apps/BUILD.gn
@@ -45,7 +45,6 @@
     "//chrome/browser/ash/plugin_vm",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/settings:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/pages/crostini",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/web_applications",
@@ -58,6 +57,7 @@
     "//ui/chromeos",
     "//ui/display",
     "//ui/events:event_constants",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
index 8a03d53..497736d 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/bluetooth/BUILD.gn
@@ -35,7 +35,6 @@
     "//ash/webui/settings/public/constants:mojom",
     "//chrome/app:generated_resources",
     "//chrome/browser:browser_public_dependencies",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/bluetooth",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/settings/search/mojom",
@@ -48,6 +47,7 @@
     "//content/public/browser",
     "//device/bluetooth/strings",
     "//ui/base",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
index d741bd2..27d9aa0 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/date_time/BUILD.gn
@@ -39,7 +39,6 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/system",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/set_time",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
@@ -47,5 +46,6 @@
     "//components/policy/proto",
     "//components/user_manager",
     "//ui/base",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
index 945f619..0a50e9b 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/BUILD.gn
@@ -53,7 +53,6 @@
     "//chrome/browser/ash/note_taking",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/system_web_apps",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:chrome_features",
@@ -70,6 +69,7 @@
     "//ui/display/manager",
     "//ui/display/types",
     "//ui/events/ash",
+    "//ui/webui",
   ]
 
   if (is_chrome_branded) {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
index 990a04f..1da9186 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
@@ -517,8 +517,8 @@
   html_source->AddBoolean(
       "languagePacksInSettingsEnabled",
       base::FeatureList::IsEnabled(features::kLanguagePacksInSettings));
-  html_source->AddBoolean("isShortcutCustomizationEnabled",
-                          ::features::IsShortcutCustomizationEnabled());
+  // TODO(b/290861003): Update the settings code and remove this.
+  html_source->AddBoolean("isShortcutCustomizationEnabled", true);
 
   AddInputMethodOptionsLoadTimeData(
       html_source,
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
index 7f60714f..09f308f7 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/files/BUILD.gn
@@ -37,7 +37,6 @@
     "//chrome/browser/ash/file_manager",
     "//chrome/browser/ash/profiles",
     "//chrome/browser/chromeos/upload_office_to_cloud",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/smb_shares",
     "//chrome/common",
@@ -47,6 +46,7 @@
     "//components/user_manager",
     "//content/public/browser",
     "//ui/base",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
index f08204d..257e628 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/internet/BUILD.gn
@@ -40,7 +40,6 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/chromeos/extensions/vpn_provider",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/cellular_setup",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
@@ -58,6 +57,7 @@
     "//ui/chromeos/strings",
     "//ui/chromeos/strings:strings_provider",
     "//ui/events:event_constants",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
index b8d3903..335d34f 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/kerberos/BUILD.gn
@@ -28,7 +28,6 @@
     "//chrome/browser:browser_process",
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:constants",
@@ -38,5 +37,6 @@
     "//ui/base",
     "//ui/chromeos/resources",
     "//ui/gfx",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
index 34a8c5ac..0bbf56c 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/languages/BUILD.gn
@@ -25,7 +25,6 @@
     "//chrome/browser/ash/input_method",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/keyboard",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chromeos/components/quick_answers/public/cpp",
@@ -34,6 +33,7 @@
     "//content/public/browser",
     "//net",
     "//ui/base",
+    "//ui/webui",
     "//url",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
index 76dc59de..62e0cdcd 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/main/BUILD.gn
@@ -36,7 +36,6 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/ash/settings:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/ash/settings/services/hats",
     "//chrome/common",
@@ -47,6 +46,7 @@
     "//content/public/browser",
     "//ui/base",
     "//ui/chromeos",
+    "//ui/webui",
   ]
 }
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
index b18ed1b..3d8e6178 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/multidevice/BUILD.gn
@@ -39,7 +39,6 @@
     "//chrome/browser/nearby_sharing/common",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui/ash/session",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/multidevice_setup",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/ui/webui/nearby_share",
@@ -53,6 +52,7 @@
     "//content/public/browser",
     "//ui/base",
     "//ui/chromeos",
+    "//ui/webui",
   ]
 
   if (is_chrome_branded) {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
index f91704b..57d6405 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
@@ -742,9 +742,17 @@
       l10n_util::GetStringFUTF16(
           IDS_SETTINGS_MULTIDEVICE_PERMISSIONS_SETUP_DIALOG_NOTIFICATION_ACCESS_PROHIBITED_SUMMARY,
           GetHelpUrlWithBoard(phonehub::kPhoneHubLearnMoreLink)));
+  html_source->AddString(
+      "authPrompt",
+      l10n_util::GetStringFUTF16(
+          IDS_SETTINGS_IN_SESSION_AUTH_ORIGIN_NAME_PROMPT,
+          l10n_util::GetStringUTF16(
+              IDS_SETTINGS_IN_SESSION_AUTH_ORIGIN_NAME_PROMPT_LOCATION)));
 
   html_source->AddBoolean("isCrossDeviceFeatureSuiteEnabled",
                           features::IsCrossDeviceFeatureSuiteAllowed());
+  html_source->AddBoolean("isAuthPanelEnabled",
+                          ash::features::IsUseAuthPanelInSessionEnabled());
 
   // We still need to register strings even if Nearby Share is not supported.
   // For example, the HTML is always built but only displayed if Nearby Share is
diff --git a/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
index 20a4c92..6c5d571 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/people/BUILD.gn
@@ -63,7 +63,6 @@
     "//chrome/browser/profiles:profile",
     "//chrome/browser/sync",
     "//chrome/browser/ui:ui_features",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/account_manager",
     "//chrome/browser/ui/webui/ash/add_supervision",
     "//chrome/browser/ui/webui/ash/settings/search",
@@ -88,6 +87,7 @@
     "//ui/display/types",
     "//ui/events:event_constants",
     "//ui/gfx",
+    "//ui/webui",
     "//url",
   ]
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/power/power_section.cc b/chrome/browser/ui/webui/ash/settings/pages/power/power_section.cc
index b09a9a7..94472834 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/power/power_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/power/power_section.cc
@@ -164,11 +164,11 @@
       {"powerIdleWhileChargingAriaLabel",
        IDS_SETTINGS_POWER_IDLE_WHILE_CHARGING_ARIA_LABEL},
       {"powerInactiveWhilePluggedInLabel",
-       IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL},
+       IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_PLUGGED_IN_LABEL},
       {"powerIdleWhileOnBatteryAriaLabel",
        IDS_SETTINGS_POWER_IDLE_WHILE_ON_BATTERY_ARIA_LABEL},
       {"powerInactiveWhileOnBatteryLabel",
-       IDS_OS_SETTINGS_REVAMP_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL},
+       IDS_OS_SETTINGS_POWER_INACTIVE_WHILE_ON_BATTERY_LABEL},
       {"powerLidShutDownLabel", IDS_SETTINGS_POWER_LID_CLOSED_SHUT_DOWN_LABEL},
       {"powerLidSignOutLabel", IDS_SETTINGS_POWER_LID_CLOSED_SIGN_OUT_LABEL},
       {"powerLidSleepLabel", IDS_SETTINGS_POWER_LID_CLOSED_SLEEP_LABEL},
diff --git a/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
index f91f120..8bd505a7 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/printing/BUILD.gn
@@ -34,7 +34,6 @@
     "//chrome/app:generated_resources",
     "//chrome/browser:browser_process",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
     "//chrome/common:chrome_features",
@@ -45,6 +44,7 @@
     "//net",
     "//printing/backend",
     "//ui/base",
+    "//ui/webui",
     "//url",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
index 4ac4b3b..cc51c7e26 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/privacy/BUILD.gn
@@ -58,7 +58,6 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/settings",
     "//chrome/browser/ash/system",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/browser/web_applications",
     "//chrome/common",
@@ -73,6 +72,7 @@
     "//components/sync/base:features",
     "//ui/base",
     "//ui/chromeos",
+    "//ui/webui",
     "//url",
   ]
 
diff --git a/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
index 1f49e94..c59b17b 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/reset/BUILD.gn
@@ -22,11 +22,11 @@
     "//chrome/browser:browser_process",
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chromeos/ash/components/browser_context_helper:browser_context_helper",
     "//components/user_manager",
     "//content/public/browser",
     "//ui/base",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/settings/pages/reset/reset_section.cc b/chrome/browser/ui/webui/ash/settings/pages/reset/reset_section.cc
index 72ea248e..dc77bc8 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/reset/reset_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/reset/reset_section.cc
@@ -63,7 +63,7 @@
 
 void ResetSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
-      {"resetPageTitle", IDS_OS_SETTINGS_REVAMP_RESET_TITLE},
+      {"resetPageTitle", IDS_OS_SETTINGS_RESET_TITLE},
       {"powerwashTitle", IDS_SETTINGS_FACTORY_RESET},
       {"powerwashDialogTitle", IDS_SETTINGS_FACTORY_RESET_HEADING},
       {"powerwashDialogButton", IDS_SETTINGS_RESTART},
@@ -103,9 +103,9 @@
       ::settings::ResetSettingsHandler::ShouldShowResetProfileBanner(
           profile()));
 
-  html_source->AddString("powerwashDescription",
-                         l10n_util::GetStringUTF16(
-                             IDS_OS_SETTINGS_REVAMP_FACTORY_RESET_DESCRIPTION));
+  html_source->AddString(
+      "powerwashDescription",
+      l10n_util::GetStringUTF16(IDS_OS_SETTINGS_FACTORY_RESET_DESCRIPTION));
 }
 
 void ResetSection::AddHandlers(content::WebUI* web_ui) {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
index 87d964c..18afaf4 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/settings/pages/search/BUILD.gn
@@ -39,7 +39,6 @@
     "//chrome/browser/ash/lobster",
     "//chrome/browser/ash/magic_boost",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/ash/assistant_optin",
     "//chrome/browser/ui/webui/ash/settings/search",
     "//chrome/common",
@@ -53,6 +52,7 @@
     "//ui/base",
     "//ui/chromeos",
     "//ui/gfx/geometry",
+    "//ui/webui",
   ]
 
   if (is_chrome_branded) {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.cc b/chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.cc
index 5b04891..136d537 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/system_preferences/startup_section.cc
@@ -56,8 +56,8 @@
   webui::LocalizedString kLocalizedStrings[] = {
       {"onStartupSettingsCardTitle",
        IDS_OS_SETTINGS_ON_STARTUP_SETTINGS_CARD_TITLE},
-      {"onStartupTitle", IDS_OS_SETTINGS_REVAMP_ON_STARTUP_TITLE},
-      {"onStartupDescription", IDS_OS_SETTINGS_REVAMP_ON_STARTUP_DESCRIPTION},
+      {"onStartupTitle", IDS_OS_SETTINGS_ON_STARTUP_TITLE},
+      {"onStartupDescription", IDS_OS_SETTINGS_ON_STARTUP_DESCRIPTION},
       {"onStartupAlways", IDS_OS_SETTINGS_ON_STARTUP_ALWAYS},
       {"onStartupAskEveryTime", IDS_OS_SETTINGS_ON_STARTUP_ASK_EVERY_TIME},
       {"onStartupDoNotRestore", IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE},
diff --git a/chrome/browser/ui/webui/ash/shortcut_customization/integration_tests/shortcut_customization_interactive_uitest.cc b/chrome/browser/ui/webui/ash/shortcut_customization/integration_tests/shortcut_customization_interactive_uitest.cc
index 4b56925c..d6d86cf 100644
--- a/chrome/browser/ui/webui/ash/shortcut_customization/integration_tests/shortcut_customization_interactive_uitest.cc
+++ b/chrome/browser/ui/webui/ash/shortcut_customization/integration_tests/shortcut_customization_interactive_uitest.cc
@@ -51,8 +51,7 @@
     webcontents_id_ = kShortcutAppWebContentsId;
 
     feature_list_.InitWithFeatures(
-        {::features::kShortcutCustomization,
-         ash::features::kInputDeviceSettingsSplit,
+        {ash::features::kInputDeviceSettingsSplit,
          ash::features::kEnableKeyboardBacklightControlInSettings},
         {});
   }
diff --git a/chrome/browser/ui/webui/ash/skyvault/BUILD.gn b/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
index 3f3fd3a..e83402b 100644
--- a/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/skyvault/BUILD.gn
@@ -35,7 +35,6 @@
     "//chrome/browser/ash/policy/skyvault",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/skyvault:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chrome/common:chrome_features",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/ash/slow/BUILD.gn b/chrome/browser/ui/webui/ash/slow/BUILD.gn
index 800a2f0..3244b47 100644
--- a/chrome/browser/ui/webui/ash/slow/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/slow/BUILD.gn
@@ -17,10 +17,10 @@
   deps = [
     "//base",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//components/feedback/content",
     "//content/public/browser",
     "//content/public/common",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn b/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
index 5470c95..ddead87 100644
--- a/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/smb_shares/BUILD.gn
@@ -31,7 +31,6 @@
     "//chrome/browser/ash/profiles",
     "//chrome/browser/ash/smb_client",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chromeos/constants",
     "//components/strings:components_strings",
diff --git a/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn b/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
index a7d38f23..780fef66 100644
--- a/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/sys_internals/BUILD.gn
@@ -18,11 +18,11 @@
     "//base",
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
     "//content/public/common",
     "//services/network/public/mojom:url_loader_base",
+    "//ui/webui",
     "//ui/webui/resources:resources_grit",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn b/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
index b4cef04..427689fe 100644
--- a/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/vc_tray_tester/BUILD.gn
@@ -17,8 +17,8 @@
     "//chrome/browser:resources",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/vc_tray_tester:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//content/public/browser",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/ash/vm/BUILD.gn b/chrome/browser/ui/webui/ash/vm/BUILD.gn
index 6a073a41..4323f90 100644
--- a/chrome/browser/ui/webui/ash/vm/BUILD.gn
+++ b/chrome/browser/ui/webui/ash/vm/BUILD.gn
@@ -20,7 +20,6 @@
     "//chrome/browser/ash/plugin_vm",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/resources/chromeos/vm:resources",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//components/strings:components_strings",
     "//content/public/browser",
diff --git a/chrome/browser/ui/webui/commerce/BUILD.gn b/chrome/browser/ui/webui/commerce/BUILD.gn
index e6d9e03..3e808b6 100644
--- a/chrome/browser/ui/webui/commerce/BUILD.gn
+++ b/chrome/browser/ui/webui/commerce/BUILD.gn
@@ -56,7 +56,6 @@
     "//chrome/browser/resources/side_panel/shared:resources_grit",
     "//chrome/browser/ui/bookmarks",
     "//chrome/browser/ui/webui",
-    "//chrome/browser/ui/webui:webui_util",
     "//components/bookmarks/browser",
     "//components/commerce/core:feature_list",
     "//components/commerce/core:metrics",
@@ -64,5 +63,6 @@
     "//components/commerce/core:utils",
     "//components/power_bookmarks/core",
     "//components/web_modal",
+    "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
index f55dddcd..7d8c87d 100644
--- a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
+++ b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
@@ -127,6 +127,10 @@
   source->AddInteger("maxNameLength", kMaxNameLength);
   source->AddInteger("maxTableSize", kMaxTableSize);
 
+  source->AddBoolean(
+      "comparisonTableListEnabled",
+      base::FeatureList::IsEnabled(commerce::kCompareManagementInterface));
+
   std::string email;
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/ui/webui/glic/glic.mojom b/chrome/browser/ui/webui/glic/glic.mojom
index d1a1c7d..bfaecc0 100644
--- a/chrome/browser/ui/webui/glic/glic.mojom
+++ b/chrome/browser/ui/webui/glic/glic.mojom
@@ -34,6 +34,16 @@
   TabContext tab_context;
 };
 
+// Information about the user profile.
+struct UserProfileInfo {
+  // Profile avatar image bitmap.
+  skia.mojom.BitmapN32? avatar_icon;
+  // The user's name for display purposes.
+  string display_name;
+  // The user's email.
+  string email;
+};
+
 // Access to the browser from the web client by proxy through the WebUI.
 // A single WebClientHandler will provide access to the browser for only
 // a single web client. If the webview navigates or refreshes, a new
@@ -86,6 +96,11 @@
   // prefs::kGlicTabContextEnabled. Returns when the browser has stored the new
   // pref value.
   SetTabContextPermissionState(bool enabled) => ();
+
+  // Returns the user profile information. This should only return null if
+  // the profile associated with this webui is invalid, which should only
+  // possibly happen during teardown.
+  GetUserProfileInfo() => (UserProfileInfo? profile_info);
 };
 
 // State of the glic panel.
diff --git a/chrome/browser/ui/webui/glic/glic_page_handler.cc b/chrome/browser/ui/webui/glic/glic_page_handler.cc
index 3d3b1a4..bd11ccf 100644
--- a/chrome/browser/ui/webui/glic/glic_page_handler.cc
+++ b/chrome/browser/ui/webui/glic/glic_page_handler.cc
@@ -4,14 +4,19 @@
 
 #include "chrome/browser/ui/webui/glic/glic_page_handler.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "base/version_info/version_info.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/glic/glic_keyed_service.h"
 #include "chrome/browser/glic/glic_keyed_service_factory.h"
 #include "chrome/browser/glic/glic_window_controller.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/glic/glic.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
 #include "ui/gfx/geometry/mojom/geometry.mojom.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -22,9 +27,10 @@
   explicit GlicWebClientHandler(
       content::BrowserContext* browser_context,
       mojo::PendingReceiver<glic::mojom::WebClientHandler> receiver)
-      : glic_service_(
+      : profile_(Profile::FromBrowserContext(browser_context)),
+        glic_service_(
             GlicKeyedServiceFactory::GetGlicKeyedService(browser_context)),
-        pref_service_(Profile::FromBrowserContext(browser_context)->GetPrefs()),
+        pref_service_(profile_->GetPrefs()),
         receiver_(this, std::move(receiver)) {}
 
   // glic::mojom::WebClientHandler implementation.
@@ -122,6 +128,28 @@
     std::move(callback).Run();
   }
 
+  void GetUserProfileInfo(GetUserProfileInfoCallback callback) override {
+    ProfileAttributesEntry* entry =
+        g_browser_process->profile_manager()
+            ->GetProfileAttributesStorage()
+            .GetProfileAttributesWithPath(profile_->GetPath());
+    if (!entry) {
+      std::move(callback).Run(nullptr);
+      return;
+    }
+
+    auto result = mojom::UserProfileInfo::New();
+    // TODO(crbug.com/382794680): Determine the correct size.
+    gfx::Image icon = entry->GetAvatarIcon(512);
+    if (!icon.IsEmpty()) {
+      result->avatar_icon = icon.AsBitmap();
+    }
+    result->display_name = base::UTF16ToUTF8(entry->GetGAIAName());
+    result->email = base::UTF16ToUTF8(entry->GetUserName());
+
+    std::move(callback).Run(std::move(result));
+  }
+
   // GlicWindowController::StateObserver implementation.
   void PanelStateChanged(const mojom::PanelState& panel_state) override {
     web_client_->NotifyPanelStateChange(panel_state.Clone());
@@ -156,6 +184,7 @@
   }
 
   PrefChangeRegistrar pref_change_registrar_;
+  raw_ptr<Profile> profile_;
   raw_ptr<GlicKeyedService> glic_service_;
   raw_ptr<PrefService> pref_service_;
   mojo::Receiver<glic::mojom::WebClientHandler> receiver_;
diff --git a/chrome/browser/ui/webui/history/history_ui.cc b/chrome/browser/ui/webui/history/history_ui.cc
index 4a82be18..4cbab60 100644
--- a/chrome/browser/ui/webui/history/history_ui.cc
+++ b/chrome/browser/ui/webui/history/history_ui.cc
@@ -47,6 +47,7 @@
 #include "chrome/grit/history_resources.h"
 #include "chrome/grit/history_resources_map.h"
 #include "chrome/grit/locale_settings.h"
+#include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/feature_utils.h"
 #include "components/commerce/core/mojom/shopping_service.mojom.h"
 #include "components/commerce/core/shopping_service.h"
@@ -248,9 +249,13 @@
   commerce::ShoppingService* service =
       commerce::ShoppingServiceFactory::GetForBrowserContext(profile);
   // Used to determine when the compare tab on history sidepanel is shown.
-  source->AddBoolean("compareHistoryEnabled",
-                     commerce::CanLoadProductSpecificationsFullPageUi(
-                         service->GetAccountChecker()));
+  // Hide the compare tab when the new management interface is enabled, since
+  // this interface provides the same functionality.
+  source->AddBoolean(
+      "compareHistoryEnabled",
+      commerce::CanLoadProductSpecificationsFullPageUi(
+          service->GetAccountChecker()) &&
+          !base::FeatureList::IsEnabled(commerce::kCompareManagementInterface));
   return source;
 }
 
diff --git a/chrome/browser/ui/webui/nearby_share/BUILD.gn b/chrome/browser/ui/webui/nearby_share/BUILD.gn
index e2e8df9..862a438e 100644
--- a/chrome/browser/ui/webui/nearby_share/BUILD.gn
+++ b/chrome/browser/ui/webui/nearby_share/BUILD.gn
@@ -24,7 +24,6 @@
     "//chrome/browser/resources/chromeos/nearby_share:resources",
     "//chrome/browser/ui:browser_navigator_params_headers",
     "//chrome/browser/ui/webui",
-    "//chrome/browser/ui/webui:webui_util",
     "//ui/webui",
   ]
 }
diff --git a/chrome/browser/ui/webui/signin/BUILD.gn b/chrome/browser/ui/webui/signin/BUILD.gn
index 4797a9a..5f23110 100644
--- a/chrome/browser/ui/webui/signin/BUILD.gn
+++ b/chrome/browser/ui/webui/signin/BUILD.gn
@@ -146,7 +146,6 @@
     "//chrome/browser/resources/signin:resources",
     "//chrome/browser/sync",
     "//chrome/browser/ui/signin",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/common",
     "//chrome/common/themes:autogenerated_theme_util",
     "//components/consent_auditor",
@@ -156,6 +155,7 @@
     "//extensions/browser",
     "//google_apis",
     "//net",
+    "//ui/webui",
   ]
 
   if (enable_dice_support) {
@@ -182,11 +182,11 @@
     deps += [
       ":login",
       "//chrome/browser/ui/tabs:tab_strip",
-      "//chrome/browser/ui/webui:webui_util",
       "//components/keyed_service/content",
       "//components/policy/core/browser",
       "//components/signin/core/browser",
       "//components/unified_consent",
+      "//ui/webui",
     ]
   }
 }
@@ -271,7 +271,7 @@
       "//chrome/browser/extensions",
       "//chrome/browser/prefs",
       "//chrome/browser/resources/gaia_auth_host:resources",
-      "//chrome/browser/ui/webui:webui_util",
+      "//ui/webui",
     ]
 
     if (is_chromeos) {
@@ -363,7 +363,6 @@
       "//chrome/browser/ui:ui_features",
       "//chrome/browser/ui/color:color_headers",
       "//chrome/browser/ui/signin",
-      "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/top_chrome",
       "//chrome/common",
       "//components/policy/core/browser:browser",
@@ -384,6 +383,7 @@
       "//ui/native_theme",
       "//ui/resources",
       "//ui/strings:ui_strings",
+      "//ui/webui",
       "//url",
     ]
   }
diff --git a/chrome/browser/ui/webui/webui_util.h b/chrome/browser/ui/webui/webui_util.h
deleted file mode 100644
index adad1e8f..0000000
--- a/chrome/browser/ui/webui/webui_util.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_WEBUI_UTIL_H_
-#define CHROME_BROWSER_UI_WEBUI_WEBUI_UTIL_H_
-
-#include "base/containers/span.h"
-#include "build/build_config.h"
-#include "ui/base/webui/resource_path.h"
-#include "ui/webui/webui_util.h"
-
-using webui::AddLocalizedString;
-using webui::EnableTrustedTypesCSP;
-using webui::kDefaultTrustedTypesPolicies;
-using webui::SetJSModuleDefaults;
-using webui::SetupWebUIDataSource;
-
-#endif  // CHROME_BROWSER_UI_WEBUI_WEBUI_UTIL_H_
diff --git a/chrome/browser/ui/webui/whats_new/BUILD.gn b/chrome/browser/ui/webui/whats_new/BUILD.gn
index 7fd106b4..178f35c 100644
--- a/chrome/browser/ui/webui/whats_new/BUILD.gn
+++ b/chrome/browser/ui/webui/whats_new/BUILD.gn
@@ -83,12 +83,12 @@
       "//chrome/browser/resources/whats_new:resources",
       "//chrome/browser/ui:browser_list",
       "//chrome/browser/ui/hats",
-      "//chrome/browser/ui/webui:webui_util",
       "//chrome/common:version_header",
       "//components/bookmarks/common",
       "//components/history_embeddings",
       "//components/user_education/common",
       "//components/variations/service",
+      "//ui/webui",
     ]
   }
 }
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager.cc b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
index 2fc7538b..a6583e4 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_manager.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
@@ -727,6 +727,14 @@
 }
 
 void PreinstalledWebAppManager::Load(ConsumeInstallOptions callback) {
+  bool preinstalling_enabled =
+      base::FeatureList::IsEnabled(features::kPreinstalledWebAppInstallation);
+
+  if (!preinstalling_enabled) {
+    std::move(callback).Run({});
+    return;
+  }
+
   auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
   RunChainedCallbacks(
       base::BindOnce(&PreinstalledWebAppManager::LoadDeviceInfo, weak_ptr),
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
index 65e11a3..a83a9ea 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_path_override.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -484,6 +485,22 @@
   ExpectHistograms(/*enabled=*/0, /*disabled=*/0, /*errors=*/2);
 }
 
+TEST_F(PreinstalledWebAppManagerTest, PreinstalledWebAppInstallDisabled) {
+  set_profile(CreateProfileAndLogin());
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      features::kPreinstalledWebAppInstallation);
+  const auto app_infos = LoadApps(kGoodJsonTestDir);
+
+  EXPECT_EQ(0u, app_infos.size());
+  histograms_.ExpectTotalCount(
+      PreinstalledWebAppManager::kHistogramConfigErrorCount, 0);
+  histograms_.ExpectTotalCount(
+      PreinstalledWebAppManager::kHistogramEnabledCount, 0);
+  histograms_.ExpectTotalCount(
+      PreinstalledWebAppManager::kHistogramDisabledCount, 0);
+}
+
 TEST_F(PreinstalledWebAppManagerTest, EnabledByFinch) {
   set_profile(CreateProfileAndLogin());
   base::AutoReset<bool> testing_scope =
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 895e5ddf..d8fe6cf 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1734717451-a7e8b7821e113ec683bfbeaf3ef8f5ceddbd20e3-59b1c8501f4c46a54e4227b038d97732e2b17942.profdata
+chrome-android32-main-1734753651-b23fabf8ebea0dcc7d56bead2c08c664f6e36e76-759122182116d7ecf34d21df3ffc79c276e85b26.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index e1b0f0f..f1e5244 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1734727983-39b32bbd0a97c65abb73f3e691d3ba178adbfb5d-178318c2d3eb469c0c67b2d2e2a55c04c4b92b21.profdata
+chrome-android64-main-1734753651-a79954e005185818f3b9a6c180bdb2803acd25c6-759122182116d7ecf34d21df3ffc79c276e85b26.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 44c541c..7e0be373 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1734674010-335f10c92986a0cc222e62d84358a56a3be14fd5-c3a02f16b49d52ab19b7261608005f952b3f3c1f.profdata
+chrome-linux-main-1734739051-53b7a1787415e05d8f77547f4bbc82f8aa4058ee-cfab8f0ac75e2fd2fad2f46c91a6d0d64b5a836a.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 6b5ca07..d1af226 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1734717451-ea7eef7976ae845dff54ce2cb22bf7c221eeda8a-59b1c8501f4c46a54e4227b038d97732e2b17942.profdata
+chrome-mac-arm-main-1734753302-db964bd25c5490c208de0c32cfba0d9dd73170a2-988e6eae6751b1789b9a44c5b0c3ef31653be3dc.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 835770b..094c5ea 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1734717451-c91cc0058fba8819a507e54e33e9f129570b1f9b-59b1c8501f4c46a54e4227b038d97732e2b17942.profdata
+chrome-mac-main-1734739051-c39300c500b0f20a13ecbca70b3d7a463779ba43-cfab8f0ac75e2fd2fad2f46c91a6d0d64b5a836a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index a4092ba..1f7935fc 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1734706069-8ca18105c690850068243a24569e8ace0ea6790a-0fed915081a71c740ff11b6f0d8b842f0f8f1cf4.profdata
+chrome-win32-main-1734739051-a74cbbe62c7d071bc6c6fa7bca641609a009e2d0-cfab8f0ac75e2fd2fad2f46c91a6d0d64b5a836a.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1c1b4d4..59cf36d8 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1734706069-49142f0b64d8c0f1f09ecce3633315d3348fff6b-0fed915081a71c740ff11b6f0d8b842f0f8f1cf4.profdata
+chrome-win64-main-1734739051-63454e5aa25e7ec8f429975087d80aa3d4a5ce6a-cfab8f0ac75e2fd2fad2f46c91a6d0d64b5a836a.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7cf4ac5..b96a503 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -200,6 +200,13 @@
              base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
+// Whether to allow installed-by-default web apps to be installed or not.
+BASE_FEATURE(kPreinstalledWebAppInstallation,
+             "DefaultWebAppInstallation",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS)
 // If enabled, specified extensions cannot be closed via the task manager.
 BASE_FEATURE(kDesktopTaskManagerEndProcessDisabledForExtension,
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index d03da54..4fd5157 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -129,6 +129,9 @@
 #if !BUILDFLAG(IS_ANDROID)
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+BASE_DECLARE_FEATURE(kPreinstalledWebAppInstallation);
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kPreinstalledWebAppDuplicationFixer);
 #endif
 
diff --git a/chrome/common/profiler/thread_profiler_platform_configuration.cc b/chrome/common/profiler/thread_profiler_platform_configuration.cc
index 2355c2a..f276094 100644
--- a/chrome/common/profiler/thread_profiler_platform_configuration.cc
+++ b/chrome/common/profiler/thread_profiler_platform_configuration.cc
@@ -170,6 +170,9 @@
       sampling_profiler::ProfilerThreadType thread,
       std::optional<version_info::Channel> release_channel) const override;
 
+  bool IsSupportedForChannel(
+      std::optional<version_info::Channel> release_channel) const override;
+
  private:
   // Whether profiling is enabled on a thread type for Android DEV channel.
   const base::flat_map<sampling_profiler::ProfilerThreadType, bool>
@@ -308,6 +311,25 @@
   }
 }
 
+bool AndroidPlatformConfiguration::IsSupportedForChannel(
+    std::optional<version_info::Channel> release_channel) const {
+  // The profiler is always supported for local builds and the CQ.
+  if (!release_channel) {
+    return true;
+  }
+
+  // All channels are supported in release builds.
+  switch (*release_channel) {
+    case version_info::Channel::CANARY:
+    case version_info::Channel::DEV:
+    case version_info::Channel::BETA:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
 #endif  // BUILDFLAG(IS_ANDROID)
 
 }  // namespace
diff --git a/chrome/elevation_service/elevator.cc b/chrome/elevation_service/elevator.cc
index 1eff2df..bd24f7f 100644
--- a/chrome/elevation_service/elevator.cc
+++ b/chrome/elevation_service/elevator.cc
@@ -33,6 +33,20 @@
 
 namespace elevation_service {
 
+namespace {
+
+ProtectionLevel RemoveFlags(ProtectionLevel protection_level,
+                            EncryptFlags& flags) {
+  const uint32_t flag_value = internal::ExtractFlags(protection_level);
+  if (flag_value & internal::kFlagUseLatestKey) {
+    flags.use_latest_key = true;
+  }
+  return static_cast<ProtectionLevel>(
+      internal::ExtractProtectionLevel(protection_level));
+}
+
+}  // namespace
+
 HRESULT Elevator::RunRecoveryCRXElevated(const wchar_t* crx_path,
                                          const wchar_t* browser_appid,
                                          const wchar_t* browser_version,
@@ -51,6 +65,9 @@
                               const BSTR plaintext,
                               BSTR* ciphertext,
                               DWORD* last_error) {
+  EncryptFlags flags;
+  protection_level = RemoveFlags(protection_level, flags);
+
   if (protection_level >= ProtectionLevel::PROTECTION_MAX) {
     return kErrorUnsupportedProtectionLevel;
   }
diff --git a/chrome/elevation_service/elevator.h b/chrome/elevation_service/elevator.h
index 4e8f8d0..5b9bc81 100644
--- a/chrome/elevation_service/elevator.h
+++ b/chrome/elevation_service/elevator.h
@@ -16,6 +16,14 @@
 
 namespace elevation_service {
 
+// These flags can modify the EncryptData operation. They are packed inside the
+// `protection_level` argument. Access these via the `EncryptAppBoundString` API
+// in chrome.
+struct EncryptFlags {
+  // Specify that the Encrypt operation should always use the latest key.
+  bool use_latest_key = false;
+};
+
 constexpr IID kTestElevatorClsid = {
     0x416C51AC,
     0x4DEF,
@@ -29,6 +37,46 @@
     "elevator-fake-reencrypt-for-testing";
 }  // namespace switches
 
+namespace internal {
+
+constexpr uint32_t kFlagUseLatestKey = 1 << 23;
+
+// Update this each time a new flag is added.
+constexpr uint32_t kMaxFlag = kFlagUseLatestKey;
+
+// A static assert verifies the flags can always fit into 24 bits.
+static_assert((kMaxFlag & 0xFFFFFF) == kMaxFlag);
+
+constexpr uint32_t PackFlagsAndProtectionLevel(uint32_t flags,
+                                               uint8_t protection_level) {
+  return ((flags & 0xFFFFFF) << 8) | protection_level;
+}
+
+constexpr uint32_t ExtractFlags(uint32_t packed) {
+  return (packed >> 8) & 0xFFFFFF;
+}
+
+constexpr uint8_t ExtractProtectionLevel(uint32_t packed) {
+  return static_cast<uint8_t>(packed & 0xFF);
+}
+
+// Tests for these basic functions can be static asserts.
+static_assert(ExtractProtectionLevel(PackFlagsAndProtectionLevel(0, 0)) == 0);
+static_assert(ExtractFlags(PackFlagsAndProtectionLevel(0x123456, 0x01)) ==
+              0x123456);
+static_assert(ExtractFlags(PackFlagsAndProtectionLevel(0xAA123456, 0)) ==
+              0x123456);
+static_assert(ExtractFlags(PackFlagsAndProtectionLevel(0, 0)) == 0);
+static_assert(ExtractProtectionLevel(PackFlagsAndProtectionLevel(0, 0x01)) ==
+              0x01);
+static_assert(
+    ExtractProtectionLevel(PackFlagsAndProtectionLevel(0x1234, 0x01)) == 0x01);
+static_assert(ExtractProtectionLevel(PackFlagsAndProtectionLevel(0x12345678,
+                                                                 0x01)) ==
+              0x01);
+
+}  // namespace internal
+
 class Elevator
     : public Microsoft::WRL::RuntimeClass<
           Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2eb68c25..e95f3d6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1475,6 +1475,7 @@
       "../browser/banners/app_banner_manager_browsertest.cc",
       "../browser/browsing_data/chrome_browsing_data_lifetime_manager_browsertest.cc",
       "../browser/engagement/important_sites_util_browsertest.cc",
+      "../browser/enterprise/data_controls/android_data_controls_dialog_browsertest.cc",
       "../browser/enterprise/reporting/cloud_profile_reporting_browsertest.cc",
       "../browser/fast_checkout/fast_checkout_tab_helper_browsertest.cc",
       "../browser/feed/rss_links_fetcher_browsertest.cc",
@@ -1535,6 +1536,7 @@
       "//chrome/browser/browsing_data:constants",
       "//chrome/browser/content_settings:content_settings_factory",
       "//chrome/browser/dips:browser_tests",
+      "//chrome/browser/enterprise/data_controls:data_controls",
       "//chrome/browser/fast_checkout:test_support",
       "//chrome/browser/flags:flags_android",
       "//chrome/browser/ip_protection:browser_tests",
@@ -6378,7 +6380,6 @@
     "//chrome/browser/ui/page_info:unit_tests",
     "//chrome/browser/ui/safety_hub:test_support",
     "//chrome/browser/ui/webui",
-    "//chrome/browser/ui/webui:webui_util",
     "//chrome/browser/ui/webui/internal_debug_pages_disabled",
     "//chrome/browser/updates/announcement_notification:unit_tests",
     "//chrome/browser/web_share_target:unit_tests",
@@ -7758,6 +7759,7 @@
       "//chrome/browser/ui/tabs:test_support",
       "//chrome/browser/ui/tabs:unit_tests",
       "//chrome/browser/ui/views/webid:test_support",
+      "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/settings",
       "//chrome/browser/ui/webui/signin:unit_tests",
       "//components/autofill_ai/core/browser:browser",
@@ -10214,7 +10216,6 @@
       "//chrome/browser/ui/signin",
       "//chrome/browser/ui/views/toolbar",
       "//chrome/browser/ui/webui",
-      "//chrome/browser/ui/webui:webui_util",
       "//chrome/browser/ui/webui/signin",
       "//chrome/browser/ui/webui/whats_new",
       "//chrome/browser/web_applications",
@@ -10292,6 +10293,7 @@
       "//ui/views",
       "//ui/views:test_support",
       "//ui/views/controls/webview",
+      "//ui/webui",
     ]
 
     if (use_ozone) {
diff --git a/chrome/test/base/ash/interactive/wifi/wifi_interactive_uitest.cc b/chrome/test/base/ash/interactive/wifi/wifi_interactive_uitest.cc
index 978de2b..7671de1 100644
--- a/chrome/test/base/ash/interactive/wifi/wifi_interactive_uitest.cc
+++ b/chrome/test/base/ash/interactive/wifi/wifi_interactive_uitest.cc
@@ -26,6 +26,7 @@
 #include "ui/base/interaction/state_observer.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/strings/grit/ui_chromeos_strings.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/button/toggle_button.h"
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/interaction/polling_view_observer.h"
@@ -46,6 +47,10 @@
   using NetworkNameObserver =
       views::test::PollingViewObserver<bool, views::View>;
 
+  using ToggleAccessibilityCheckedStateObserver =
+      views::test::PollingViewObserver<ax::mojom::CheckedState,
+                                       views::ToggleButton>;
+
   // InteractiveAshTest:
   void SetUpOnMainThread() override {
     InteractiveAshTest::SetUpOnMainThread();
@@ -137,6 +142,20 @@
         base::Milliseconds(50)));
   }
 
+  auto PollToggleAccessibilityCheckedState(
+      const ui::test::StateIdentifier<ToggleAccessibilityCheckedStateObserver>&
+          polling_identifier) {
+    return Steps(PollView(
+        polling_identifier, kNetworkDetailedViewWifiToggleElementId,
+        [&](const views::ToggleButton* toggle_button)
+            -> ax::mojom::CheckedState {
+          ui::AXNodeData data;
+          toggle_button->GetViewAccessibility().GetAccessibleNodeData(&data);
+          return data.GetCheckedState();
+        },
+        base::Milliseconds(500)));
+  }
+
  private:
   const ShillServiceInfo wifi_service_info_{/*id=*/0, shill::kTypeWifi};
 };
@@ -217,6 +236,8 @@
                                       kWifiPoweredState);
   DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ToggleObserver, kToggleButtonState);
   DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(NetworkNameObserver, kNetworkInListState);
+  DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ToggleAccessibilityCheckedStateObserver,
+                                      kToggleAccessibilityCheckedState);
 
   ConfigureWifi(/*connected=*/true);
 
@@ -233,6 +254,7 @@
                        kNetworkDetailedViewWifiToggleElementId,
                        &views::ToggleButton::GetIsOn),
       PollNetworkInList(WifiServiceName(), kNetworkInListState),
+      PollToggleAccessibilityCheckedState(kToggleAccessibilityCheckedState),
 
       Log("Opening the Quick Settings bubble and navigating to the network "
           "page"),
@@ -244,6 +266,8 @@
 
       WaitForShow(kNetworkDetailedViewWifiToggleElementId),
       VerifyWifiState(/*enabled=*/true, kWifiPoweredState, kToggleButtonState),
+      WaitForState(kToggleAccessibilityCheckedState,
+                   ax::mojom::CheckedState::kTrue),
 
       Log("Verify the WiFi service in the network list"),
 
@@ -257,6 +281,8 @@
       Log("Wait for WiFi to have the expected disabled state"),
 
       VerifyWifiState(/*enabled=*/false, kWifiPoweredState, kToggleButtonState),
+      WaitForState(kToggleAccessibilityCheckedState,
+                   ax::mojom::CheckedState::kFalse),
 
       Log("Re-enable WiFi"),
 
@@ -266,6 +292,8 @@
       Log("Wait for WiFi to have the expected enabled state"),
 
       VerifyWifiState(/*enabled=*/true, kWifiPoweredState, kToggleButtonState),
+      WaitForState(kToggleAccessibilityCheckedState,
+                   ax::mojom::CheckedState::kTrue),
 
       Log("Verify the WiFi service in the network list"),
 
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index f1d5067..6f343e5 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -114,20 +114,22 @@
   kiosk_chrome_app_manager_ = std::make_unique<ash::KioskChromeAppManager>();
 #endif
 
-  // Subclasses can provide their own Profile.
-  std::string profile_name = GetDefaultProfileName();
+  // Subclasses can provide their own Profile name.
+  std::optional<std::string> profile_name = GetDefaultProfileName();
+  if (profile_name) {
 #if BUILDFLAG(IS_CHROMEOS)
-  LogIn(profile_name);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  SwitchActiveUser(profile_name);
+    LogIn(*profile_name);
 #endif
+    profile_ = CreateProfile(*profile_name);
+#if BUILDFLAG(IS_CHROMEOS)
+    SwitchActiveUser(*profile_name);
 #endif
-  profile_ = CreateProfile(profile_name);
 
-  window_ = CreateBrowserWindow();
+    window_ = CreateBrowserWindow();
 
-  browser_ =
-      CreateBrowser(profile(), browser_type_, hosted_app_, window_.get());
+    browser_ =
+        CreateBrowser(profile(), browser_type_, hosted_app_, window_.get());
+  }
 }
 
 void BrowserWithTestWindowTest::TearDown() {
@@ -254,7 +256,7 @@
   content::FocusWebContentsOnFrame(contents, contents->GetPrimaryMainFrame());
 }
 
-std::string BrowserWithTestWindowTest::GetDefaultProfileName() {
+std::optional<std::string> BrowserWithTestWindowTest::GetDefaultProfileName() {
   return TestingProfile::kDefaultProfileUserName;
 }
 
@@ -311,7 +313,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 void BrowserWithTestWindowTest::LogIn(const std::string& email) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   const AccountId account_id = AccountId::FromUserEmail(email);
   user_manager_->AddUser(account_id);
   ash_test_helper()->test_session_controller_client()->AddUserSession(email);
@@ -320,7 +321,6 @@
       user_manager::FakeUserManager::GetFakeUsernameHash(account_id),
       /*browser_restart=*/false,
       /*is_child=*/false);
-#endif
 }
 #endif
 
diff --git a/chrome/test/base/browser_with_test_window_test.h b/chrome/test/base/browser_with_test_window_test.h
index 68e6d583..837178d9 100644
--- a/chrome/test/base/browser_with_test_window_test.h
+++ b/chrome/test/base/browser_with_test_window_test.h
@@ -6,6 +6,7 @@
 #define CHROME_TEST_BASE_BROWSER_WITH_TEST_WINDOW_TEST_H_
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 #include "base/compiler_specific.h"
@@ -206,9 +207,9 @@
   void FocusMainFrameOfActiveWebContents();
 
   // Returns the profile name used for the profile created in SetUp() by
-  // default.
-  // Subclasses can override to change the profile name.
-  virtual std::string GetDefaultProfileName();
+  // default.  Subclasses can override to change the profile name. If it returns
+  // std::nullopt, this will skip creating profile and browser window.
+  virtual std::optional<std::string> GetDefaultProfileName();
 
   // Creates the profile used by this test. The caller doesn't own the return
   // value.
diff --git a/chrome/test/data/autofill/captured_sites/artifacts b/chrome/test/data/autofill/captured_sites/artifacts
index 4fe29ba..8c66a34 160000
--- a/chrome/test/data/autofill/captured_sites/artifacts
+++ b/chrome/test/data/autofill/captured_sites/artifacts
@@ -1 +1 @@
-Subproject commit 4fe29ba42dfd45c824c4623ecb5335bd82d6bad0
+Subproject commit 8c66a34eccf070d66903db5db487bc1de597e7c6
diff --git a/chrome/test/data/pdf/BUILD.gn b/chrome/test/data/pdf/BUILD.gn
index 33fb66e..5029388 100644
--- a/chrome/test/data/pdf/BUILD.gn
+++ b/chrome/test/data/pdf/BUILD.gn
@@ -61,11 +61,11 @@
 
   if (enable_pdf_ink2) {
     files += [
-      "ink2_brush_selector_test.ts",
       "ink2_before_unload_stroke_test.ts",
       "ink2_before_unload_undo_test.ts",
       "ink2_bottom_toolbar_dropdown_test.ts",
       "ink2_bottom_toolbar_test.ts",
+      "ink2_brush_selector_test.ts",
       "ink2_color_selector_test.ts",
       "ink2_save_test.ts",
       "ink2_side_panel_test.ts",
diff --git a/chrome/test/data/webui/app_settings/BUILD.gn b/chrome/test/data/webui/app_settings/BUILD.gn
index f7b6942..de138334 100644
--- a/chrome/test/data/webui/app_settings/BUILD.gn
+++ b/chrome/test/data/webui/app_settings/BUILD.gn
@@ -12,10 +12,10 @@
   files = [
     "app_management_test_support.ts",
     "app_test.ts",
-    "test_app_management_browser_proxy.ts",
     "file_handling_item_test.ts",
     "permission_item_test.ts",
     "supported_links_item_test.ts",
+    "test_app_management_browser_proxy.ts",
     "uninstall_button_test.ts",
     "window_mode_item_test.ts",
   ]
diff --git a/chrome/test/data/webui/bookmarks/BUILD.gn b/chrome/test/data/webui/bookmarks/BUILD.gn
index 5259c958..fa590bf 100644
--- a/chrome/test/data/webui/bookmarks/BUILD.gn
+++ b/chrome/test/data/webui/bookmarks/BUILD.gn
@@ -38,8 +38,8 @@
                            "$root_gen_dir/chrome/browser/resources/bookmarks/tsc/bookmarks.d.ts",
                            target_gen_dir) ]
   ts_definitions = [
-    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/bookmark_manager_private.d.ts",
+    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/runtime.d.ts",
     "//tools/typescript/definitions/tabs.d.ts",
diff --git a/chrome/test/data/webui/chromeos/diagnostics/wifi_info_test.ts b/chrome/test/data/webui/chromeos/diagnostics/wifi_info_test.ts
index a9c5611..99be297b 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/wifi_info_test.ts
+++ b/chrome/test/data/webui/chromeos/diagnostics/wifi_info_test.ts
@@ -27,7 +27,8 @@
     wifiInfoElement = null;
   });
 
-  function initializeWifiInfo(network = fakeWifiNetwork): Promise<void> {
+  function initializeWifiInfo(network: Network = fakeWifiNetwork):
+      Promise<void> {
     // Add the wifi info to the DOM.
     wifiInfoElement = document.createElement('wifi-info');
     assert(wifiInfoElement);
diff --git a/chrome/test/data/webui/chromeos/settings/BUILD.gn b/chrome/test/data/webui/chromeos/settings/BUILD.gn
index b41a5b1..f450041 100644
--- a/chrome/test/data/webui/chromeos/settings/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/settings/BUILD.gn
@@ -21,6 +21,7 @@
   files = [
     "fake_canvas_context.ts",
     "fake_input_method_private.ts",
+    "fake_in_session_auth.ts",
     "fake_language_settings_private.ts",
     "fake_media_devices.ts",
     "fake_metrics_private.ts",
diff --git a/chrome/test/data/webui/chromeos/settings/fake_in_session_auth.ts b/chrome/test/data/webui/chromeos/settings/fake_in_session_auth.ts
new file mode 100644
index 0000000..4193a4d
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/settings/fake_in_session_auth.ts
@@ -0,0 +1,44 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Fake implementation of InSessionAuth for testing.
+ */
+
+import {RequestTokenReply} from 'chrome://resources/mojo/chromeos/components/in_session_auth/mojom/in_session_auth.mojom-webui.js';
+
+/**
+ * Fake implementation of TimeDelta used inside the InSessionAuth token reply
+ * timeout.
+ */
+class TimeDelta {
+  microseconds: bigint;
+
+  constructor(microseconds: bigint) {
+    this.microseconds = microseconds;
+  }
+}
+
+/**
+ * Fake implementation of InSessionAuthInterface
+ */
+export class FakeInSessionAuth {
+  tokenReply_: RequestTokenReply|null;
+
+  constructor() {
+    this.tokenReply_ = { token: 'token', timeout: new TimeDelta(BigInt(1000)) }
+  }
+
+  requestToken(): {reply: null|RequestTokenReply} {
+    return {reply: this.tokenReply_};
+  }
+
+  checkToken(): boolean {
+    return true;
+  }
+
+  invalidateToken() {
+    this.tokenReply_ = null;
+  }
+}
diff --git a/chrome/test/data/webui/chromeos/settings/multidevice_page/multidevice_page_test.ts b/chrome/test/data/webui/chromeos/settings/multidevice_page/multidevice_page_test.ts
index 1173241..a2d738e 100644
--- a/chrome/test/data/webui/chromeos/settings/multidevice_page/multidevice_page_test.ts
+++ b/chrome/test/data/webui/chromeos/settings/multidevice_page/multidevice_page_test.ts
@@ -18,6 +18,8 @@
 import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
 
+import {FakeInSessionAuth} from '../fake_in_session_auth.js';
+
 import {createFakePageContentData, HOST_DEVICE, TestMultideviceBrowserProxy} from './test_multidevice_browser_proxy.js';
 
 suite('<settings-multidevice-page>', () => {
@@ -160,7 +162,9 @@
     }));
     flush();
 
-    if (authRequired) {
+    // The password prompt dialog should only be triggered when
+    // isAuthPanelEnabled is false.
+    if (authRequired && !loadTimeData.getBoolean('isAuthPanelEnabled')) {
       assertTrue(multidevicePage.get('showPasswordPromptDialog_'));
       const prompt = multidevicePage.shadowRoot!.querySelector(
           '#multidevicePasswordPrompt');
@@ -233,6 +237,9 @@
     document.body.appendChild(multidevicePage);
     flush();
     await browserProxy.whenCalled('getPageContentData');
+
+    multidevicePage.set(
+        'fakeInSessionAuthForTesting_', new FakeInSessionAuth());
   }
 
   setup(async () => {
diff --git a/chrome/test/data/webui/commerce/product_specifications/BUILD.gn b/chrome/test/data/webui/commerce/product_specifications/BUILD.gn
index b6c75d5..cf9917c 100644
--- a/chrome/test/data/webui/commerce/product_specifications/BUILD.gn
+++ b/chrome/test/data/webui/commerce/product_specifications/BUILD.gn
@@ -8,8 +8,8 @@
   files = [
     "app_test.ts",
     "buying_options_section_test.ts",
-    "comparison_table_list_test.ts",
     "comparison_table_list_item_test.ts",
+    "comparison_table_list_test.ts",
     "description_citation_test.ts",
     "description_section_test.ts",
     "disclosure_app_test.ts",
diff --git a/chrome/test/data/webui/commerce/product_specifications/app_test.ts b/chrome/test/data/webui/commerce/product_specifications/app_test.ts
index d819ad1..cefac4ef 100644
--- a/chrome/test/data/webui/commerce/product_specifications/app_test.ts
+++ b/chrome/test/data/webui/commerce/product_specifications/app_test.ts
@@ -5,6 +5,7 @@
 import 'chrome://compare/app.js';
 
 import {CrFeedbackOption} from '//resources/cr_elements/cr_feedback_buttons/cr_feedback_buttons.js';
+import {PluralStringProxyImpl} from '//resources/js/plural_string_proxy.js';
 import {COLUMN_MODIFICATION_HISTOGRAM_NAME, CompareTableColumnAction, CompareTableLoadStatus, LOADING_END_EVENT_TYPE, LOADING_START_EVENT_TYPE, TABLE_LOAD_HISTOGRAM_NAME} from 'chrome://compare/app.js';
 import type {ProductSpecificationsElement} from 'chrome://compare/app.js';
 import type {ProductSelectorElement} from 'chrome://compare/product_selector.js';
@@ -19,12 +20,14 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {stringToMojoUrl} from 'chrome://resources/js/mojo_type_util.js';
 import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
+import type {Uuid} from 'chrome://resources/mojo/mojo/public/mojom/base/uuid.mojom-webui.js';
 import type {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js';
 import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js';
 import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {TestMock} from 'chrome://webui-test/test_mock.js';
+import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
 import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';
 
 import {$$, installMock} from './test_support.js';
@@ -2292,4 +2295,182 @@
       assertEquals('chrome://settings/syncSetup/advanced', arg);
     });
   });
+
+  suite('Comparison table list', () => {
+    setup(() => {
+      // Used by the item elements in the list.
+      const pluralStringProxy = new TestPluralStringProxy();
+      PluralStringProxyImpl.setInstance(pluralStringProxy);
+
+      loadTimeData.overrideValues({
+        'comparisonTableListEnabled': true,
+      });
+
+      shoppingServiceApi.setResultFor(
+          'getAllProductSpecificationsSets', Promise.resolve({
+            sets: [
+              {
+                name: 'abc',
+                uuid: {value: '123'},
+                urls: [
+                  {url: 'http://example1.com'},
+                  {url: 'http://example2.com'},
+                ],
+              },
+              {
+                name: 'xyz',
+                uuid: {value: '456'},
+                urls: [{url: 'http://example3.com'}],
+              },
+            ],
+          }));
+      shoppingServiceApi.setResultMapperFor(
+          'getProductInfoForUrl', (url: Url) => {
+            return Promise.resolve({
+              productInfo: {
+                imageUrl: {url: `${url.url}/image.png`},
+              },
+            });
+          });
+
+      productSpecificationsProxy.setResultMapperFor(
+          'getComparisonTableUrlForUuid', (uuid: Uuid) => {
+            return Promise.resolve(`chrome://compare/?id=${uuid.value}`);
+          });
+    });
+
+    test('list does not appear when the feature is off', async () => {
+      loadTimeData.overrideValues({
+        'comparisonTableListEnabled': false,
+      });
+
+      const appElement = await createAppElement();
+      await flushTasks();
+
+      const listElement = appElement.$.comparisonTableList;
+      assertFalse(isVisible(listElement));
+    });
+
+    test('list is hidden if there are no comparison tables', async () => {
+      shoppingServiceApi.setResultFor(
+          'getAllProductSpecificationsSets', Promise.resolve({sets: []}));
+
+      const appElement = await createAppElement();
+      await flushTasks();
+
+      const listElement = appElement.$.comparisonTableList;
+      assertFalse(isVisible(listElement));
+    });
+
+    test(
+        'list displays available tables and uses first product image',
+        async () => {
+          const appElement = await createAppElement();
+          await flushTasks();
+
+          const listElement = appElement.$.comparisonTableList;
+          assertArrayEquals(
+              [
+                {
+                  name: 'abc',
+                  uuid: {value: '123'},
+                  numUrls: 2,
+                  imageUrl: {url: 'http://example1.com/image.png'},
+                },
+                {
+                  name: 'xyz',
+                  uuid: {value: '456'},
+                  numUrls: 1,
+                  imageUrl: {url: 'http://example3.com/image.png'},
+                },
+              ],
+              listElement.tables);
+        });
+
+    test('list updates on set updated', async () => {
+      const appElement = await createAppElement();
+      await flushTasks();
+
+      callbackRouterRemote.onProductSpecificationsSetUpdated({
+        name: 'def',
+        uuid: {value: '123'},
+        urls: [{url: 'http://example2.com'}],
+      });
+      await flushTasks();
+
+      const listElement = appElement.$.comparisonTableList;
+      assertArrayEquals(
+          [
+            {
+              name: 'def',
+              uuid: {value: '123'},
+              numUrls: 1,
+              imageUrl: {url: 'http://example2.com/image.png'},
+            },
+            {
+              name: 'xyz',
+              uuid: {value: '456'},
+              numUrls: 1,
+              imageUrl: {url: 'http://example3.com/image.png'},
+            },
+          ],
+          listElement.tables);
+    });
+
+    test('list updates on set added', async () => {
+      const appElement = await createAppElement();
+      await flushTasks();
+
+      callbackRouterRemote.onProductSpecificationsSetAdded({
+        name: 'def',
+        uuid: {value: '789'},
+        urls: [{url: 'http://example5.com'}],
+      });
+      await flushTasks();
+
+      const listElement = appElement.$.comparisonTableList;
+      assertArrayEquals(
+          [
+            {
+              name: 'def',
+              uuid: {value: '789'},
+              numUrls: 1,
+              imageUrl: {url: 'http://example5.com/image.png'},
+            },
+            {
+              name: 'abc',
+              uuid: {value: '123'},
+              numUrls: 2,
+              imageUrl: {url: 'http://example1.com/image.png'},
+            },
+            {
+              name: 'xyz',
+              uuid: {value: '456'},
+              numUrls: 1,
+              imageUrl: {url: 'http://example3.com/image.png'},
+            },
+          ],
+          listElement.tables);
+    });
+
+    test('list updates on set removed', async () => {
+      const appElement = await createAppElement();
+      await flushTasks();
+
+      callbackRouterRemote.onProductSpecificationsSetRemoved({value: '123'});
+      await flushTasks();
+
+      const listElement = appElement.$.comparisonTableList;
+      assertArrayEquals(
+          [
+            {
+              name: 'xyz',
+              uuid: {value: '456'},
+              numUrls: 1,
+              imageUrl: {url: 'http://example3.com/image.png'},
+            },
+          ],
+          listElement.tables);
+    });
+  });
 });
diff --git a/chrome/test/data/webui/compose/BUILD.gn b/chrome/test/data/webui/compose/BUILD.gn
index 88576510..7c37495 100644
--- a/chrome/test/data/webui/compose/BUILD.gn
+++ b/chrome/test/data/webui/compose/BUILD.gn
@@ -8,12 +8,12 @@
   is_chrome_untrusted = true
   files = [
     "compose_animator_test.ts",
+    "compose_app_focus_test.ts",
     "compose_app_test.ts",
     "compose_textarea_test.ts",
     "result_text_test.ts",
-    "word_streamer_test.ts",
-    "compose_app_focus_test.ts",
     "test_compose_api_proxy.ts",
+    "word_streamer_test.ts",
   ]
 
   ts_path_mappings =
diff --git a/chrome/test/data/webui/cr_components/BUILD.gn b/chrome/test/data/webui/cr_components/BUILD.gn
index de1bcea..713fa861 100644
--- a/chrome/test/data/webui/cr_components/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/BUILD.gn
@@ -12,10 +12,10 @@
     "customize_color_scheme_mode_test.ts",
     "localized_link_test.ts",
     "managed_dialog_test.ts",
+    "managed_footnote_test.ts",
     "most_visited_focus_test.ts",
     "most_visited_test.ts",
     "most_visited_test_support.ts",
-    "managed_footnote_test.ts",
   ]
 
   ts_definitions = [
diff --git a/chrome/test/data/webui/cr_components/certificate_manager/BUILD.gn b/chrome/test/data/webui/cr_components/certificate_manager/BUILD.gn
index e24201a..0aa0f58 100644
--- a/chrome/test/data/webui/cr_components/certificate_manager/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/certificate_manager/BUILD.gn
@@ -28,8 +28,8 @@
       "certificate_manager_v2_test_support.ts",
       "certificate_password_dialog_test.ts",
       "certificate_subpage_v2_test.ts",
-      "navigation_v2_test.ts",
       "local_certs_section_v2_test.ts",
+      "navigation_v2_test.ts",
     ]
   }
 
diff --git a/chrome/test/data/webui/cr_components/help_bubble/BUILD.gn b/chrome/test/data/webui/cr_components/help_bubble/BUILD.gn
index e75033f..82a72db4 100644
--- a/chrome/test/data/webui/cr_components/help_bubble/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/help_bubble/BUILD.gn
@@ -8,8 +8,8 @@
 
 build_webui_tests("build") {
   files = [
-    "help_bubble_mixin_test.ts",
     "help_bubble_mixin_lit_test.ts",
+    "help_bubble_mixin_test.ts",
     "help_bubble_test.ts",
   ]
 
diff --git a/chrome/test/data/webui/cr_components/searchbox/BUILD.gn b/chrome/test/data/webui/cr_components/searchbox/BUILD.gn
index 2a77b0d..6e6ec93 100644
--- a/chrome/test/data/webui/cr_components/searchbox/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/searchbox/BUILD.gn
@@ -10,8 +10,8 @@
   files = [
     "searchbox_lens_test.ts",
     "searchbox_match_test.ts",
-    "searchbox_test_utils.ts",
     "searchbox_test.ts",
+    "searchbox_test_utils.ts",
     "test_searchbox_browser_proxy.ts",
   ]
 
diff --git a/chrome/test/data/webui/cr_components/theme_color_picker/BUILD.gn b/chrome/test/data/webui/cr_components/theme_color_picker/BUILD.gn
index 2349c6da..6b41825 100644
--- a/chrome/test/data/webui/cr_components/theme_color_picker/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/theme_color_picker/BUILD.gn
@@ -9,8 +9,8 @@
 build_webui_tests("build") {
   files = [
     "check_mark_wrapper_test.ts",
-    "theme_color_test.ts",
     "theme_color_picker_test.ts",
+    "theme_color_test.ts",
     "theme_hue_slider_dialog_test.ts",
   ]
 
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn
index f51a302..e56fc741 100644
--- a/chrome/test/data/webui/cr_elements/BUILD.gn
+++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -17,8 +17,8 @@
     "cr_checkbox_test.ts",
     "cr_chip_test.ts",
     "cr_collapse_test.ts",
-    "cr_container_shadow_mixin_test.ts",
     "cr_container_shadow_mixin_lit_test.ts",
+    "cr_container_shadow_mixin_test.ts",
     "cr_dialog_test.ts",
     "cr_drawer_test.ts",
     "cr_expand_button_test.ts",
@@ -32,8 +32,8 @@
     "cr_infinite_list_test.ts",
     "cr_input_test.ts",
     "cr_lazy_list_test.ts",
-    "cr_lazy_render_test.ts",
     "cr_lazy_render_lit_test.ts",
+    "cr_lazy_render_test.ts",
     "cr_link_row_test.ts",
     "cr_lit_element_test.ts",
     "cr_loading_gradient_test.ts",
@@ -48,8 +48,8 @@
     "cr_ripple_mixin_polymer_test.ts",
     "cr_ripple_mixin_test.ts",
     "cr_ripple_test.ts",
-    "cr_scroll_observer_mixin_test.ts",
     "cr_scroll_observer_mixin_lit_test.ts",
+    "cr_scroll_observer_mixin_test.ts",
     "cr_search_field_test.ts",
     "cr_selectable_mixin_test.ts",
     "cr_slider_test.ts",
@@ -66,16 +66,16 @@
     "cr_tree_test.ts",
     "cr_url_list_item_test.ts",
     "cr_view_manager_test.ts",
-    "find_shortcut_mixin_test.ts",
     "find_shortcut_mixin_lit_test.ts",
+    "find_shortcut_mixin_test.ts",
     "focus_row_mixin_lit_test.ts",
-    "i18n_mixin_test.ts",
     "i18n_mixin_lit_test.ts",
+    "i18n_mixin_test.ts",
     "iron_list_focus_test.ts",
     "list_property_update_mixin_test.ts",
     "store_client_test.ts",
-    "web_ui_listener_mixin_test.ts",
     "web_ui_listener_mixin_lit_test.ts",
+    "web_ui_listener_mixin_test.ts",
   ]
 
   ts_composite = true
diff --git a/chrome/test/data/webui/extensions/BUILD.gn b/chrome/test/data/webui/extensions/BUILD.gn
index 0662bac4..12dd6f0 100644
--- a/chrome/test/data/webui/extensions/BUILD.gn
+++ b/chrome/test/data/webui/extensions/BUILD.gn
@@ -10,12 +10,12 @@
 
 build_webui_tests("build") {
   files = [
-    "toolbar_test.ts",
     "activity_log_history_item_test.ts",
     "activity_log_history_test.ts",
     "activity_log_stream_item_test.ts",
     "activity_log_stream_test.ts",
     "activity_log_test.ts",
+    "async_map_directive_test.ts",
     "code_section_test.ts",
     "detail_view_test.ts",
     "error_console_test.ts",
@@ -31,13 +31,12 @@
     "manager_test_with_id_query_param.ts",
     "manager_unit_test.ts",
     "manager_unit_test_with_activity_log_flag.ts",
-    "mv2_deprecation_panel_warning_test.ts",
     "mv2_deprecation_panel_disabled_test.ts",
     "mv2_deprecation_panel_unsupported_test.ts",
+    "mv2_deprecation_panel_warning_test.ts",
     "navigation_helper_test.ts",
     "options_dialog_test.ts",
     "pack_dialog_test.ts",
-    "async_map_directive_test.ts",
     "review_panel_test.ts",
     "runtime_host_permissions_test.ts",
     "runtime_hosts_dialog_test.ts",
@@ -52,6 +51,7 @@
     "test_service.ts",
     "test_util.ts",
     "toggle_row_test.ts",
+    "toolbar_test.ts",
     "url_util_test.ts",
   ]
 
@@ -67,8 +67,8 @@
   ]
   ts_definitions = [
     "//tools/typescript/definitions/activity_log_private.d.ts",
-    "//tools/typescript/definitions/developer_private.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
+    "//tools/typescript/definitions/developer_private.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
   ]
 }
diff --git a/chrome/test/data/webui/js/BUILD.gn b/chrome/test/data/webui/js/BUILD.gn
index 00f45f6..02c74e7 100644
--- a/chrome/test/data/webui/js/BUILD.gn
+++ b/chrome/test/data/webui/js/BUILD.gn
@@ -7,6 +7,7 @@
 build_webui_tests("build") {
   files = [
     "color_utils_test.ts",
+    "cr_router_test.ts",
     "cr_test.ts",
     "custom_element_test.ts",
     "icon_test.ts",
@@ -16,7 +17,6 @@
     "parse_html_subset_test.ts",
     "parse_html_subset_trusted_types_test.ts",
     "promise_resolver_test.ts",
-    "cr_router_test.ts",
     "static_types_test.ts",
     "store_test.ts",
     "test_suite_self_test.ts",
diff --git a/chrome/test/data/webui/lens/BUILD.gn b/chrome/test/data/webui/lens/BUILD.gn
index 52623576..90f52cabd 100644
--- a/chrome/test/data/webui/lens/BUILD.gn
+++ b/chrome/test/data/webui/lens/BUILD.gn
@@ -9,15 +9,17 @@
   files = [
     "ghost_loader/ghost_loader_state_test.ts",
     "ghost_loader/test_ghost_loader_browser_proxy.ts",
+    "overlay/cubic_bezier_test.ts",
     "overlay/find_words_in_region_test.ts",
     "overlay/object_selection_test.ts",
     "overlay/overlay_background_scrim_test.ts",
     "overlay/overlay_close_button_test.ts",
-    "overlay/performance_tracker_test.ts",
     "overlay/overlay_cursor_test.ts",
     "overlay/overlay_more_options_button_test.ts",
     "overlay/overlay_screenshot_test.ts",
+    "overlay/overlay_show_translate_promo_test.ts",
     "overlay/overlay_theme_test.ts",
+    "overlay/performance_tracker_test.ts",
     "overlay/post_selection_renderer_test.ts",
     "overlay/region_selection_test.ts",
     "overlay/searchbox_test.ts",
@@ -25,16 +27,14 @@
     "overlay/test_language_browser_proxy.ts",
     "overlay/test_overlay_browser_proxy.ts",
     "overlay/text_selection_test.ts",
-    "overlay/cubic_bezier_test.ts",
     "overlay/translate_button_test.ts",
-    "overlay/overlay_show_translate_promo_test.ts",
+    "side_panel/error_page_test.ts",
+    "side_panel/ghost_loader_state_test.ts",
     "side_panel/results_frame_test.ts",
     "side_panel/searchbox_back_button_test.ts",
     "side_panel/test_side_panel_browser_proxy.ts",
-    "side_panel/error_page_test.ts",
-    "side_panel/ghost_loader_state_test.ts",
-    "utils/object_utils.ts",
     "utils/image_utils.ts",
+    "utils/object_utils.ts",
     "utils/selection_utils.ts",
     "utils/text_utils.ts",
   ]
diff --git a/chrome/test/data/webui/metrics_internals/BUILD.gn b/chrome/test/data/webui/metrics_internals/BUILD.gn
index ebe9ab7..f4b7a48 100644
--- a/chrome/test/data/webui/metrics_internals/BUILD.gn
+++ b/chrome/test/data/webui/metrics_internals/BUILD.gn
@@ -6,10 +6,10 @@
 
 build_webui_tests("build") {
   files = [
-    "no_logs_test.ts",
-    "with_log_test.ts",
-    "utils.ts",
     "field_trials_test.ts",
+    "no_logs_test.ts",
+    "utils.ts",
+    "with_log_test.ts",
   ]
 
   ts_path_mappings =
diff --git a/chrome/test/data/webui/password_manager/BUILD.gn b/chrome/test/data/webui/password_manager/BUILD.gn
index 71d5b502..9c19d230 100644
--- a/chrome/test/data/webui/password_manager/BUILD.gn
+++ b/chrome/test/data/webui/password_manager/BUILD.gn
@@ -11,13 +11,13 @@
     "add_password_dialog_test.ts",
     "checkup_details_section_test.ts",
     "checkup_section_test.ts",
-    "delete_passkey_dialog_test.ts",
-    "full_data_reset_test.ts",
-    "edit_password_dialog_test.ts",
-    "edit_passkey_dialog_test.ts",
-    "move_passwords_dialog_test.ts",
     "credential_field_test.ts",
     "credential_note_test.ts",
+    "delete_passkey_dialog_test.ts",
+    "edit_passkey_dialog_test.ts",
+    "edit_password_dialog_test.ts",
+    "full_data_reset_test.ts",
+    "move_passwords_dialog_test.ts",
     "passkey_details_card_test.ts",
     "password_details_card_test.ts",
     "password_details_section_test.ts",
@@ -30,12 +30,12 @@
     "passwords_section_test.ts",
     "promo_cards_test.ts",
     "settings_section_test.ts",
-    "share_password_flow_test.ts",
-    "share_password_family_picker_dialog_test.ts",
-    "share_password_loading_dialog_test.ts",
     "share_password_confirmation_dialog_test.ts",
-    "share_password_header_test.ts",
+    "share_password_family_picker_dialog_test.ts",
+    "share_password_flow_test.ts",
     "share_password_group_avatar_test.ts",
+    "share_password_header_test.ts",
+    "share_password_loading_dialog_test.ts",
     "share_password_recipient_test.ts",
     "site_favicon_test.ts",
     "test_password_manager_proxy.ts",
diff --git a/chrome/test/data/webui/print_preview/BUILD.gn b/chrome/test/data/webui/print_preview/BUILD.gn
index 747d7f2..7f33ceb 100644
--- a/chrome/test/data/webui/print_preview/BUILD.gn
+++ b/chrome/test/data/webui/print_preview/BUILD.gn
@@ -92,8 +92,8 @@
 
   ts_definitions = [
     "//tools/typescript/definitions/chrome_event.d.ts",
-    "//tools/typescript/definitions/pending.d.ts",
     "//tools/typescript/definitions/mime_handler_private.d.ts",
+    "//tools/typescript/definitions/pending.d.ts",
   ]
 
   ts_deps = [
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn b/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn
index 2c3f4d7..109b4bbf 100644
--- a/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn
+++ b/chrome/test/data/webui/privacy_sandbox/internals/BUILD.gn
@@ -6,8 +6,8 @@
 
 build_webui_tests("build") {
   files = [
-    "privacy_sandbox_internals_test.ts",
     "content_settings_test.ts",
+    "privacy_sandbox_internals_test.ts",
   ]
   ts_path_mappings = [ "chrome://privacy-sandbox-internals/*|" + rebase_path(
                            "$root_gen_dir/chrome/browser/resources/privacy_sandbox/internals/tsc/*",
@@ -19,10 +19,10 @@
     "//components/content_settings/core/common:mojo_bindings_ts__generator",
   ]
   mojo_files = [
+    "$root_gen_dir/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings_enums.mojom-webui.ts",
     "$root_gen_dir/components/content_settings/core/common/content_settings_types.mojom-webui.ts",
-    "$root_gen_dir/chrome/browser/ui/webui/privacy_sandbox/privacy_sandbox_internals.mojom-webui.ts",
   ]
   ts_deps = [
     "//chrome/browser/resources/privacy_sandbox/internals:build_ts",
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/related_website_sets/BUILD.gn b/chrome/test/data/webui/privacy_sandbox/internals/related_website_sets/BUILD.gn
index 57b3cd5..60395fa 100644
--- a/chrome/test/data/webui/privacy_sandbox/internals/related_website_sets/BUILD.gn
+++ b/chrome/test/data/webui/privacy_sandbox/internals/related_website_sets/BUILD.gn
@@ -10,17 +10,16 @@
   files = [
     "app_test.ts",
     "container_test.ts",
-    "toolbar_test.ts",
-    "test_api_proxy.ts",
-    "test_data.ts",
     "list_item_test.ts",
     "sidebar_test.ts",
     "site_favicon_test.ts",
+    "test_api_proxy.ts",
+    "test_data.ts",
+    "toolbar_test.ts",
   ]
 
-  ts_path_mappings = [ "chrome://privacy-sandbox-internals/related_website_sets/related_website_sets.js|" +
-                       rebase_path(
-                          "$root_gen_dir/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/tsc/related_website_sets.d.ts",
+  ts_path_mappings = [ "chrome://privacy-sandbox-internals/related_website_sets/related_website_sets.js|" + rebase_path(
+                           "$root_gen_dir/chrome/browser/resources/privacy_sandbox/internals/related_website_sets/tsc/related_website_sets.d.ts",
                            target_gen_dir) ]
 
   ts_deps = [
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index f587b634..8696ee27 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -20,15 +20,17 @@
     "appearance_fonts_page_test.ts",
     "appearance_page_test.ts",
     "autofill_ai_section_test.ts",
+    "autofill_fake_data.ts",
     "autofill_page_test.ts",
     "autofill_section_address_validation_test.ts",
-    "autofill_section_test_utils.ts",
+    "autofill_section_focus_test.ts",
     "autofill_section_test.ts",
+    "autofill_section_test_utils.ts",
     "basic_page_test.ts",
     "battery_page_test.ts",
     "category_setting_exceptions_test.ts",
-    "checkbox_test.ts",
     "checkbox_list_entry_test.ts",
+    "checkbox_test.ts",
     "chooser_exception_list_entry_test.ts",
     "chooser_exception_list_test.ts",
     "clear_browsing_data_test.ts",
@@ -43,8 +45,8 @@
     "dropdown_menu_test.ts",
     "extension_controlled_indicator_test.ts",
     "file_system_site_details_test.ts",
-    "file_system_site_entry_test.ts",
     "file_system_site_entry_item_test.ts",
+    "file_system_site_entry_test.ts",
     "file_system_site_list_test.ts",
     "fingerprint_progress_arc_test.ts",
     "help_page_test.ts",
@@ -52,10 +54,8 @@
     "memory_page_test.ts",
     "offer_writing_help_page_test.ts",
     "on_startup_page_test.ts",
-    "autofill_fake_data.ts",
-    "autofill_section_focus_test.ts",
-    "payments_section_card_rows_test.ts",
     "payments_section_card_dialogs_test.ts",
+    "payments_section_card_rows_test.ts",
     "payments_section_focus_test.ts",
     "payments_section_iban_test.ts",
     "payments_section_interactive_test.ts",
@@ -71,12 +71,12 @@
     "privacy_guide_completion_fragment_test.ts",
     "privacy_guide_cookies_fragment_test.ts",
     "privacy_guide_history_sync_fragment_test.ts",
-    "privacy_guide_msbb_fragment_test.ts",
-    "privacy_guide_safe_browsing_fragment_test.ts",
-    "privacy_guide_welcome_fragment_test.ts",
     "privacy_guide_integration_test.ts",
+    "privacy_guide_msbb_fragment_test.ts",
     "privacy_guide_page_test.ts",
+    "privacy_guide_safe_browsing_fragment_test.ts",
     "privacy_guide_test_util.ts",
+    "privacy_guide_welcome_fragment_test.ts",
     "privacy_page_test.ts",
     "privacy_sandbox_page_test.ts",
     "protocol_handlers_test.ts",
@@ -86,9 +86,9 @@
     "route_test.ts",
     "safety_hub_card_test.ts",
     "safety_hub_entry_point_test.ts",
+    "safety_hub_extensions_module_test.ts",
     "safety_hub_module_test.ts",
     "safety_hub_notification_permissions_module_test.ts",
-    "safety_hub_extensions_module_test.ts",
     "safety_hub_page_test.ts",
     "safety_hub_unused_site_permissions_module_test.ts",
     "scrollable_mixin_test.ts",
@@ -98,13 +98,13 @@
     "search_settings_test.ts",
     "secure_dns_interactive_test.ts",
     "secure_dns_test.ts",
-    "security_keys_subpage_test.ts",
     "security_keys_bio_enrollment_test.ts",
     "security_keys_credential_management_test.ts",
+    "security_keys_phones_subpage_test.ts",
     "security_keys_reset_dialog_test.ts",
     "security_keys_set_pin_dialog_test.ts",
+    "security_keys_subpage_test.ts",
     "security_keys_test_util.ts",
-    "security_keys_phones_subpage_test.ts",
     "security_page_test.ts",
     "settings_animated_pages_test.ts",
     "settings_category_default_radio_group_test.ts",
@@ -113,9 +113,9 @@
     "settings_menu_test.ts",
     "settings_page_test_util.ts",
     "settings_performance_menu_test.ts",
-    "settings_prefs_test_cases.ts",
-    "settings_prefs_test.ts",
     "settings_pref_util_test.ts",
+    "settings_prefs_test.ts",
+    "settings_prefs_test_cases.ts",
     "settings_section_test.ts",
     "settings_slider_test.ts",
     "settings_subpage_test.ts",
@@ -123,8 +123,8 @@
     "settings_ui_test.ts",
     "simple_confirmation_dialog_test.ts",
     "site_data_test.ts",
-    "site_details_permission_test.ts",
     "site_details_permission_device_entry_test.ts",
+    "site_details_permission_test.ts",
     "site_details_test.ts",
     "site_entry_test.ts",
     "site_favicon_test.ts",
@@ -133,13 +133,12 @@
     "site_settings_page_test.ts",
     "speed_page_test.ts",
     "startup_urls_page_test.ts",
-    "storage_access_static_site_list_entry_test.ts",
     "storage_access_site_list_entry_test.ts",
     "storage_access_site_list_test.ts",
+    "storage_access_static_site_list_entry_test.ts",
     "sync_test_util.ts",
     "tab_discard_exception_dialog_test.ts",
     "test_about_page_browser_proxy.ts",
-    "test_user_annotations_manager_proxy.ts",
     "test_clear_browsing_data_browser_proxy.ts",
     "test_extension_control_browser_proxy.ts",
     "test_hats_browser_proxy.ts",
@@ -153,11 +152,12 @@
     "test_privacy_sandbox_browser_proxy.ts",
     "test_profile_info_browser_proxy.ts",
     "test_reset_browser_proxy.ts",
+    "test_safety_hub_browser_proxy.ts",
     "test_search_engines_browser_proxy.ts",
     "test_security_keys_browser_proxy.ts",
-    "test_safety_hub_browser_proxy.ts",
     "test_site_settings_prefs_browser_proxy.ts",
     "test_sync_browser_proxy.ts",
+    "test_user_annotations_manager_proxy.ts",
     "test_util.ts",
     "zoom_levels_test.ts",
   ]
@@ -185,17 +185,17 @@
 
   if (!is_chromeos) {
     files += [
-      "live_caption_section_test.ts",
-      "live_translate_section_test.ts",
-      "test_captions_browser_proxy.ts",
       "default_browser_test.ts",
       "import_data_dialog_test.ts",
+      "live_caption_section_test.ts",
+      "live_translate_section_test.ts",
       "system_page_test.ts",
+      "test_captions_browser_proxy.ts",
     ]
   } else {
     files += [
-      "smart_card_readers_page_test.ts",
       "smart_card_reader_origin_entry_test.ts",
+      "smart_card_readers_page_test.ts",
     ]
   }
 
@@ -223,8 +223,8 @@
   }
 
   static_files = [
-    "cr_lottie_green.json",
     "cr_lottie_blue.json",
+    "cr_lottie_green.json",
   ]
 
   ts_path_mappings = [
diff --git a/chrome/test/data/webui/side_panel/BUILD.gn b/chrome/test/data/webui/side_panel/BUILD.gn
index 7a67770c..df4e530e 100644
--- a/chrome/test/data/webui/side_panel/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/BUILD.gn
@@ -6,6 +6,8 @@
 
 build_webui_tests("build") {
   files = [
+    "bookmarks/commerce/shopping_list_test.ts",
+    "bookmarks/commerce/test_shopping_service_api_proxy.ts",
     "bookmarks/power_bookmarks_context_menu_test.ts",
     "bookmarks/power_bookmarks_drag_manager_test.ts",
     "bookmarks/power_bookmarks_edit_dialog_test.ts",
@@ -14,10 +16,8 @@
     "bookmarks/power_bookmarks_service_test.ts",
     "bookmarks/test_bookmarks_api_proxy.ts",
     "bookmarks/test_power_bookmarks_delegate.ts",
-    "bookmarks/commerce/shopping_list_test.ts",
-    "bookmarks/commerce/test_shopping_service_api_proxy.ts",
-    "commerce/shopping_insights_app_test.ts",
     "commerce/price_tracking_section_test.ts",
+    "commerce/shopping_insights_app_test.ts",
     "history_clusters/history_clusters_app_test.ts",
     "reading_list/reading_list_app_test.ts",
     "reading_list/test_reading_list_api_proxy.ts",
@@ -48,8 +48,8 @@
             target_gen_dir),
   ]
   ts_definitions = [
-    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/bookmark_manager_private.d.ts",
+    "//tools/typescript/definitions/bookmarks.d.ts",
     "//tools/typescript/definitions/chrome_event.d.ts",
     "//tools/typescript/definitions/metrics_private.d.ts",
     "//tools/typescript/definitions/pending.d.ts",
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
index 8a426ae7..455cefc 100644
--- a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
@@ -12,13 +12,13 @@
     "cards_test.ts",
     "categories_test.ts",
     "check_mark_wrapper_test.ts",
-    "wallpaper_search/combobox_test.ts",
     "hover_button_test.ts",
     "shortcuts_test.ts",
     "test_support.ts",
-    "themes_test.ts",
     "theme_snapshot_test.ts",
+    "themes_test.ts",
     "toolbar_test.ts",
+    "wallpaper_search/combobox_test.ts",
     "wallpaper_search/wallpaper_search_test.ts",
   ]
 
diff --git a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
index 34cc10f..98d2574 100644
--- a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
@@ -13,8 +13,8 @@
     "app_style_updater_test.ts",
     "checkmark_visible_on_selected_test.ts",
     "color_menu_test.ts",
-    "common_test.ts",
     "common.ts",
+    "common_test.ts",
     "fake_reading_mode.ts",
     "fake_speech_synthesis.ts",
     "fake_tree_builder.ts",
@@ -39,8 +39,8 @@
     "rate_selection_test.ts",
     "read_aloud_flag_test.ts",
     "read_aloud_highlighting_test.ts",
-    "read_aloud_update_content_selection_test.ts",
     "read_aloud_update_content_selection_pdf_test.ts",
+    "read_aloud_update_content_selection_test.ts",
     "read_anything_logger_test.ts",
     "speech_test.ts",
     "speech_uses_max_text_length_test.ts",
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn
index e074d6e3..f25896f 100644
--- a/chrome/test/data/webui/signin/BUILD.gn
+++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -10,30 +10,30 @@
 
 build_webui_tests("build") {
   files = [
+    "legacy_managed_user_profile_notice_test.ts",
     "profile_card_menu_test.ts",
+    "profile_customization_test.ts",
     "profile_picker_app_test.ts",
     "profile_picker_main_view_test.ts",
-    "test_manage_profiles_browser_proxy.ts",
-    "legacy_managed_user_profile_notice_test.ts",
-    "profile_customization_test.ts",
     "profile_switch_test.ts",
     "profile_type_choice_test.ts",
+    "signin_reauth_test.ts",
     "sync_confirmation_test.ts",
+    "test_manage_profiles_browser_proxy.ts",
     "test_managed_user_profile_notice_browser_proxy.ts",
     "test_profile_customization_browser_proxy.ts",
-    "test_sync_confirmation_browser_proxy.ts",
     "test_signin_reauth_browser_proxy.ts",
-    "signin_reauth_test.ts",
+    "test_sync_confirmation_browser_proxy.ts",
   ]
 
   if (enable_dice_support) {
     files += [
       "batch_upload_data_sections_test.ts",
       "batch_upload_view_test.ts",
-      "dice_web_signin_intercept_test.ts",
       "dice_web_signin_intercept_chrome_signin_test.ts",
-      "test_dice_web_signin_intercept_browser_proxy.ts",
+      "dice_web_signin_intercept_test.ts",
       "test_batch_upload_browser_proxy.ts",
+      "test_dice_web_signin_intercept_browser_proxy.ts",
     ]
   }
 
diff --git a/chrome/test/data/webui/tab_search/BUILD.gn b/chrome/test/data/webui/tab_search/BUILD.gn
index 6b75179..d79696fa 100644
--- a/chrome/test/data/webui/tab_search/BUILD.gn
+++ b/chrome/test/data/webui/tab_search/BUILD.gn
@@ -6,11 +6,11 @@
 
 build_webui_tests("build") {
   files = [
-    "lazy_list_test.ts",
-    "selectable_lazy_list_test.ts",
-    "search_test.ts",
     "auto_tab_groups_page_test.ts",
     "declutter_page_test.ts",
+    "lazy_list_test.ts",
+    "search_test.ts",
+    "selectable_lazy_list_test.ts",
     "tab_organization_selector_test.ts",
     "tab_search_app_test.ts",
     "tab_search_item_test.ts",
diff --git a/chrome/test/data/webui/tab_strip/BUILD.gn b/chrome/test/data/webui/tab_strip/BUILD.gn
index 797d237..b3e03f2 100644
--- a/chrome/test/data/webui/tab_strip/BUILD.gn
+++ b/chrome/test/data/webui/tab_strip/BUILD.gn
@@ -9,8 +9,8 @@
 
 build_webui_tests("build") {
   files = [
-    "alert_indicators_test.ts",
     "alert_indicator_test.ts",
+    "alert_indicators_test.ts",
     "drag_manager_test.ts",
     "tab_group_test.ts",
     "tab_list_test.ts",
diff --git a/chrome/test/data/webui/webview/BUILD.gn b/chrome/test/data/webui/webview/BUILD.gn
index b19faa4..3248bce 100644
--- a/chrome/test/data/webui/webview/BUILD.gn
+++ b/chrome/test/data/webui/webview/BUILD.gn
@@ -10,11 +10,11 @@
 build_webui_tests("build") {
   ts_definitions = [
     "//tools/typescript/definitions/chrome_event.d.ts",
-    "//tools/typescript/definitions/webview_tag.d.ts",
-    "//tools/typescript/definitions/web_request.d.ts",
     "//tools/typescript/definitions/context_menus.d.ts",
     "//tools/typescript/definitions/extension_types.d.ts",
     "//tools/typescript/definitions/tabs.d.ts",
+    "//tools/typescript/definitions/web_request.d.ts",
+    "//tools/typescript/definitions/webview_tag.d.ts",
   ]
 
   files = [
diff --git a/chrome/test/data/webui/whats_new/BUILD.gn b/chrome/test/data/webui/whats_new/BUILD.gn
index 5905122c..f0c37da 100644
--- a/chrome/test/data/webui/whats_new/BUILD.gn
+++ b/chrome/test/data/webui/whats_new/BUILD.gn
@@ -8,33 +8,33 @@
 
 build_webui_tests("build") {
   files = [
-    "whats_new_app_test.ts",
-    "whats_new_v2_app_test.ts",
     "test_whats_new_browser_proxy.ts",
-    "test_with_legacy_command_3.ts",
     "test_with_command_4.ts",
-    "test_with_metrics_page_loaded.ts",
+    "test_with_legacy_command_3.ts",
+    "test_with_metrics_explore_more_toggled.ts",
+    "test_with_metrics_module_click.ts",
     "test_with_metrics_module_impression.ts",
     "test_with_metrics_module_impression_v2.ts",
-    "test_with_metrics_explore_more_toggled.ts",
+    "test_with_metrics_module_video_events.ts",
+    "test_with_metrics_page_loaded.ts",
     "test_with_metrics_scroll_depth.ts",
     "test_with_metrics_time_on_page.ts",
-    "test_with_metrics_module_click.ts",
-    "test_with_metrics_module_video_events.ts",
+    "whats_new_app_test.ts",
+    "whats_new_v2_app_test.ts",
   ]
 
   static_files = [
     "test.html",
-    "test_with_legacy_command_3.html",
     "test_with_command_4.html",
-    "test_with_metrics_page_loaded.html",
+    "test_with_legacy_command_3.html",
+    "test_with_metrics_explore_more_toggled.html",
+    "test_with_metrics_module_click.html",
     "test_with_metrics_module_impression.html",
     "test_with_metrics_module_impression_v2.html",
-    "test_with_metrics_explore_more_toggled.html",
+    "test_with_metrics_module_video_events.html",
+    "test_with_metrics_page_loaded.html",
     "test_with_metrics_scroll_depth.html",
     "test_with_metrics_time_on_page.html",
-    "test_with_metrics_module_click.html",
-    "test_with_metrics_module_video_events.html",
   ]
 
   ts_path_mappings =
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 237bfd8..1ac2231 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -297,6 +297,8 @@
         "app/server/win/com_classes.h",
         "app/server/win/com_classes_legacy.cc",
         "app/server/win/com_classes_legacy.h",
+        "app/server/win/com_classes_util.cc",
+        "app/server/win/com_classes_util.h",
         "app/server/win/update_service_internal_stub_win.cc",
         "app/server/win/update_service_internal_stub_win.h",
         "app/server/win/update_service_stub_win.cc",
@@ -960,6 +962,7 @@
         "activity_impl_win_unittest.cc",
         "app/app_install_win_unittest.cc",
         "app/server/win/com_classes_legacy_unittest.cc",
+        "app/server/win/com_classes_util_unittest.cc",
         "auto_run_on_os_upgrade_task_unittest.cc",
         "policy/win/group_policy_manager_unittest.cc",
         "test/integration_tests_win.cc",
diff --git a/chrome/updater/app/app_server_win.cc b/chrome/updater/app/app_server_win.cc
index 3d1c0df45a..219f87b 100644
--- a/chrome/updater/app/app_server_win.cc
+++ b/chrome/updater/app/app_server_win.cc
@@ -228,19 +228,6 @@
 
 }  // namespace
 
-HRESULT IsCOMCallerAllowed() {
-  if (!IsSystemInstall()) {
-    return S_OK;
-  }
-
-  ASSIGN_OR_RETURN(const bool result, IsCOMCallerAdmin(), [](HRESULT error) {
-    LOG(ERROR) << "IsCOMCallerAdmin failed: " << std::hex << error;
-    return error;
-  });
-
-  return result ? S_OK : E_ACCESSDENIED;
-}
-
 scoped_refptr<App> MakeAppServer() {
   return GetAppServerWinInstance();
 }
diff --git a/chrome/updater/app/server/win/com_classes.cc b/chrome/updater/app/server/win/com_classes.cc
index 6e5f5bcc..ed53923 100644
--- a/chrome/updater/app/server/win/com_classes.cc
+++ b/chrome/updater/app/server/win/com_classes.cc
@@ -29,6 +29,7 @@
 #include "base/win/variant_vector.h"
 #include "chrome/updater/app/app_server_win.h"
 #include "chrome/updater/app/server/win/com_classes_legacy.h"
+#include "chrome/updater/app/server/win/com_classes_util.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_version.h"
@@ -37,9 +38,6 @@
 namespace updater {
 namespace {
 
-// Maximum string length for COM strings.
-constexpr size_t kMaxStringLen = 0x4000;  // 16KB.
-
 using IUpdaterCallbackPtr = Microsoft::WRL::ComPtr<IUpdaterCallback>;
 using IUpdaterInternalCallbackPtr =
     Microsoft::WRL::ComPtr<IUpdaterInternalCallback>;
@@ -219,7 +217,9 @@
 }
 
 HRESULT UpdaterImpl::GetVersion(BSTR* version) {
-  CHECK(version);
+  if (!version) {
+    return E_INVALIDARG;
+  }
 
   // Return the hardcoded version instead of calling the corresponding
   // non-blocking function of `UpdateServiceImpl`. This results in some
@@ -286,46 +286,9 @@
     return E_INVALIDARG;
   }
 
-  // Validates that string parameters are not longer than 16K characters.
-  std::optional<RegistrationRequest> request =
-      [app_id, brand_code, brand_path, ap, version, existence_checker_path,
-       install_id]() -> decltype(request) {
-    for (const auto& str : {app_id, brand_code, brand_path, ap, version,
-                            existence_checker_path, install_id}) {
-      if (wcsnlen_s(str, kMaxStringLen) == kMaxStringLen) {
-        return std::nullopt;
-      }
-    }
-
-    RegistrationRequest request;
-    if (!app_id || !base::WideToUTF8(app_id, wcslen(app_id), &request.app_id)) {
-      return std::nullopt;
-    }
-    if (!brand_code || !base::WideToUTF8(brand_code, wcslen(brand_code),
-                                         &request.brand_code)) {
-      return std::nullopt;
-    }
-    request.brand_path = base::FilePath(brand_path);
-    if (!ap || !base::WideToUTF8(ap, wcslen(ap), &request.ap)) {
-      return std::nullopt;
-    }
-    std::string version_str;
-    if (!version || !base::WideToUTF8(version, wcslen(version), &version_str)) {
-      return std::nullopt;
-    }
-    request.version = base::Version(version_str);
-    if (!request.version.IsValid()) {
-      return std::nullopt;
-    }
-    request.existence_checker_path = base::FilePath(existence_checker_path);
-    if (install_id && !base::WideToUTF8(install_id, wcslen(install_id),
-                                        &request.install_id)) {
-      return std::nullopt;
-    }
-
-    return request;
-  }();
-
+  const std::optional<RegistrationRequest> request =
+      ValidateRegistrationRequest(app_id, brand_code, brand_path, ap, version,
+                                  existence_checker_path, install_id);
   if (!request) {
     return E_INVALIDARG;
   }
@@ -448,6 +411,16 @@
     return E_INVALIDARG;
   }
 
+  const std::optional<std::string> app_id_validated = ValidateAppId(app_id);
+  if (!app_id_validated) {
+    return E_INVALIDARG;
+  }
+  const std::optional<std::string> language_validated =
+      ValidateLanguage(language);
+  if (!language_validated) {
+    return E_INVALIDARG;
+  }
+
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
       {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
   base::RepeatingCallback<void(const UpdateService::UpdateState&)>
@@ -490,8 +463,8 @@
             language, std::move(state_change_callback),
             std::move(complete_callback));
       },
-      base::WideToUTF8(app_id), static_cast<UpdateService::Priority>(priority),
-      same_version_update_allowed, base::WideToUTF8(language),
+      *app_id_validated, static_cast<UpdateService::Priority>(priority),
+      same_version_update_allowed, *language_validated,
       std::move(state_change_callback), std::move(complete_callback)));
   return S_OK;
 }
@@ -521,6 +494,21 @@
     return E_INVALIDARG;
   }
 
+  const std::optional<std::string> app_id_validated = ValidateAppId(app_id);
+  if (!app_id_validated) {
+    return E_INVALIDARG;
+  }
+  const std::optional<std::string> install_data_index_validated =
+      ValidateInstallDataIndex(install_data_index);
+  if (!install_data_index_validated) {
+    return E_INVALIDARG;
+  }
+  const std::optional<std::string> language_validated =
+      ValidateLanguage(language);
+  if (!language_validated) {
+    return E_INVALIDARG;
+  }
+
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
       {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
   base::RepeatingCallback<void(const UpdateService::UpdateState&)>
@@ -564,9 +552,9 @@
             language, std::move(state_change_callback),
             std::move(complete_callback));
       },
-      base::WideToUTF8(app_id), base::WideToUTF8(install_data_index),
+      *app_id_validated, *install_data_index_validated,
       static_cast<UpdateService::Priority>(priority),
-      same_version_update_allowed, base::WideToUTF8(language),
+      same_version_update_allowed, *language_validated,
       std::move(state_change_callback), std::move(complete_callback)));
   return S_OK;
 }
@@ -645,52 +633,29 @@
     return E_INVALIDARG;
   }
 
-  // Validates that string parameters are not longer than 16K characters.
-  std::optional<RegistrationRequest> request =
-      [app_id, brand_code, brand_path, ap, version, existence_checker_path,
-       client_install_data, install_data_index, install_id,
-       language]() -> decltype(request) {
-    for (const auto& str :
-         {app_id, brand_code, brand_path, ap, version, existence_checker_path,
-          client_install_data, install_data_index, install_id, language}) {
-      if (wcsnlen_s(str, kMaxStringLen) == kMaxStringLen) {
-        return std::nullopt;
-      }
-    }
-
-    RegistrationRequest request;
-    if (!app_id || !base::WideToUTF8(app_id, wcslen(app_id), &request.app_id)) {
-      return std::nullopt;
-    }
-    if (!brand_code || !base::WideToUTF8(brand_code, wcslen(brand_code),
-                                         &request.brand_code)) {
-      return std::nullopt;
-    }
-    request.brand_path = base::FilePath(brand_path);
-    if (!ap || !base::WideToUTF8(ap, wcslen(ap), &request.ap)) {
-      return std::nullopt;
-    }
-    std::string version_str;
-    if (!version || !base::WideToUTF8(version, wcslen(version), &version_str)) {
-      return std::nullopt;
-    }
-    request.version = base::Version(version_str);
-    if (!request.version.IsValid()) {
-      return std::nullopt;
-    }
-    request.existence_checker_path = base::FilePath(existence_checker_path);
-    if (install_id && !base::WideToUTF8(install_id, wcslen(install_id),
-                                        &request.install_id)) {
-      return std::nullopt;
-    }
-
-    return request;
-  }();
-
+  const std::optional<RegistrationRequest> request =
+      ValidateRegistrationRequest(app_id, brand_code, brand_path, ap, version,
+                                  existence_checker_path, install_id);
   if (!request) {
     return E_INVALIDARG;
   }
 
+  const std::optional<std::string> client_install_data_validated =
+      ValidateClientInstallData(client_install_data);
+  if (!client_install_data_validated) {
+    return E_INVALIDARG;
+  }
+  const std::optional<std::string> install_data_index_validated =
+      ValidateInstallDataIndex(install_data_index);
+  if (!install_data_index_validated) {
+    return E_INVALIDARG;
+  }
+  const std::optional<std::string> language_validated =
+      ValidateLanguage(language);
+  if (!language_validated) {
+    return E_INVALIDARG;
+  }
+
   auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
       {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
   base::RepeatingCallback<void(const UpdateService::UpdateState&)>
@@ -732,18 +697,15 @@
                                 std::move(state_change_callback),
                                 std::move(complete_callback));
       },
-      *request, base::WideToUTF8(client_install_data),
-      base::WideToUTF8(install_data_index),
-      static_cast<UpdateService::Priority>(priority),
-      base::WideToUTF8(language), std::move(state_change_callback),
-      std::move(complete_callback)));
+      *request, *client_install_data_validated, *install_data_index_validated,
+      static_cast<UpdateService::Priority>(priority), *language_validated,
+      std::move(state_change_callback), std::move(complete_callback)));
   return S_OK;
 }
 
 HRESULT UpdaterImpl::CancelInstalls(const wchar_t* app_id) {
-  std::string app_id_str;
-  if (wcsnlen_s(app_id, kMaxStringLen) >= kMaxStringLen || !app_id ||
-      !base::WideToUTF8(app_id, wcslen(app_id), &app_id_str)) {
+  const std::optional<std::string> app_id_validated = ValidateAppId(app_id);
+  if (!app_id_validated) {
     return E_INVALIDARG;
   }
   AppServerWin::PostRpcTask(base::BindOnce(
@@ -755,7 +717,7 @@
         }
         update_service->CancelInstalls(app_id_str);
       },
-      app_id_str));
+      *app_id_validated));
   return S_OK;
 }
 
@@ -786,44 +748,33 @@
     return E_INVALIDARG;
   }
 
-  for (const wchar_t* str : {app_id, installer_path, install_args, install_data,
-                             install_settings, language}) {
-    if (wcsnlen_s(str, kMaxStringLen) >= kMaxStringLen) {
-      return E_INVALIDARG;
-    }
-  }
-
-  std::string app_id_str;
-  if (!app_id || !base::WideToUTF8(app_id, wcslen(app_id), &app_id_str)) {
+  const std::optional<std::string> app_id_validated = ValidateAppId(app_id);
+  if (!app_id_validated) {
     return E_INVALIDARG;
   }
-
-  if (!installer_path) {
+  const std::optional<base::FilePath> installer_path_validated =
+      ValidateInstallerPath(installer_path);
+  if (!installer_path_validated) {
     return E_INVALIDARG;
   }
-
-  std::string install_args_str;
-  if (install_args && !base::WideToUTF8(install_args, wcslen(install_args),
-                                        &install_args_str)) {
+  const std::optional<std::string> install_args_validated =
+      ValidateInstallArgs(install_args);
+  if (!install_args_validated) {
     return E_INVALIDARG;
   }
-
-  std::string install_settings_str;
-  if (install_settings &&
-      !base::WideToUTF8(install_settings, wcslen(install_settings),
-                        &install_settings_str)) {
+  const std::optional<std::string> install_data_validated =
+      ValidateClientInstallData(install_data);
+  if (!install_data_validated) {
     return E_INVALIDARG;
   }
-
-  std::string install_data_str;
-  if (install_data && !base::WideToUTF8(install_data, wcslen(install_data),
-                                        &install_data_str)) {
+  const std::optional<std::string> install_settings_validated =
+      ValidateInstallSettings(install_settings);
+  if (!install_settings_validated) {
     return E_INVALIDARG;
   }
-
-  std::string language_str;
-  if (language &&
-      !base::WideToUTF8(language, wcslen(language), &language_str)) {
+  const std::optional<std::string> language_validated =
+      ValidateLanguage(language);
+  if (!language_validated) {
     return E_INVALIDARG;
   }
 
@@ -867,8 +818,8 @@
                                      std::move(state_change_callback),
                                      std::move(complete_callback));
       },
-      app_id_str, base::FilePath(installer_path), install_args_str,
-      install_data_str, install_settings_str, language_str,
+      *app_id_validated, *installer_path_validated, *install_args_validated,
+      *install_data_validated, *install_settings_validated, *language_validated,
       std::move(state_change_callback), std::move(complete_callback)));
   return S_OK;
 }
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index 4b75c85..733a27b 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -38,6 +38,7 @@
 #include "base/win/scoped_variant.h"
 #include "chrome/updater/activity.h"
 #include "chrome/updater/app/app_server_win.h"
+#include "chrome/updater/app/server/win/com_classes_util.h"
 #include "chrome/updater/constants.h"
 #include "chrome/updater/persisted_data.h"
 #include "chrome/updater/policy/manager.h"
@@ -122,7 +123,9 @@
 
   // Overrides for IAppVersionWeb.
   IFACEMETHODIMP get_version(BSTR* version) override {
-    CHECK(version);
+    if (!version) {
+      return E_INVALIDARG;
+    }
 
     *version = base::win::ScopedBstr(version_).Release();
     return S_OK;
@@ -194,21 +197,27 @@
 
   // Overrides for ICurrentState.
   IFACEMETHODIMP get_stateValue(LONG* state_value) override {
-    CHECK(state_value);
+    if (!state_value) {
+      return E_INVALIDARG;
+    }
 
     *state_value = state_value_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_availableVersion(BSTR* available_version) override {
-    CHECK(available_version);
+    if (!available_version) {
+      return E_INVALIDARG;
+    }
 
     *available_version = base::win::ScopedBstr(available_version_).Release();
     return S_OK;
   }
 
   IFACEMETHODIMP get_bytesDownloaded(ULONG* bytes_downloaded) override {
-    CHECK(bytes_downloaded);
+    if (!bytes_downloaded) {
+      return E_INVALIDARG;
+    }
 
     *bytes_downloaded = bytes_downloaded_;
     return S_OK;
@@ -216,7 +225,9 @@
 
   IFACEMETHODIMP get_totalBytesToDownload(
       ULONG* total_bytes_to_download) override {
-    CHECK(total_bytes_to_download);
+    if (!total_bytes_to_download) {
+      return E_INVALIDARG;
+    }
 
     *total_bytes_to_download = total_bytes_to_download_;
     return S_OK;
@@ -224,14 +235,18 @@
 
   IFACEMETHODIMP get_downloadTimeRemainingMs(
       LONG* download_time_remaining_ms) override {
-    CHECK(download_time_remaining_ms);
+    if (!download_time_remaining_ms) {
+      return E_INVALIDARG;
+    }
 
     *download_time_remaining_ms = download_time_remaining_ms_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_nextRetryTime(ULONGLONG* next_retry_time) override {
-    CHECK(next_retry_time);
+    if (!next_retry_time) {
+      return E_INVALIDARG;
+    }
 
     *next_retry_time = next_retry_time_;
     return S_OK;
@@ -239,7 +254,9 @@
 
   IFACEMETHODIMP get_installProgress(
       LONG* install_progress_percentage) override {
-    CHECK(install_progress_percentage);
+    if (!install_progress_percentage) {
+      return E_INVALIDARG;
+    }
 
     *install_progress_percentage = install_progress_percentage_;
     return S_OK;
@@ -247,42 +264,54 @@
 
   IFACEMETHODIMP get_installTimeRemainingMs(
       LONG* install_time_remaining_ms) override {
-    CHECK(install_time_remaining_ms);
+    if (!install_time_remaining_ms) {
+      return E_INVALIDARG;
+    }
 
     *install_time_remaining_ms = install_time_remaining_ms_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_isCanceled(VARIANT_BOOL* is_canceled) override {
-    CHECK(is_canceled);
+    if (!is_canceled) {
+      return E_INVALIDARG;
+    }
 
     *is_canceled = is_canceled_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_errorCode(LONG* error_code) override {
-    CHECK(error_code);
+    if (!error_code) {
+      return E_INVALIDARG;
+    }
 
     *error_code = error_code_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_extraCode1(LONG* extra_code1) override {
-    CHECK(extra_code1);
+    if (!extra_code1) {
+      return E_INVALIDARG;
+    }
 
     *extra_code1 = extra_code1_;
     return S_OK;
   }
 
   IFACEMETHODIMP get_completionMessage(BSTR* completion_message) override {
-    CHECK(completion_message);
+    if (!completion_message) {
+      return E_INVALIDARG;
+    }
 
     *completion_message = base::win::ScopedBstr(completion_message_).Release();
     return S_OK;
   }
 
   IFACEMETHODIMP get_installerResultCode(LONG* installer_result_code) override {
-    CHECK(installer_result_code);
+    if (!installer_result_code) {
+      return E_INVALIDARG;
+    }
 
     *installer_result_code = installer_result_code_;
     return S_OK;
@@ -290,7 +319,9 @@
 
   IFACEMETHODIMP get_installerResultExtraCode1(
       LONG* installer_result_extra_code1) override {
-    CHECK(installer_result_extra_code1);
+    if (!installer_result_extra_code1) {
+      return E_INVALIDARG;
+    }
 
     *installer_result_extra_code1 = installer_result_extra_code1_;
     return S_OK;
@@ -298,7 +329,9 @@
 
   IFACEMETHODIMP get_postInstallLaunchCommandLine(
       BSTR* post_install_launch_command_line) override {
-    CHECK(post_install_launch_command_line);
+    if (!post_install_launch_command_line) {
+      return E_INVALIDARG;
+    }
 
     *post_install_launch_command_line =
         base::win::ScopedBstr(post_install_launch_command_line_).Release();
@@ -306,14 +339,18 @@
   }
 
   IFACEMETHODIMP get_postInstallUrl(BSTR* post_install_url) override {
-    CHECK(post_install_url);
+    if (!post_install_url) {
+      return E_INVALIDARG;
+    }
 
     *post_install_url = base::win::ScopedBstr(post_install_url_).Release();
     return S_OK;
   }
 
   IFACEMETHODIMP get_postInstallAction(LONG* post_install_action) override {
-    CHECK(post_install_action);
+    if (!post_install_action) {
+      return E_INVALIDARG;
+    }
 
     *post_install_action = post_install_action_;
     return S_OK;
@@ -578,6 +615,10 @@
   }
 
   IFACEMETHODIMP get_currentVersionWeb(IDispatch** current) override {
+    if (!current) {
+      return E_INVALIDARG;
+    }
+
     // Holds the result of the IPC to retrieve the current version.
     struct CurrentVersionResult
         : public base::RefCountedThreadSafe<CurrentVersionResult> {
@@ -622,6 +663,10 @@
   }
 
   IFACEMETHODIMP get_nextVersionWeb(IDispatch** next) override {
+    if (!next) {
+      return E_INVALIDARG;
+    }
+
     base::AutoLock lock{lock_};
 
     if (!state_update_ || !state_update_->next_version.IsValid()) {
@@ -633,6 +678,10 @@
   }
 
   IFACEMETHODIMP get_command(BSTR command_id, IDispatch** command) override {
+    if (!ValidateCommandId(command_id) || !command) {
+      return E_INVALIDARG;
+    }
+
     return MakeAndInitializeComObject<LegacyAppCommandWebImpl>(
         command, GetUpdaterScope(), base::UTF8ToWide(app_id_), command_id);
   }
@@ -652,7 +701,9 @@
   }
 
   IFACEMETHODIMP get_currentState(IDispatch** current_state) override {
-    CHECK(current_state);
+    if (!current_state) {
+      return E_INVALIDARG;
+    }
 
     base::AutoLock lock{lock_};
 
@@ -762,7 +813,9 @@
   }
 
   IFACEMETHODIMP get_serverInstallDataIndex(BSTR* install_data_index) override {
-    CHECK(install_data_index);
+    if (!install_data_index) {
+      return E_INVALIDARG;
+    }
 
     *install_data_index =
         base::win::ScopedBstr(base::UTF8ToWide(install_data_index_)).Release();
@@ -770,6 +823,10 @@
   }
 
   IFACEMETHODIMP put_serverInstallDataIndex(BSTR install_data_index) override {
+    if (!install_data_index) {
+      return E_INVALIDARG;
+    }
+
     install_data_index_ = base::WideToUTF8(install_data_index);
     return S_OK;
   }
@@ -882,6 +939,11 @@
                            BSTR brand_code,
                            BSTR language,
                            BSTR ap) override {
+    if (!ValidateAppId(app_id) || !ValidateBrandCode(brand_code) ||
+        !ValidateLanguage(language) || !ValidateAP(ap)) {
+      return E_INVALIDARG;
+    }
+
     base::AutoLock lock{lock_};
 
     if (app_web_) {
@@ -894,6 +956,10 @@
   }
 
   IFACEMETHODIMP createInstalledApp(BSTR app_id) override {
+    if (!ValidateAppId(app_id)) {
+      return E_INVALIDARG;
+    }
+
     base::AutoLock lock{lock_};
 
     if (app_web_) {
@@ -925,9 +991,13 @@
   }
 
   IFACEMETHODIMP get_appWeb(int index, IDispatch** app_web) override {
+    if (index || !app_web) {
+      return E_INVALIDARG;
+    }
+
     base::AutoLock lock{lock_};
 
-    if (index != 0 || !app_web_) {
+    if (!app_web_) {
       return E_UNEXPECTED;
     }
 
@@ -1009,7 +1079,10 @@
 
 STDMETHODIMP LegacyOnDemandImpl::createAppBundleWeb(
     IDispatch** app_bundle_web) {
-  CHECK(app_bundle_web);
+  if (!app_bundle_web) {
+    return E_INVALIDARG;
+  }
+
   return MakeAndInitializeComObject<AppBundleWebImpl>(app_bundle_web);
 }
 
@@ -1032,6 +1105,11 @@
     const WCHAR* command_id,
     DWORD caller_proc_id,
     ULONG_PTR* proc_handle) {
+  if (!ValidateAppId(app_id) || !ValidateCommandId(command_id) ||
+      !proc_handle) {
+    return E_INVALIDARG;
+  }
+
   base::win::ScopedHandle caller_proc_handle;
   if (HRESULT hr = OpenCallerProcessHandle(caller_proc_id, caller_proc_handle);
       FAILED(hr)) {
@@ -1104,7 +1182,9 @@
 }
 
 STDMETHODIMP LegacyAppCommandWebImpl::get_status(UINT* status) {
-  CHECK(status);
+  if (!status) {
+    return E_INVALIDARG;
+  }
 
   if (!process_.IsValid()) {
     *status = COMMAND_STATUS_INIT;
@@ -1118,7 +1198,9 @@
 }
 
 STDMETHODIMP LegacyAppCommandWebImpl::get_exitCode(DWORD* exit_code) {
-  CHECK(exit_code);
+  if (!exit_code) {
+    return E_INVALIDARG;
+  }
 
   int code = -1;
   if (!process_.IsValid() ||
@@ -1144,8 +1226,7 @@
                                               VARIANT substitution7,
                                               VARIANT substitution8,
                                               VARIANT substitution9) {
-  CHECK(app_command_runner_.has_value());
-  if (process_.IsValid()) {
+  if (!app_command_runner_.has_value() || process_.IsValid()) {
     return E_UNEXPECTED;
   }
 
@@ -1264,7 +1345,9 @@
 
 // IPolicyStatus.
 STDMETHODIMP PolicyStatusImpl::get_lastCheckPeriodMinutes(DWORD* minutes) {
-  CHECK(minutes);
+  if (!minutes) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<base::TimeDelta> period = policy_service_->GetLastCheckPeriod();
   if (!period) {
@@ -1284,6 +1367,9 @@
   CHECK(start_min);
   CHECK(duration_min);
   CHECK(are_updates_suppressed);
+  if (!start_hour || !start_min || !duration_min || !are_updates_suppressed) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<UpdatesSuppressedTimes> updates_suppressed_times =
       policy_service_->GetUpdatesSuppressedTimes();
@@ -1301,7 +1387,9 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_downloadPreferenceGroupPolicy(BSTR* pref) {
-  CHECK(pref);
+  if (!pref) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<std::string> download_preference =
       policy_service_->GetDownloadPreference();
@@ -1315,7 +1403,9 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_packageCacheSizeLimitMBytes(DWORD* limit) {
-  CHECK(limit);
+  if (!limit) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<int> cache_size_limit =
       policy_service_->GetPackageCacheSizeLimitMBytes();
@@ -1328,7 +1418,9 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_packageCacheExpirationTimeDays(DWORD* days) {
-  CHECK(days);
+  if (!days) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<int> cache_life_limit =
       policy_service_->GetPackageCacheExpirationTimeDays();
@@ -1343,7 +1435,9 @@
 STDMETHODIMP PolicyStatusImpl::get_effectivePolicyForAppInstalls(
     BSTR app_id,
     DWORD* policy) {
-  CHECK(policy);
+  if (!policy) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<int> install_policy =
       policy_service_->GetPolicyForAppInstalls(base::WideToUTF8(app_id));
@@ -1357,7 +1451,9 @@
 
 STDMETHODIMP PolicyStatusImpl::get_effectivePolicyForAppUpdates(BSTR app_id,
                                                                 DWORD* policy) {
-  CHECK(policy);
+  if (!ValidateAppId(app_id) || !policy) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<int> update_policy =
       policy_service_->GetPolicyForAppUpdates(base::WideToUTF8(app_id));
@@ -1371,7 +1467,9 @@
 
 STDMETHODIMP PolicyStatusImpl::get_targetVersionPrefix(BSTR app_id,
                                                        BSTR* prefix) {
-  CHECK(prefix);
+  if (!ValidateAppId(app_id) || !prefix) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<std::string> target_version_prefix =
       policy_service_->GetTargetVersionPrefix(base::WideToUTF8(app_id));
@@ -1388,7 +1486,9 @@
 STDMETHODIMP PolicyStatusImpl::get_isRollbackToTargetVersionAllowed(
     BSTR app_id,
     VARIANT_BOOL* rollback_allowed) {
-  CHECK(rollback_allowed);
+  if (!ValidateAppId(app_id) || !rollback_allowed) {
+    return E_INVALIDARG;
+  }
 
   PolicyStatus<bool> is_rollback_allowed =
       policy_service_->IsRollbackToTargetVersionAllowed(
@@ -1403,7 +1503,9 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_updaterVersion(BSTR* version) {
-  CHECK(version);
+  if (!version) {
+    return E_INVALIDARG;
+  }
 
   *version = base::win::ScopedBstr(kUpdaterVersionUtf16).Release();
   return S_OK;
@@ -1460,7 +1562,9 @@
 }  // namespace
 
 STDMETHODIMP PolicyStatusImpl::get_lastCheckedTime(DATE* last_checked) {
-  CHECK(last_checked);
+  if (!last_checked) {
+    return E_INVALIDARG;
+  }
 
   using PolicyStatusImplPtr = Microsoft::WRL::ComPtr<PolicyStatusImpl>;
   auto result = base::MakeRefCounted<LastCheckedTimeResult>();
@@ -1524,7 +1628,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_lastCheckPeriodMinutes(
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<int>::Get(base::BindRepeating(
       &PolicyService::DeprecatedGetLastCheckPeriodMinutes, policy_service_));
   return policy_status.has_value()
@@ -1535,8 +1642,9 @@
 STDMETHODIMP PolicyStatusImpl::get_updatesSuppressedTimes(
     IPolicyStatusValue** value,
     VARIANT_BOOL* are_updates_suppressed) {
-  CHECK(value);
-  CHECK(are_updates_suppressed);
+  if (!value || !are_updates_suppressed) {
+    return E_INVALIDARG;
+  }
 
   auto policy_status =
       PolicyStatusResult<UpdatesSuppressedTimes>::Get(base::BindRepeating(
@@ -1556,7 +1664,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_downloadPreferenceGroupPolicy(
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(base::BindRepeating(
       &PolicyService::GetDownloadPreference, policy_service_));
   return policy_status.has_value()
@@ -1566,7 +1677,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_packageCacheSizeLimitMBytes(
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<int>::Get(base::BindRepeating(
       &PolicyService::GetPackageCacheSizeLimitMBytes, policy_service_));
   return policy_status.has_value()
@@ -1576,7 +1690,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_packageCacheExpirationTimeDays(
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<int>::Get(base::BindRepeating(
       &PolicyService::GetPackageCacheExpirationTimeDays, policy_service_));
   return policy_status.has_value()
@@ -1585,7 +1702,10 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_proxyMode(IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(
       base::BindRepeating(&PolicyService::GetProxyMode, policy_service_));
   return policy_status.has_value()
@@ -1594,7 +1714,10 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_proxyPacUrl(IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(
       base::BindRepeating(&PolicyService::GetProxyPacUrl, policy_service_));
   return policy_status.has_value()
@@ -1603,7 +1726,10 @@
 }
 
 STDMETHODIMP PolicyStatusImpl::get_proxyServer(IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(
       base::BindRepeating(&PolicyService::GetProxyServer, policy_service_));
   return policy_status.has_value()
@@ -1614,7 +1740,10 @@
 STDMETHODIMP PolicyStatusImpl::get_effectivePolicyForAppInstalls(
     BSTR app_id,
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!ValidateAppId(app_id) || !value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<int>::Get(
       base::BindRepeating(&PolicyService::GetPolicyForAppInstalls,
                           policy_service_, base::WideToUTF8(app_id)));
@@ -1626,7 +1755,10 @@
 STDMETHODIMP PolicyStatusImpl::get_effectivePolicyForAppUpdates(
     BSTR app_id,
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!ValidateAppId(app_id) || !value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<int>::Get(
       base::BindRepeating(&PolicyService::GetPolicyForAppUpdates,
                           policy_service_, base::WideToUTF8(app_id)));
@@ -1638,7 +1770,10 @@
 STDMETHODIMP PolicyStatusImpl::get_targetVersionPrefix(
     BSTR app_id,
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!ValidateAppId(app_id) || !value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(
       base::BindRepeating(&PolicyService::GetTargetVersionPrefix,
                           policy_service_, base::WideToUTF8(app_id)));
@@ -1650,7 +1785,10 @@
 STDMETHODIMP PolicyStatusImpl::get_isRollbackToTargetVersionAllowed(
     BSTR app_id,
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!ValidateAppId(app_id) || !value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<bool>::Get(
       base::BindRepeating(&PolicyService::IsRollbackToTargetVersionAllowed,
                           policy_service_, base::WideToUTF8(app_id)));
@@ -1661,7 +1799,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_targetChannel(BSTR app_id,
                                                  IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!ValidateAppId(app_id) || !value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<std::string>::Get(
       base::BindRepeating(&PolicyService::GetTargetChannel, policy_service_,
                           base::WideToUTF8(app_id)));
@@ -1673,7 +1814,10 @@
 STDMETHODIMP PolicyStatusImpl::get_forceInstallApps(
     VARIANT_BOOL is_machine,
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status =
       PolicyStatusResult<std::vector<std::string>>::Get(base::BindRepeating(
           &PolicyService::GetForceInstallApps, policy_service_));
@@ -1684,7 +1828,10 @@
 
 STDMETHODIMP PolicyStatusImpl::get_cloudPolicyOverridesPlatformPolicy(
     IPolicyStatusValue** value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
   auto policy_status = PolicyStatusResult<bool>::Get(base::BindRepeating(
       &PolicyService::CloudPolicyOverridesPlatformPolicy, policy_service_));
   return policy_status.has_value()
@@ -1703,6 +1850,10 @@
 [[nodiscard]] HRESULT PolicyStatusValueImpl::Create(
     const T& value,
     IPolicyStatusValue** policy_status_value) {
+  if (!policy_status_value) {
+    return E_INVALIDARG;
+  }
+
   return MakeAndInitializeComObject<PolicyStatusValueImpl>(
       policy_status_value,
       value.effective_policy() ? value.effective_policy()->source : "",
@@ -1733,14 +1884,18 @@
 
 // IPolicyStatusValue.
 STDMETHODIMP PolicyStatusValueImpl::get_source(BSTR* source) {
-  CHECK(source);
+  if (!source) {
+    return E_INVALIDARG;
+  }
 
   *source = base::win::ScopedBstr(source_).Release();
   return S_OK;
 }
 
 STDMETHODIMP PolicyStatusValueImpl::get_value(BSTR* value) {
-  CHECK(value);
+  if (!value) {
+    return E_INVALIDARG;
+  }
 
   *value = base::win::ScopedBstr(value_).Release();
   return S_OK;
@@ -1748,21 +1903,27 @@
 
 STDMETHODIMP PolicyStatusValueImpl::get_hasConflict(
     VARIANT_BOOL* has_conflict) {
-  CHECK(has_conflict);
+  if (!has_conflict) {
+    return E_INVALIDARG;
+  }
 
   *has_conflict = has_conflict_;
   return S_OK;
 }
 
 STDMETHODIMP PolicyStatusValueImpl::get_conflictSource(BSTR* conflict_source) {
-  CHECK(conflict_source);
+  if (!conflict_source) {
+    return E_INVALIDARG;
+  }
 
   *conflict_source = base::win::ScopedBstr(conflict_source_).Release();
   return S_OK;
 }
 
 STDMETHODIMP PolicyStatusValueImpl::get_conflictValue(BSTR* conflict_value) {
-  CHECK(conflict_value);
+  if (!conflict_value) {
+    return E_INVALIDARG;
+  }
 
   *conflict_value = base::win::ScopedBstr(conflict_value_).Release();
   return S_OK;
diff --git a/chrome/updater/app/server/win/com_classes_util.cc b/chrome/updater/app/server/win/com_classes_util.cc
new file mode 100644
index 0000000..092dac1
--- /dev/null
+++ b/chrome/updater/app/server/win/com_classes_util.cc
@@ -0,0 +1,197 @@
+// Copyright 2024 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/updater/app/server/win/com_classes_util.h"
+
+#include <optional>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/types/expected_macros.h"
+#include "base/version.h"
+#include "base/win/windows_types.h"
+#include "chrome/updater/registration_data.h"
+#include "chrome/updater/updater_scope.h"
+#include "chrome/updater/util/win_util.h"
+
+namespace updater {
+
+namespace {
+
+// Maximum string length for COM strings.
+constexpr size_t kMaxStringLen = 0x4000;  // 16KB.
+
+// Maximum string length for `language` strings.
+constexpr size_t kMaxLanguageStringLen = 10;
+
+}  // namespace
+
+HRESULT IsCOMCallerAllowed() {
+  if (!IsSystemInstall()) {
+    return S_OK;
+  }
+
+  ASSIGN_OR_RETURN(const bool result, IsCOMCallerAdmin(), [](HRESULT error) {
+    LOG(ERROR) << "IsCOMCallerAdmin failed: " << std::hex << error;
+    return error;
+  });
+
+  return result ? S_OK : E_ACCESSDENIED;
+}
+
+std::optional<std::string> ValidateStringEmptyNotOk(const wchar_t* value,
+                                                    size_t max_length) {
+  std::string value_s;
+  return value && base::WideToUTF8(value, wcslen(value), &value_s) &&
+                 !value_s.empty() && (value_s.length() <= max_length)
+             ? std::make_optional(value_s)
+             : std::nullopt;
+}
+
+std::optional<std::string> ValidateStringEmptyOk(const wchar_t* value,
+                                                 size_t max_length) {
+  std::string value_s;
+  return !value ? std::make_optional(value_s)
+         : base::WideToUTF8(value, wcslen(value), &value_s) &&
+                 (value_s.length() <= max_length)
+             ? std::make_optional(value_s)
+             : std::nullopt;
+}
+
+std::optional<std::string> ValidateAppId(const wchar_t* app_id) {
+  return ValidateStringEmptyNotOk(app_id, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateCommandId(const wchar_t* command_id) {
+  return ValidateStringEmptyNotOk(command_id, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateBrandCode(const wchar_t* brand_code) {
+  return ValidateStringEmptyOk(brand_code, kMaxStringLen);
+}
+
+std::optional<base::FilePath> ValidateBrandPath(const wchar_t* brand_path) {
+  const std::optional<std::string> brand_path_s =
+      ValidateStringEmptyOk(brand_path, kMaxStringLen);
+  return brand_path_s ? std::make_optional(
+                            base::FilePath(base::UTF8ToWide(*brand_path_s)))
+                      : std::nullopt;
+}
+
+std::optional<std::string> ValidateAP(const wchar_t* ap) {
+  return ValidateStringEmptyOk(ap, kMaxStringLen);
+}
+
+std::optional<base::Version> ValidateVersion(const wchar_t* version) {
+  const std::optional<std::string> version_s =
+      ValidateStringEmptyNotOk(version, kMaxStringLen);
+  if (!version_s) {
+    return std::nullopt;
+  }
+  const base::Version version_v = base::Version(*version_s);
+  return version_v.IsValid() ? std::make_optional(version_v) : std::nullopt;
+}
+
+std::optional<base::FilePath> ValidateExistenceCheckerPath(
+    const wchar_t* existence_checker_path) {
+  const std::optional<std::string> existence_checker_path_s =
+      ValidateStringEmptyOk(existence_checker_path, kMaxStringLen);
+  return existence_checker_path_s
+             ? std::make_optional(
+                   base::FilePath(base::UTF8ToWide(*existence_checker_path_s)))
+             : std::nullopt;
+}
+
+std::optional<base::FilePath> ValidateInstallerPath(
+    const wchar_t* installer_path) {
+  const std::optional<std::string> installer_path_s =
+      ValidateStringEmptyNotOk(installer_path, kMaxStringLen);
+  return installer_path_s ? std::make_optional(base::FilePath(
+                                base::UTF8ToWide(*installer_path_s)))
+                          : std::nullopt;
+}
+
+std::optional<std::string> ValidateInstallArgs(const wchar_t* install_args) {
+  return ValidateStringEmptyOk(install_args, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateInstallSettings(
+    const wchar_t* install_settings) {
+  return ValidateStringEmptyOk(install_settings, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateClientInstallData(
+    const wchar_t* client_install_data) {
+  return ValidateStringEmptyOk(client_install_data, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateInstallDataIndex(
+    const wchar_t* install_data_index) {
+  return ValidateStringEmptyOk(install_data_index, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateInstallId(const wchar_t* install_id) {
+  return ValidateStringEmptyOk(install_id, kMaxStringLen);
+}
+
+std::optional<std::string> ValidateLanguage(const wchar_t* language) {
+  return ValidateStringEmptyOk(language, kMaxLanguageStringLen);
+}
+
+std::optional<RegistrationRequest> ValidateRegistrationRequest(
+    const wchar_t* app_id,
+    const wchar_t* brand_code,
+    const wchar_t* brand_path,
+    const wchar_t* ap,
+    const wchar_t* version,
+    const wchar_t* existence_checker_path,
+    const wchar_t* install_id) {
+  const std::optional<std::string> app_id_validated = ValidateAppId(app_id);
+  if (!app_id_validated) {
+    return {};
+  }
+  const std::optional<std::string> brand_code_validated =
+      ValidateBrandCode(brand_code);
+  if (!brand_code_validated) {
+    return {};
+  }
+  const std::optional<base::FilePath> brand_path_validated =
+      ValidateBrandPath(brand_path);
+  if (!brand_path_validated) {
+    return {};
+  }
+  const std::optional<std::string> ap_validated = ValidateAP(ap);
+  if (!ap_validated) {
+    return {};
+  }
+  const std::optional<base::Version> version_validated =
+      ValidateVersion(version);
+  if (!version_validated) {
+    return {};
+  }
+  const std::optional<base::FilePath> existence_checker_path_validated =
+      ValidateExistenceCheckerPath(existence_checker_path);
+  if (!existence_checker_path_validated) {
+    return {};
+  }
+  const std::optional<std::string> install_id_validated =
+      ValidateInstallId(install_id);
+  if (!install_id_validated) {
+    return {};
+  }
+
+  RegistrationRequest request;
+  request.app_id = *app_id_validated;
+  request.brand_code = *brand_code_validated;
+  request.brand_path = *brand_path_validated;
+  request.ap = *ap_validated;
+  request.version = *version_validated;
+  request.existence_checker_path = *existence_checker_path_validated;
+  request.install_id = *install_id_validated;
+  return request;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/app/server/win/com_classes_util.h b/chrome/updater/app/server/win/com_classes_util.h
new file mode 100644
index 0000000..9025884
--- /dev/null
+++ b/chrome/updater/app/server/win/com_classes_util.h
@@ -0,0 +1,61 @@
+// Copyright 2024 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_UPDATER_APP_SERVER_WIN_COM_CLASSES_UTIL_H_
+#define CHROME_UPDATER_APP_SERVER_WIN_COM_CLASSES_UTIL_H_
+
+#include <optional>
+#include <string>
+
+#include "base/win/windows_types.h"
+
+namespace base {
+
+class FilePath;
+class Version;
+
+}  // namespace base
+
+namespace updater {
+
+struct RegistrationRequest;
+
+// Returns S_OK if user install, or if the COM caller is admin. Error otherwise.
+HRESULT IsCOMCallerAllowed();
+
+std::optional<std::string> ValidateStringEmptyNotOk(const wchar_t* value,
+                                                    size_t max_length);
+std::optional<std::string> ValidateStringEmptyOk(const wchar_t* value,
+                                                 size_t max_length);
+std::optional<std::string> ValidateAppId(const wchar_t* app_id);
+std::optional<std::string> ValidateCommandId(const wchar_t* command_id);
+std::optional<std::string> ValidateBrandCode(const wchar_t* brand_code);
+std::optional<base::FilePath> ValidateBrandPath(const wchar_t* brand_path);
+std::optional<std::string> ValidateAP(const wchar_t* ap);
+std::optional<base::Version> ValidateVersion(const wchar_t* version);
+std::optional<base::FilePath> ValidateExistenceCheckerPath(
+    const wchar_t* existence_checker_path);
+std::optional<base::FilePath> ValidateInstallerPath(
+    const wchar_t* installer_path);
+std::optional<std::string> ValidateInstallArgs(const wchar_t* install_args);
+std::optional<std::string> ValidateInstallSettings(
+    const wchar_t* install_settings);
+std::optional<std::string> ValidateClientInstallData(
+    const wchar_t* client_install_data);
+std::optional<std::string> ValidateInstallDataIndex(
+    const wchar_t* install_data_index);
+std::optional<std::string> ValidateInstallId(const wchar_t* install_id);
+std::optional<std::string> ValidateLanguage(const wchar_t* language);
+std::optional<RegistrationRequest> ValidateRegistrationRequest(
+    const wchar_t* app_id,
+    const wchar_t* brand_code,
+    const wchar_t* brand_path,
+    const wchar_t* ap,
+    const wchar_t* version,
+    const wchar_t* existence_checker_path,
+    const wchar_t* install_id);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_APP_SERVER_WIN_COM_CLASSES_UTIL_H_
diff --git a/chrome/updater/app/server/win/com_classes_util_unittest.cc b/chrome/updater/app/server/win/com_classes_util_unittest.cc
new file mode 100644
index 0000000..d81cb18
--- /dev/null
+++ b/chrome/updater/app/server/win/com_classes_util_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright 2024 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/updater/app/server/win/com_classes_util.h"
+
+#include <optional>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/types/expected_macros.h"
+#include "base/version.h"
+#include "base/win/windows_types.h"
+#include "chrome/updater/registration_data.h"
+#include "chrome/updater/updater_scope.h"
+#include "chrome/updater/util/win_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace updater::test {
+
+TEST(ComClassesUtil, ValidateStringEmptyNotOk) {
+  ASSERT_FALSE(ValidateStringEmptyNotOk(nullptr, 10));
+  ASSERT_FALSE(ValidateStringEmptyNotOk(L"", 10));
+  ASSERT_FALSE(ValidateStringEmptyNotOk(L"morethan10characters", 10));
+  ASSERT_EQ(ValidateStringEmptyNotOk(L"ninechars", 10).value(), "ninechars");
+}
+
+TEST(ComClassesUtil, ValidateStringEmptyOk) {
+  ASSERT_EQ(ValidateStringEmptyOk(nullptr, 10).value(), "");
+  ASSERT_EQ(ValidateStringEmptyOk(L"", 10).value(), "");
+  ASSERT_FALSE(ValidateStringEmptyOk(L"morethan10characters", 10));
+  ASSERT_EQ(ValidateStringEmptyOk(L"ninechars", 10).value(), "ninechars");
+}
+
+TEST(ComClassesUtil, ValidateAppId) {
+  ASSERT_FALSE(ValidateAppId(nullptr));
+  ASSERT_FALSE(ValidateAppId(L""));
+  ASSERT_FALSE(ValidateAppId(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateAppId(L"appidisvalid").value(), "appidisvalid");
+}
+
+TEST(ComClassesUtil, ValidateCommandId) {
+  ASSERT_FALSE(ValidateCommandId(nullptr));
+  ASSERT_FALSE(ValidateCommandId(L""));
+  ASSERT_FALSE(ValidateCommandId(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateCommandId(L"commandidisvalid").value(), "commandidisvalid");
+}
+
+TEST(ComClassesUtil, ValidateBrandCode) {
+  ASSERT_EQ(ValidateBrandCode(nullptr).value(), "");
+  ASSERT_EQ(ValidateBrandCode(L"").value(), "");
+  ASSERT_FALSE(ValidateBrandCode(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateBrandCode(L"brandcodeisvalid").value(), "brandcodeisvalid");
+}
+
+TEST(ComClassesUtil, ValidateBrandPath) {
+  ASSERT_TRUE(ValidateBrandPath(nullptr).value().empty());
+  ASSERT_TRUE(ValidateBrandPath(L"").value().empty());
+  ASSERT_FALSE(ValidateBrandPath(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateBrandPath(L"brandpathisvalid").value().value(),
+            L"brandpathisvalid");
+}
+
+TEST(ComClassesUtil, ValidateAP) {
+  ASSERT_EQ(ValidateAP(nullptr).value(), "");
+  ASSERT_EQ(ValidateAP(L"").value(), "");
+  ASSERT_FALSE(ValidateAP(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateAP(L"apisvalid").value(), "apisvalid");
+}
+
+TEST(ComClassesUtil, ValidateVersion) {
+  ASSERT_FALSE(ValidateVersion(nullptr));
+  ASSERT_FALSE(ValidateVersion(L""));
+  ASSERT_FALSE(ValidateVersion(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_FALSE(ValidateVersion(L"invalidversion"));
+  ASSERT_EQ(ValidateVersion(L"1.2.3.4").value(), base::Version("1.2.3.4"));
+}
+
+TEST(ComClassesUtil, ValidateExistenceCheckerPath) {
+  ASSERT_TRUE(ValidateExistenceCheckerPath(nullptr).value().empty());
+  ASSERT_TRUE(ValidateExistenceCheckerPath(L"").value().empty());
+  ASSERT_FALSE(ValidateExistenceCheckerPath(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(
+      ValidateExistenceCheckerPath(L"existencecheckerisvalid").value().value(),
+      L"existencecheckerisvalid");
+}
+
+TEST(ComClassesUtil, ValidateInstallerPath) {
+  ASSERT_FALSE(ValidateInstallerPath(nullptr));
+  ASSERT_FALSE(ValidateInstallerPath(L""));
+  ASSERT_FALSE(ValidateInstallerPath(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateInstallerPath(L"installerpathisvalid").value().value(),
+            L"installerpathisvalid");
+}
+
+TEST(ComClassesUtil, ValidateInstallArgs) {
+  ASSERT_EQ(ValidateInstallArgs(nullptr).value(), "");
+  ASSERT_EQ(ValidateInstallArgs(L"").value(), "");
+  ASSERT_FALSE(ValidateInstallArgs(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateInstallArgs(L"installargsisvalid").value(),
+            "installargsisvalid");
+}
+
+TEST(ComClassesUtil, ValidateInstallSettings) {
+  ASSERT_EQ(ValidateInstallSettings(nullptr).value(), "");
+  ASSERT_EQ(ValidateInstallSettings(L"").value(), "");
+  ASSERT_FALSE(ValidateInstallSettings(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateInstallSettings(L"installsettingsisvalid").value(),
+            "installsettingsisvalid");
+}
+
+TEST(ComClassesUtil, ValidateClientInstallData) {
+  ASSERT_EQ(ValidateClientInstallData(nullptr).value(), "");
+  ASSERT_EQ(ValidateClientInstallData(L"").value(), "");
+  ASSERT_FALSE(ValidateClientInstallData(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateClientInstallData(L"clientinstalldataisvalid").value(),
+            "clientinstalldataisvalid");
+}
+
+TEST(ComClassesUtil, ValidateInstallDataIndex) {
+  ASSERT_EQ(ValidateInstallDataIndex(nullptr).value(), "");
+  ASSERT_EQ(ValidateInstallDataIndex(L"").value(), "");
+  ASSERT_FALSE(ValidateInstallDataIndex(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateInstallDataIndex(L"installdataindexisvalid").value(),
+            "installdataindexisvalid");
+}
+
+TEST(ComClassesUtil, ValidateInstallId) {
+  ASSERT_EQ(ValidateInstallId(nullptr).value(), "");
+  ASSERT_EQ(ValidateInstallId(L"").value(), "");
+  ASSERT_FALSE(ValidateInstallId(std::wstring(0x4001, 'a').c_str()));
+  ASSERT_EQ(ValidateInstallId(L"installidisvalid").value(), "installidisvalid");
+}
+
+TEST(ComClassesUtil, ValidateLanguage) {
+  ASSERT_EQ(ValidateLanguage(nullptr).value(), "");
+  ASSERT_EQ(ValidateLanguage(L"").value(), "");
+  ASSERT_FALSE(ValidateLanguage(std::wstring(11, 'a').c_str()));
+  ASSERT_EQ(ValidateLanguage(L"langvalid").value(), "langvalid");
+}
+
+TEST(ComClassesUtil, ValidateRegistrationRequest) {
+  ASSERT_FALSE(ValidateRegistrationRequest(nullptr, nullptr, nullptr, nullptr,
+                                           nullptr, nullptr, nullptr));
+  ASSERT_FALSE(ValidateRegistrationRequest(L"", L"", L"", L"", L"", L"", L""));
+  ASSERT_FALSE(ValidateRegistrationRequest(std::wstring(0x4001, 'a').c_str(),
+                                           L"", L"", L"", L"", L"", L""));
+  ASSERT_FALSE(ValidateRegistrationRequest(
+      L"app_id", L"brand_code", L"brand_path", L"ap", L"invalidversion",
+      L"existence_checker_path", L"install_id"));
+
+  std::optional<RegistrationRequest> request = ValidateRegistrationRequest(
+      L"app_id", L"brand_code", L"brand_path", L"ap", L"1.2.3.4",
+      L"existence_checker_path", L"install_id");
+  ASSERT_TRUE(request);
+
+  RegistrationRequest expected_request;
+  expected_request.app_id = "app_id";
+  expected_request.brand_code = "brand_code";
+  expected_request.brand_path = base::FilePath(L"brand_path");
+  expected_request.ap = "ap";
+  expected_request.version = base::Version("1.2.3.4");
+  expected_request.existence_checker_path =
+      base::FilePath(L"existence_checker_path");
+  expected_request.install_id = "install_id";
+
+  ASSERT_EQ(request->app_id, expected_request.app_id);
+  ASSERT_EQ(request->brand_code, expected_request.brand_code);
+  ASSERT_EQ(request->brand_path, expected_request.brand_path);
+  ASSERT_EQ(request->ap, expected_request.ap);
+  ASSERT_EQ(request->ap_path, expected_request.ap_path);
+  ASSERT_EQ(request->ap_key, expected_request.ap_key);
+  ASSERT_EQ(request->version, expected_request.version);
+  ASSERT_EQ(request->version_path, expected_request.version_path);
+  ASSERT_EQ(request->version_key, expected_request.version_key);
+  ASSERT_EQ(request->existence_checker_path,
+            expected_request.existence_checker_path);
+}
+
+}  // namespace updater::test
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 187cbd5..71cc9aa3 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16134.0.0-1065529
\ No newline at end of file
+16134.0.0-1065535
\ No newline at end of file
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index fb495d45..d639ad8 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -6481,6 +6481,9 @@
         <message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ACCESSIBILITY" desc="The text read aloud by the screen reader describing the keyboard icon 'accessibility'.">
           accessibility options
         </message>
+        <message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB" desc="The text read aloud by the screen reader describing the keyboard icon 'do not disturb'.">
+          do not disturb
+        </message>
 
         <!-- End of Shortcut Customization -->
 
diff --git a/chromeos/chromeos_strings_grd/IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB.png.sha1
new file mode 100644
index 0000000..fdd9100
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_DO_NOT_DISTURB.png.sha1
@@ -0,0 +1 @@
+393e8fc4eefadd8ed530dab644abc08dacc750a6
\ No newline at end of file
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index 2bacc998e..65e4c14 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -112,7 +112,6 @@
     "volume_manager.mojom",
     "vpn_extension_observer.mojom",
     "vpn_service.mojom",
-    "wallpaper.mojom",
     "web_app_service.mojom",
     "web_app_types.mojom",
     "web_kiosk_service.mojom",
diff --git a/clank b/clank
index 9a87c33..c21490b 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 9a87c3392f476429eccefd7ed2a1689dfc378c9d
+Subproject commit c21490b893c1a3efa293da12c73480149478ce73
diff --git a/components/crash/core/browser/resources/BUILD.gn b/components/crash/core/browser/resources/BUILD.gn
index 40bc307..d871ced 100644
--- a/components/crash/core/browser/resources/BUILD.gn
+++ b/components/crash/core/browser/resources/BUILD.gn
@@ -8,8 +8,8 @@
   grd_prefix = "crashes"
 
   static_files = [
-    "crashes.html",
     "crashes.css",
+    "crashes.html",
     "sadtab.svg",
   ]
 
diff --git a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/configs/DataSharingUiConfig.java b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/configs/DataSharingUiConfig.java
index 71e103d2..832dcf7 100644
--- a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/configs/DataSharingUiConfig.java
+++ b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/configs/DataSharingUiConfig.java
@@ -30,7 +30,7 @@
         // TODO (ritikagup) : Cleanup this method, once the overloaded method is fully integrated.
         default void onLearnMoreAboutSharedTabGroupsClicked(GURL url) {}
 
-        default void onLearnMoreAboutSharedTabGroupsClicked(Context context, String url) {}
+        default void onLearnMoreAboutSharedTabGroupsClicked(Context context, GURL url) {}
     }
 
     private DataSharingUiConfig(Builder builder) {
diff --git a/components/desks_storage/core/desk_model_wrapper.cc b/components/desks_storage/core/desk_model_wrapper.cc
index d2776e643..02c8d20 100644
--- a/components/desks_storage/core/desk_model_wrapper.cc
+++ b/components/desks_storage/core/desk_model_wrapper.cc
@@ -9,14 +9,13 @@
 #include "base/uuid.h"
 #include "components/account_id/account_id.h"
 #include "components/desks_storage/core/desk_model.h"
-#include "desk_sync_bridge.h"
-#include "local_desk_data_manager.h"
+#include "components/desks_storage/core/local_desk_data_manager.h"
 
 namespace desks_storage {
 
 DeskModelWrapper::DeskModelWrapper(
-    desks_storage::DeskModel* save_and_recall_desks_model)
-    : save_and_recall_desks_model_(save_and_recall_desks_model) {}
+    desks_storage::DeskModel* saved_desks_and_groups_model)
+    : saved_desks_and_groups_model_(saved_desks_and_groups_model) {}
 
 DeskModelWrapper::~DeskModelWrapper() = default;
 
@@ -28,17 +27,19 @@
     return templates_result;
   }
 
-  DeskModel::GetAllEntriesResult save_and_recall_result =
-      save_and_recall_desks_model_->GetAllEntries();
+  DeskModel::GetAllEntriesResult saved_desk_or_group_result =
+      saved_desks_and_groups_model_->GetAllEntries();
 
-  if (save_and_recall_result.status != DeskModel::GetAllEntriesStatus::kOk) {
-    return save_and_recall_result;
+  if (saved_desk_or_group_result.status !=
+      DeskModel::GetAllEntriesStatus::kOk) {
+    return saved_desk_or_group_result;
   }
 
   std::vector<raw_ptr<const ash::DeskTemplate, VectorExperimental>>&
       all_entries = templates_result.entries;
 
-  for (const ash::DeskTemplate* const entry : save_and_recall_result.entries) {
+  for (const ash::DeskTemplate* const entry :
+       saved_desk_or_group_result.entries) {
     all_entries.push_back(entry);
   }
 
@@ -63,7 +64,7 @@
   if (GetDeskTemplateModel()->HasUuid(uuid)) {
     return GetDeskTemplateModel()->GetEntryByUUID(uuid);
   } else {
-    return save_and_recall_desks_model_->GetEntryByUUID(uuid);
+    return saved_desks_and_groups_model_->GetEntryByUUID(uuid);
   }
 }
 
@@ -77,11 +78,11 @@
                                                std::move(callback));
       return;
     case ash::DeskTemplateType::kSaveAndRecall:
-      save_and_recall_desks_model_->AddOrUpdateEntry(std::move(new_entry),
-                                                     std::move(callback));
+    case ash::DeskTemplateType::kCoral:
+      saved_desks_and_groups_model_->AddOrUpdateEntry(std::move(new_entry),
+                                                      std::move(callback));
       return;
     // Return kInvalidArgument on an unknown desk type.
-    case ash::DeskTemplateType::kCoral:
     case ash::DeskTemplateType::kUnknown:
       std::move(callback).Run(AddOrUpdateEntryStatus::kInvalidArgument,
                               std::move(new_entry));
@@ -95,7 +96,7 @@
   if (GetDeskTemplateModel()->HasUuid(uuid)) {
     GetDeskTemplateModel()->DeleteEntry(uuid, std::move(callback));
   } else {
-    save_and_recall_desks_model_->DeleteEntry(uuid, std::move(callback));
+    saved_desks_and_groups_model_->DeleteEntry(uuid, std::move(callback));
   }
 }
 
@@ -107,7 +108,7 @@
     std::move(callback).Run(desk_template_delete_status);
     return;
   }
-  save_and_recall_desks_model_->DeleteAllEntries(
+  saved_desks_and_groups_model_->DeleteAllEntries(
       base::BindOnce(&DeskModelWrapper::OnDeleteAllEntries,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -115,11 +116,12 @@
 // TODO(crbug.com/1320805): Remove this function once both desk models support
 // desk type counts.
 size_t DeskModelWrapper::GetEntryCount() const {
-  return GetSaveAndRecallDeskEntryCount() + GetDeskTemplateEntryCount();
+  return GetCoralEntryCount() + GetSaveAndRecallDeskEntryCount() +
+         GetDeskTemplateEntryCount();
 }
 
 size_t DeskModelWrapper::GetSaveAndRecallDeskEntryCount() const {
-  return save_and_recall_desks_model_->GetSaveAndRecallDeskEntryCount();
+  return saved_desks_and_groups_model_->GetSaveAndRecallDeskEntryCount();
 }
 
 size_t DeskModelWrapper::GetDeskTemplateEntryCount() const {
@@ -128,11 +130,11 @@
 }
 
 size_t DeskModelWrapper::GetCoralEntryCount() const {
-  return 0u;
+  return saved_desks_and_groups_model_->GetCoralEntryCount();
 }
 
 size_t DeskModelWrapper::GetMaxSaveAndRecallDeskEntryCount() const {
-  return save_and_recall_desks_model_->GetMaxSaveAndRecallDeskEntryCount();
+  return saved_desks_and_groups_model_->GetMaxSaveAndRecallDeskEntryCount();
 }
 
 size_t DeskModelWrapper::GetMaxDeskTemplateEntryCount() const {
@@ -141,7 +143,7 @@
 }
 
 size_t DeskModelWrapper::GetMaxCoralEntryCount() const {
-  return 0u;
+  return saved_desks_and_groups_model_->GetMaxCoralEntryCount();
 }
 
 std::set<base::Uuid> DeskModelWrapper::GetAllEntryUuids() const {
@@ -150,9 +152,9 @@
   for (const auto& it : policy_entries_)
     keys.emplace(it.get()->uuid());
 
-  for (const auto& save_and_recall_uuid :
-       save_and_recall_desks_model_->GetAllEntryUuids()) {
-    keys.emplace(save_and_recall_uuid);
+  for (const auto& saved_desk_or_group_uuid :
+       saved_desks_and_groups_model_->GetAllEntryUuids()) {
+    keys.emplace(saved_desk_or_group_uuid);
   }
 
   for (const auto& desk_template_uuid :
@@ -163,7 +165,7 @@
 }
 
 bool DeskModelWrapper::IsReady() const {
-  return save_and_recall_desks_model_->IsReady() &&
+  return saved_desks_and_groups_model_->IsReady() &&
          GetDeskTemplateModel()->IsReady();
 }
 
@@ -180,9 +182,9 @@
     case ash::DeskTemplateType::kFloatingWorkspace:
       return GetDeskTemplateModel()->FindOtherEntryWithName(name, type, uuid);
     case ash::DeskTemplateType::kSaveAndRecall:
-      return save_and_recall_desks_model_->FindOtherEntryWithName(name, type,
-                                                                  uuid);
     case ash::DeskTemplateType::kCoral:
+      return saved_desks_and_groups_model_->FindOtherEntryWithName(name, type,
+                                                                   uuid);
     case ash::DeskTemplateType::kUnknown:
       return nullptr;
   }
diff --git a/components/desks_storage/core/desk_model_wrapper.h b/components/desks_storage/core/desk_model_wrapper.h
index 6087173..4c5e3829 100644
--- a/components/desks_storage/core/desk_model_wrapper.h
+++ b/components/desks_storage/core/desk_model_wrapper.h
@@ -73,7 +73,8 @@
   void OnDeleteAllEntries(DeskModel::DeleteEntryCallback callback,
                           desks_storage::DeskModel::DeleteEntryStatus status);
 
-  raw_ptr<desks_storage::DeskModel> save_and_recall_desks_model_;
+  // The local model used for save and recall and coral saved groups.
+  raw_ptr<desks_storage::DeskModel> saved_desks_and_groups_model_;
 
   raw_ptr<desks_storage::DeskSyncBridge> desk_template_model_;
 
diff --git a/components/download/resources/download_internals/BUILD.gn b/components/download/resources/download_internals/BUILD.gn
index f11eef0..f55e4fa 100644
--- a/components/download/resources/download_internals/BUILD.gn
+++ b/components/download/resources/download_internals/BUILD.gn
@@ -13,9 +13,9 @@
   ]
 
   non_web_component_files = [
+    "download_internals.ts",
     "download_internals_browser_proxy.ts",
     "download_internals_visuals.ts",
-    "download_internals.ts",
   ]
 
   ts_deps = [
diff --git a/components/history_clusters/core/config.cc b/components/history_clusters/core/config.cc
index c4726f5..f4e18a7 100644
--- a/components/history_clusters/core/config.cc
+++ b/components/history_clusters/core/config.cc
@@ -190,22 +190,6 @@
             number_interesting_visits_filter_threshold);
   }
 
-  // The `kUseEngagementScoreCache` feature and child params.
-  {
-    use_engagement_score_cache =
-        base::FeatureList::IsEnabled(features::kUseEngagementScoreCache);
-
-    engagement_score_cache_size = GetFieldTrialParamByFeatureAsInt(
-        features::kUseEngagementScoreCache, "engagement_score_cache_size",
-        engagement_score_cache_size);
-
-    engagement_score_cache_refresh_duration =
-        base::Minutes(GetFieldTrialParamByFeatureAsInt(
-            features::kUseEngagementScoreCache,
-            "engagement_score_cache_refresh_duration_minutes",
-            engagement_score_cache_refresh_duration.InMinutes()));
-  }
-
   // The `kHistoryClustersVisitDeduping` feature and child params.
   {
     use_host_for_visit_deduping = GetFieldTrialParamByFeatureAsBool(
diff --git a/components/history_clusters/core/config.h b/components/history_clusters/core/config.h
index 6f0cf2f..107f639 100644
--- a/components/history_clusters/core/config.h
+++ b/components/history_clusters/core/config.h
@@ -191,20 +191,6 @@
   // on the zero state UI).
   size_t number_interesting_visits_filter_threshold = 1;
 
-  // The `kUseEngagementScoreCache` feature and child params.
-
-  // Whether to use a cache to store the site engagement scores per host. Used
-  // in both the old (OnDeviceClusteringBackend) and new
-  // (ContextClustererHistoryServiceObserver) clustering paths.
-  bool use_engagement_score_cache = true;
-
-  // The max number of hosts that should be stored in the engagement score
-  // cache.
-  int engagement_score_cache_size = 100;
-
-  // The max time a host should be stored in the engagement score cache.
-  base::TimeDelta engagement_score_cache_refresh_duration = base::Minutes(120);
-
   // The `kHistoryClustersVisitDeduping` feature and child params.
 
   // Use host instead of heavily-stripped URL as URL for deduping.
diff --git a/components/history_clusters/core/context_clusterer_history_service_observer.cc b/components/history_clusters/core/context_clusterer_history_service_observer.cc
index 6fc9bf0..08a77f8 100644
--- a/components/history_clusters/core/context_clusterer_history_service_observer.cc
+++ b/components/history_clusters/core/context_clusterer_history_service_observer.cc
@@ -19,6 +19,10 @@
 
 namespace {
 
+constexpr int kEngagementScoreCacheSize = 100;
+constexpr base::TimeDelta kEngagementScoreCacheRefreshDuration =
+    base::Minutes(120);
+
 // Returns whether `visit` should be added to `cluster`.
 bool ShouldAddVisitToCluster(const history::VisitRow& new_visit,
                              const std::u16string& search_terms,
@@ -129,7 +133,7 @@
     : history_service_(history_service),
       template_url_service_(template_url_service),
       optimization_guide_decider_(optimization_guide_decider),
-      engagement_score_cache_(GetConfig().engagement_score_cache_size),
+      engagement_score_cache_(kEngagementScoreCacheSize),
       engagement_score_provider_(engagement_score_provider),
       clock_(base::DefaultClock::GetInstance()) {
   if (history_service_) {
@@ -484,10 +488,6 @@
 
 float ContextClustererHistoryServiceObserver::GetEngagementScore(
     const GURL& normalized_url) {
-  if (!GetConfig().use_engagement_score_cache) {
-    return engagement_score_provider_->GetScore(normalized_url);
-  }
-
   std::string visit_host = normalized_url.host();
   auto it = engagement_score_cache_.Peek(visit_host);
   if (it != engagement_score_cache_.end() &&
@@ -499,8 +499,7 @@
   engagement_score_cache_.Put(
       visit_host,
       CachedEngagementScore(
-          score,
-          clock_->Now() + GetConfig().engagement_score_cache_refresh_duration));
+          score, clock_->Now() + kEngagementScoreCacheRefreshDuration));
   return score;
 }
 
diff --git a/components/history_clusters/core/on_device_clustering_backend.cc b/components/history_clusters/core/on_device_clustering_backend.cc
index 778a65e7..fb2cb797 100644
--- a/components/history_clusters/core/on_device_clustering_backend.cc
+++ b/components/history_clusters/core/on_device_clustering_backend.cc
@@ -42,6 +42,8 @@
 
 namespace {
 
+constexpr int kEngagementScoreCacheSize = 100;
+
 void RecordBatchUpdateProcessingTime(base::TimeDelta time_delta) {
   base::UmaHistogramTimes(
       "History.Clusters.Backend.ProcessBatchOfVisits.ThreadTime", time_delta);
@@ -74,7 +76,7 @@
                   ? continue_on_shutdown_best_effort_task_traits_
                   : best_effort_task_traits_)),
       engagement_score_cache_last_refresh_timestamp_(base::TimeTicks::Now()),
-      engagement_score_cache_(GetConfig().engagement_score_cache_size) {
+      engagement_score_cache_(kEngagementScoreCacheSize) {
   if (GetConfig().should_check_hosts_to_skip_clustering_for &&
       optimization_guide_decider) {
     optimization_guide_decider_ = optimization_guide_decider;
diff --git a/components/history_clusters/core/on_device_clustering_features.cc b/components/history_clusters/core/on_device_clustering_features.cc
index 6fbfd5f4..7beac01 100644
--- a/components/history_clusters/core/on_device_clustering_features.cc
+++ b/components/history_clusters/core/on_device_clustering_features.cc
@@ -18,10 +18,6 @@
              "HistoryClustersOnDeviceClustering",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kUseEngagementScoreCache,
-             "JourneysUseEngagementScoreCache",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kOnDeviceClusteringBlocklists,
              "JourneysOnDeviceClusteringBlocklist",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/history_clusters/core/on_device_clustering_features.h b/components/history_clusters/core/on_device_clustering_features.h
index 9f13c65..20e566f 100644
--- a/components/history_clusters/core/on_device_clustering_features.h
+++ b/components/history_clusters/core/on_device_clustering_features.h
@@ -17,9 +17,6 @@
 // Enables configuring the on-device clustering backend.
 BASE_DECLARE_FEATURE(kOnDeviceClustering);
 
-// Uses an in-memory cache that stores engagement score.
-BASE_DECLARE_FEATURE(kUseEngagementScoreCache);
-
 // Specifies various blocklists for on-device clustering backend.
 BASE_DECLARE_FEATURE(kOnDeviceClusteringBlocklists);
 
diff --git a/components/history_embeddings/history_embeddings_features.cc b/components/history_embeddings/history_embeddings_features.cc
index 8c322661..59a83b4c 100644
--- a/components/history_embeddings/history_embeddings_features.cc
+++ b/components/history_embeddings/history_embeddings_features.cc
@@ -235,6 +235,10 @@
     "WordMatchSearchNonAsciiPassages",
     false);
 
+const base::FeatureParam<bool> kInsertTitlePassage(&kHistoryEmbeddings,
+                                                   "InsertTitlePassage",
+                                                   false);
+
 FeatureParameters::FeatureParameters(bool load_finch) {
   if (!load_finch) {
     return;
@@ -284,6 +288,7 @@
   scroll_tags_enabled = kScrollTagsEnabled.Get();
   erase_non_ascii_characters = kEraseNonAsciiCharacters.Get();
   word_match_search_non_ascii_passages = kWordMatchSearchNonAsciiPassages.Get();
+  insert_title_passage = kInsertTitlePassage.Get();
 }
 
 FeatureParameters::FeatureParameters(const FeatureParameters&) = default;
diff --git a/components/history_embeddings/history_embeddings_features.h b/components/history_embeddings/history_embeddings_features.h
index 10e67af7..3bca4e1 100644
--- a/components/history_embeddings/history_embeddings_features.h
+++ b/components/history_embeddings/history_embeddings_features.h
@@ -184,6 +184,12 @@
   // characters. See also `word_match_min_embedding_score`, which this bypasses.
   // Note, when `erase_non_ascii_characters` is true, this will have no effect.
   bool word_match_search_non_ascii_passages = false;
+
+  // Whether to insert the web contents title as the first passage when it
+  // isn't already in the set of extracted passages. Enabling this can help
+  // recall for URLs that have a title after the tab loads, for example PDF
+  // documents where there is no DOM and hence no <title> tag text to extract.
+  bool insert_title_passage = false;
 };
 
 // Use this to apply changes for testing only while an instance lives.
diff --git a/components/omnibox/browser/featured_search_provider.cc b/components/omnibox/browser/featured_search_provider.cc
index 8d44caa..42dcaa4 100644
--- a/components/omnibox/browser/featured_search_provider.cc
+++ b/components/omnibox/browser/featured_search_provider.cc
@@ -246,7 +246,7 @@
     if (OmniboxFieldTrial::IsStarterPackExpansionEnabled() &&
         template_url.starter_pack_id() == TemplateURLStarterPackData::kGemini) {
       match.description = l10n_util::GetStringFUTF16(
-          IDS_OMNIBOX_INSTANT_KEYWORD_CHAT_TEXT, template_url.keyword(),
+          IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT, template_url.keyword(),
           template_url.short_name());
       match.relevance = kGeminiRelevance;
     } else {
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index a2270b26a..d2eb39be9 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -321,17 +321,17 @@
   <message name="IDS_SEARCH_ENGINES_STARTER_PACK_GEMINI_NAME" desc = "The name of the Gemini engine as it appears on chrome://settings/searchEngines.">
     Gemini
   </message>
-  <message name="IDS_SEARCH_ENGINES_STARTER_PACK_GEMINI_KEYWORD" desc = "The keyword required to trigger Chat with Gemini in keyword mode. This will be prepended with an '@'.">
+  <message name="IDS_SEARCH_ENGINES_STARTER_PACK_GEMINI_KEYWORD" desc = "The keyword required to trigger Ask Gemini in keyword mode. This will be prepended with an '@'.">
     Gemini
   </message>
-  <message name="IDS_OMNIBOX_INSTANT_KEYWORD_CHAT_TEXT" desc="Text shown in an omnibox suggestion ready for instant keyword search when the destination is suitable for chatting. For example, starter pack suggestions like @gemini will chat with Gemini.">
-    <ph name="KEYWORD">$1<ex>@gemini</ex></ph> - Chat with <ph name="KEYWORD_SHORT_NAME">$2<ex>Gemini</ex></ph>
+  <message name="IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT" desc="Text shown in an omnibox suggestion ready for instant keyword search when the destination is suitable for asking. For example, starter pack suggestions like @gemini will Ask Gemini.">
+    <ph name="KEYWORD">$1<ex>@gemini</ex></ph> - Ask <ph name="KEYWORD_SHORT_NAME">$2<ex>Gemini</ex></ph>
   </message>
   <message name="IDS_OMNIBOX_INSTANT_KEYWORD_SEARCH_TEXT" desc="Text shown in an omnibox suggestion ready for instant keyword search when the destination is suitable for searching. For example, starter pack suggestions like @bookmarks will search Bookmarks.">
     <ph name="KEYWORD">$1<ex>@bookmarks</ex></ph> - Search <ph name="KEYWORD_SHORT_NAME">$2<ex>Bookmarks</ex></ph>
   </message>
-  <message name="IDS_OMNIBOX_SELECTED_KEYWORD_CHAT_TEXT" desc="Text shown at the front of the Omnibox when a user has selected a keyword that is suitable for chatting. For example, starter pack suggestions like @gemini will chat with Gemini.">
-    Chat with <ph name="KEYWORD_SHORT_NAME">$1<ex>Gemini</ex></ph>
+  <message name="IDS_OMNIBOX_SELECTED_KEYWORD_ASK_TEXT" desc="Text shown at the front of the Omnibox when a user has selected a keyword that is suitable for asking. For example, starter pack suggestions like @gemini will Ask Gemini.">
+    Ask <ph name="KEYWORD_SHORT_NAME">$1<ex>Gemini</ex></ph>
   </message>
 
   <!-- No results description for the Starter Pack's tab search feature (@tabs). This appears as the first suggestion when no matching tabs are found. -->
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT.png.sha1
new file mode 100644
index 0000000..5ff5fa3
--- /dev/null
+++ b/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_ASK_TEXT.png.sha1
@@ -0,0 +1 @@
+ae8613e216fa69dfa1480bc8582e0fab7f09b8d8
\ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_CHAT_TEXT.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_CHAT_TEXT.png.sha1
deleted file mode 100644
index ee0461c..0000000
--- a/components/omnibox_strings_grdp/IDS_OMNIBOX_INSTANT_KEYWORD_CHAT_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b9ba8188ba7255502114bffc1f2908f4a6998555
\ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_ASK_TEXT.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_ASK_TEXT.png.sha1
new file mode 100644
index 0000000..5ff5fa3
--- /dev/null
+++ b/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_ASK_TEXT.png.sha1
@@ -0,0 +1 @@
+ae8613e216fa69dfa1480bc8582e0fab7f09b8d8
\ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_CHAT_TEXT.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_CHAT_TEXT.png.sha1
deleted file mode 100644
index 0eaaa82..0000000
--- a/components/omnibox_strings_grdp/IDS_OMNIBOX_SELECTED_KEYWORD_CHAT_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3bccb5520c44dfe039f0a419a1f28a7873f2b2d4
\ No newline at end of file
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index be08527..ad25fb3 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit be08527a88307c18e6c8e1d60d4edad905ce57da
+Subproject commit ad25fb362531d62c3c06cbf57e18b3ce5a016473
diff --git a/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn b/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
index 01ac7078..f7644715 100644
--- a/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
+++ b/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
@@ -8,8 +8,8 @@
   grd_prefix = "optimization_guide_internals"
 
   static_files = [
-    "optimization_guide_internals.html",
     "optimization_guide_internals.css",
+    "optimization_guide_internals.html",
   ]
 
   non_web_component_files = [
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 09c335d..b46b49ac 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -195,7 +195,6 @@
     "public/resource_attribution/resource_types.h",
     "public/resource_attribution/type_helpers.h",
     "public/resource_attribution/worker_context.h",
-    "public/scenarios/performance_scenario_observer.h",
     "public/scenarios/performance_scenarios.h",
     "public/tracing_support.h",
     "public/user_tuning/prefs.h",
@@ -246,7 +245,6 @@
     "scenarios/loading_scenario_observer.h",
     "scenarios/performance_scenario_data.cc",
     "scenarios/performance_scenario_data.h",
-    "scenarios/performance_scenario_oberver.cc",
     "scenarios/performance_scenarios.cc",
     "service_worker_context_adapter.cc",
     "service_worker_context_adapter.h",
diff --git a/components/performance_manager/graph_features.cc b/components/performance_manager/graph_features.cc
index 32e77b4b..a14c241 100644
--- a/components/performance_manager/graph_features.cc
+++ b/components/performance_manager/graph_features.cc
@@ -22,7 +22,6 @@
 #include "components/performance_manager/public/decorators/tab_page_decorator.h"
 #include "components/performance_manager/public/graph/graph.h"
 #include "components/performance_manager/public/metrics/metrics_collector.h"
-#include "components/performance_manager/public/scenarios/performance_scenario_observer.h"
 #include "components/performance_manager/resource_attribution/query_scheduler.h"
 #include "components/performance_manager/scenarios/loading_scenario_observer.h"
 #include "components/performance_manager/v8_memory/v8_context_tracker.h"
@@ -79,7 +78,6 @@
   }
   if (flags_.performance_scenarios) {
     Install<LoadingScenarioObserver>(graph);
-    Install<PerformanceScenarioNotifier>(graph);
   }
   if (flags_.resource_attribution_scheduler) {
     Install<resource_attribution::internal::QueryScheduler>(graph);
diff --git a/components/performance_manager/public/scenarios/performance_scenario_observer.h b/components/performance_manager/public/scenarios/performance_scenario_observer.h
deleted file mode 100644
index 6f405b3d..0000000
--- a/components/performance_manager/public/scenarios/performance_scenario_observer.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PERFORMANCE_SCENARIO_OBSERVER_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PERFORMANCE_SCENARIO_OBSERVER_H_
-
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
-#include "base/sequence_checker.h"
-#include "components/performance_manager/public/graph/graph_registered.h"
-#include "third_party/blink/public/common/performance/performance_scenarios.h"
-
-namespace performance_manager {
-
-class ProcessNode;
-
-// Convenience aliases.
-using LoadingScenario = blink::performance_scenarios::LoadingScenario;
-using InputScenario = blink::performance_scenarios::InputScenario;
-
-class PerformanceScenarioObserver : public base::CheckedObserver {
- public:
-  // Invoked whenever the given scenario changes for all pages.
-  virtual void OnGlobalLoadingScenarioChanged(LoadingScenario old_scenario,
-                                              LoadingScenario new_scenario) {}
-  virtual void OnGlobalInputScenarioChanged(InputScenario old_scenario,
-                                            InputScenario new_scenario) {}
-
-  // Invoked whenever the given scenario changes for pages hosted partially in
-  // `process_node`.
-  virtual void OnProcessLoadingScenarioChanged(const ProcessNode* process_node,
-                                               LoadingScenario old_scenario,
-                                               LoadingScenario new_scenario) {}
-  virtual void OnProcessInputScenarioChanged(const ProcessNode* process_node,
-                                             InputScenario old_scenario,
-                                             InputScenario new_scenario) {}
-};
-
-class PerformanceScenarioNotifier final
-    : public GraphOwnedAndRegistered<PerformanceScenarioNotifier> {
- public:
-  PerformanceScenarioNotifier();
-  ~PerformanceScenarioNotifier() final;
-
-  PerformanceScenarioNotifier(const PerformanceScenarioNotifier&) = delete;
-  PerformanceScenarioNotifier& operator=(const PerformanceScenarioNotifier&) =
-      delete;
-
-  void AddGlobalObserver(PerformanceScenarioObserver* observer);
-  void RemoveGlobalObserver(const PerformanceScenarioObserver* observer);
-
-  void AddObserverForProcess(const ProcessNode* process_node,
-                             PerformanceScenarioObserver* observer);
-  void RemoveObserverForProcess(const ProcessNode* process_node,
-                                const PerformanceScenarioObserver* observer);
-
- private:
-  // Allow PerformanceScenarioNotifierAccessor to read the observer lists.
-  friend class PerformanceScenarioNotifierAccessor;
-
-  using ObserverList = base::ObserverList<PerformanceScenarioObserver>;
-
-  ObserverList* GetGlobalObservers();
-  ObserverList* GetProcessObservers(const ProcessNode* process_node);
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  ObserverList global_observers_ GUARDED_BY_CONTEXT(sequence_checker_);
-};
-
-}  // namespace performance_manager
-
-#endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PERFORMANCE_SCENARIO_OBSERVER_H_
diff --git a/components/performance_manager/resource_attribution/cpu_measurement_monitor.cc b/components/performance_manager/resource_attribution/cpu_measurement_monitor.cc
index 8e62232..933c69f 100644
--- a/components/performance_manager/resource_attribution/cpu_measurement_monitor.cc
+++ b/components/performance_manager/resource_attribution/cpu_measurement_monitor.cc
@@ -22,6 +22,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
 #include "base/numerics/clamped_math.h"
 #include "base/sequence_checker.h"
 #include "base/strings/strcat.h"
@@ -130,7 +131,7 @@
   CHECK(!graph_);
   CHECK(measurement_results_.empty());
   CHECK(dead_context_results_.empty());
-  CHECK(origin_in_browsing_instance_weak_results_.empty());
+  CHECK(weak_origin_results_.empty());
   graph_ = graph;
   graph_->AddFrameNodeObserver(this);
   graph_->AddPageNodeObserver(this);
@@ -154,7 +155,7 @@
   }
   measurement_results_.clear();
   dead_context_results_.clear();
-  origin_in_browsing_instance_weak_results_.clear();
+  weak_origin_results_.clear();
   graph_->RemoveFrameNodeObserver(this);
   graph_->RemovePageNodeObserver(this);
   graph_->RemoveProcessNodeObserver(this);
@@ -211,31 +212,30 @@
   // contexts that have measurement deltas where as
   // GetLiveOriginInBrowsingInstanceContexts() below iterates over all resource
   // contexts.
-  const std::set<OriginInBrowsingInstanceContext>
-      live_origin_in_browsing_instance_contexts =
-          GetLiveOriginInBrowsingInstanceContexts();
+  const std::set<OriginInBrowsingInstanceContext> live_origin_contexts =
+      GetLiveOriginInBrowsingInstanceContexts();
 
-  // Populate `results` with CPU results for all live contexts, and list dead
+  // Populate `results` with CPU results for all live contexts, and remove dead
   // `OriginInBrowsingInstanceContext`s referenced by `measurement_results_`.
   QueryResultMap results;
-  std::vector<ResourceContext> dead_origin_in_browsing_instance_contexts;
-  for (const auto& [context, result_ptr] : measurement_results_) {
+  for (auto it = measurement_results_.begin();
+       it != measurement_results_.end();) {
+    const ResourceContext& context = it->first;
+    ScopedCPUTimeResultPtr& result_ptr = it->second;
     CHECK(result_ptr);
     if (ContextIs<OriginInBrowsingInstanceContext>(context) &&
-        !base::Contains(live_origin_in_browsing_instance_contexts,
+        !base::Contains(live_origin_contexts,
                         AsContext<OriginInBrowsingInstanceContext>(context))) {
-      dead_origin_in_browsing_instance_contexts.push_back(context);
+      SaveFinalMeasurement(std::move(result_ptr));
+      it = measurement_results_.erase(it);
     } else {
       ValidateCPUTimeResult(result_ptr->result());
       results.emplace(context,
                       QueryResults{.cpu_time_result = result_ptr->result()});
+      ++it;
     }
   }
 
-  // Move results for dead `OriginInBrowsingInstanceContext`s from
-  // `measurement_results_` to `dead_context_results_`.
-  SaveFinalMeasurements(dead_origin_in_browsing_instance_contexts);
-
   // Populate `results` with CPU results for contexts that became dead since the
   // last time this query got an update (note: non-repeating queries don't get
   // results for dead contexts).
@@ -396,7 +396,7 @@
   // Take a measurement of the process CPU usage, including this frame, so that
   // its final CPU usage is attributed to it before it's removed.
   UpdateCPUMeasurements(frame_node->GetProcessNode());
-  SaveFinalMeasurements({frame_node->GetResourceContext()});
+  SaveFinalMeasurement(frame_node->GetResourceContext());
 }
 
 void CPUMeasurementMonitor::OnOriginChanged(
@@ -414,8 +414,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // No need to call UpdateCPUMeasurements() since a measurement was taken when
   // the last frame was removed from the page.
-  const PageContext& page_context = page_node->GetResourceContext();
-  SaveFinalMeasurements({page_context});
+  SaveFinalMeasurement(page_node->GetResourceContext());
 }
 
 void CPUMeasurementMonitor::OnProcessLifetimeChange(
@@ -439,7 +438,7 @@
   // TODO(crbug.com/325330345): Capture the full final measurement reported
   // through ChildProcessTerminationInfo::cpu_usage.
   UpdateCPUMeasurements(process_node);
-  SaveFinalMeasurements({process_node->GetResourceContext()});
+  SaveFinalMeasurement(process_node->GetResourceContext());
 }
 
 void CPUMeasurementMonitor::OnPriorityChanged(
@@ -465,7 +464,7 @@
   // Take a measurement of the process CPU usage, including this node, so that
   // its final CPU usage is attributed to it before it's removed.
   UpdateCPUMeasurements(worker_node->GetProcessNode());
-  SaveFinalMeasurements({worker_node->GetResourceContext()});
+  SaveFinalMeasurement(worker_node->GetResourceContext());
 }
 
 void CPUMeasurementMonitor::OnBeforeClientFrameAdded(
@@ -580,37 +579,21 @@
   ApplyMeasurementDeltas(measurement_deltas, graph_change);
 }
 
-std::pair<CPUTimeResult&, bool>
-CPUMeasurementMonitor::GetOrCreateResultForContext(
-    const ResourceContext& context,
-    const CPUTimeResult& init_result) {
+CPUMeasurementMonitor::ScopedCPUTimeResultPtr&
+CPUMeasurementMonitor::GetResultPtr(const ResourceContext& context) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  ValidateCPUTimeResult(init_result);
-  auto [it, inserted] =
-      measurement_results_.try_emplace(context, ScopedCPUTimeResultPtr());
-  if (inserted) {
-    CHECK(!it->second);
-
+  auto [it, inserted] = measurement_results_.try_emplace(context, nullptr);
+  ScopedCPUTimeResultPtr& result_ptr = it->second;
+  if (inserted && ContextIs<OriginInBrowsingInstanceContext>(context)) {
     // Check if there is a result for this `OriginInBrowsingInstanceContext`
     // which is still referenced by `dead_context_results_`.
-    if (ContextIs<OriginInBrowsingInstanceContext>(context)) {
-      auto result_it = origin_in_browsing_instance_weak_results_.find(
-          AsContext<OriginInBrowsingInstanceContext>(context));
-      if (result_it != origin_in_browsing_instance_weak_results_.end()) {
-        it->second = result_it->second;
-      }
-    }
-
-    if (!it->second) {
-      it->second =
-          base::MakeRefCounted<ScopedCPUTimeResult>(this, context, init_result);
-      return {it->second->result(), true};
+    auto result_it = weak_origin_results_.find(
+        AsContext<OriginInBrowsingInstanceContext>(context));
+    if (result_it != weak_origin_results_.end()) {
+      result_ptr = result_it->second;
     }
   }
-
-  CHECK(it->second);
-  ValidateCPUTimeResult(it->second->result());
-  return {it->second->result(), false};
+  return result_ptr;
 }
 
 void CPUMeasurementMonitor::ApplyMeasurementDeltas(
@@ -619,28 +602,30 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (const auto& [context, delta] : measurement_deltas) {
     CHECK(!ContextIs<PageContext>(context));
+    CHECK(!ContextIs<OriginInBrowsingInstanceContext>(context));
 
     // Add the new process, frame and worker measurements to the existing
-    // measurements.
-    ApplySequentialDelta(context, delta);
+    // measurements, and aggregate new frame and worker measurements to pages.
+    if (ContextIs<ProcessContext>(context)) {
+      ApplySequentialDelta(context, delta);
+    } else if (ContextIs<FrameContext>(context)) {
+      ApplySequentialDelta(context, delta);
 
-    // Aggregate new frame and worker measurements to pages.
-    if (ContextIs<FrameContext>(context)) {
       const FrameNode* frame_node =
           AsContext<FrameContext>(context).GetFrameNode();
       CHECK(frame_node);
       ApplyOverlappingDelta(frame_node->GetPageNode()->GetResourceContext(),
                             delta);
-      std::optional<OriginInBrowsingInstanceContext>
-          origin_in_browsing_instance_context =
-              OriginInBrowsingInstanceContextForNode(
-                  frame_node, frame_node->GetBrowsingInstanceId(),
-                  graph_change);
-      if (origin_in_browsing_instance_context.has_value()) {
-        ApplyOverlappingDelta(origin_in_browsing_instance_context.value(),
-                              delta);
+
+      std::optional<OriginInBrowsingInstanceContext> origin_context =
+          OriginInBrowsingInstanceContextForNode(
+              frame_node, frame_node->GetBrowsingInstanceId(), graph_change);
+      if (origin_context.has_value()) {
+        ApplyOverlappingDelta(origin_context.value(), delta);
       }
     } else if (ContextIs<WorkerContext>(context)) {
+      ApplySequentialDelta(context, delta);
+
       const WorkerNode* worker_node =
           AsContext<WorkerContext>(context).GetWorkerNode();
       CHECK(worker_node);
@@ -653,15 +638,16 @@
 
       for (content::BrowsingInstanceId browsing_instance :
            client_browsing_instances) {
-        std::optional<OriginInBrowsingInstanceContext>
-            origin_in_browsing_instance_context =
-                OriginInBrowsingInstanceContextForNode(
-                    worker_node, browsing_instance, graph_change);
-        if (origin_in_browsing_instance_context.has_value()) {
-          ApplyOverlappingDelta(origin_in_browsing_instance_context.value(),
-                                delta);
+        std::optional<OriginInBrowsingInstanceContext> origin_context =
+            OriginInBrowsingInstanceContextForNode(
+                worker_node, browsing_instance, graph_change);
+        if (origin_context.has_value()) {
+          ApplyOverlappingDelta(origin_context.value(), delta);
         }
       }
+    } else {
+      // That should cover all context types.
+      NOTREACHED();
     }
   }
 }
@@ -669,12 +655,16 @@
 void CPUMeasurementMonitor::ApplySequentialDelta(const ResourceContext& context,
                                                  const CPUTimeResult& delta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  auto [result, created] = GetOrCreateResultForContext(context, delta);
-  if (created) {
+  ValidateCPUTimeResult(delta);
+  ScopedCPUTimeResultPtr& result_ptr = GetResultPtr(context);
+  if (!result_ptr) {
+    result_ptr =
+        base::MakeRefCounted<ScopedCPUTimeResult>(this, context, delta);
     return;
   }
 
+  CPUTimeResult& result = result_ptr->result();
+  ValidateCPUTimeResult(result);
   CHECK_EQ(result.metadata.algorithm, delta.metadata.algorithm);
   CHECK_LE(result.metadata.measurement_time, delta.start_time);
   result.metadata.measurement_time = delta.metadata.measurement_time;
@@ -689,12 +679,17 @@
     const ResourceContext& context,
     const CPUTimeResult& delta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto [result, created] = GetOrCreateResultForContext(context, delta);
-  if (created) {
-    result.metadata.algorithm = MeasurementAlgorithm::kSum;
+  ValidateCPUTimeResult(delta);
+  ScopedCPUTimeResultPtr& result_ptr = GetResultPtr(context);
+  if (!result_ptr) {
+    result_ptr =
+        base::MakeRefCounted<ScopedCPUTimeResult>(this, context, delta);
+    result_ptr->result().metadata.algorithm = MeasurementAlgorithm::kSum;
     return;
   }
 
+  CPUTimeResult& result = result_ptr->result();
+  ValidateCPUTimeResult(result);
   CHECK_EQ(result.metadata.algorithm, MeasurementAlgorithm::kSum);
   result.metadata.measurement_time = std::max(result.metadata.measurement_time,
                                               delta.metadata.measurement_time);
@@ -706,67 +701,58 @@
   ValidateCPUTimeResult(result);
 }
 
-void CPUMeasurementMonitor::SaveFinalMeasurements(
-    const std::vector<ResourceContext>& contexts) {
+void CPUMeasurementMonitor::SaveFinalMeasurement(
+    const ResourceContext& context) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  for (const auto& context : contexts) {
-    auto it = measurement_results_.find(context);
-    if (it == measurement_results_.end()) {
-      continue;
-    }
-    // Copy the scoped_refptr to result list for every existing query_id.
-    const ScopedCPUTimeResultPtr& result_ptr = it->second;
-    for (auto& [query_id, dead_context_results_for_query] :
-         dead_context_results_) {
-      dead_context_results_for_query.to_report.emplace(result_ptr);
-    }
-    // Drop the scoped_refptr from the live measurement results. Now there's one
-    // reference for every query, and the CPUTimeResult will be deleted once all
-    // queries have gotten the result.
+  auto it = measurement_results_.find(context);
+  if (it != measurement_results_.end()) {
+    SaveFinalMeasurement(std::move(it->second));
     measurement_results_.erase(it);
   }
 }
 
+void CPUMeasurementMonitor::SaveFinalMeasurement(
+    ScopedCPUTimeResultPtr&& result_ptr) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CHECK(result_ptr);
+  // Copy the scoped_refptr to result list for every existing query_id.
+  for (auto& [query_id, dead_context_results_for_query] :
+       dead_context_results_) {
+    dead_context_results_for_query.to_report.emplace(result_ptr);
+  }
+  // When `result_ptr` goes out of scope it's dropped from the live measurement
+  // results. Now there's one reference for every query, and the CPUTimeResult
+  // will be deleted once all queries have gotten the result.
+}
+
 std::set<OriginInBrowsingInstanceContext>
 CPUMeasurementMonitor::GetLiveOriginInBrowsingInstanceContexts() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::set<OriginInBrowsingInstanceContext>
-      live_origin_in_browsing_instance_contexts;
-  for (const auto& [context, result_ptr] : measurement_results_) {
-    if (ContextIs<FrameContext>(context)) {
-      const FrameNode* frame_node =
-          AsContext<FrameContext>(context).GetFrameNode();
-      if (frame_node) {
-        std::optional<OriginInBrowsingInstanceContext>
-            origin_in_browsing_instance_context =
-                OriginInBrowsingInstanceContextForNode(
-                    frame_node, frame_node->GetBrowsingInstanceId());
-        if (origin_in_browsing_instance_context.has_value()) {
-          live_origin_in_browsing_instance_contexts.insert(
-              origin_in_browsing_instance_context.value());
-        }
-      }
-    } else if (ContextIs<WorkerContext>(context)) {
-      const WorkerNode* worker_node =
-          AsContext<WorkerContext>(context).GetWorkerNode();
-      CHECK(worker_node);
-      auto [_, client_browsing_instances] =
-          GetWorkerClientPagesAndBrowsingInstances(worker_node);
+  CHECK(graph_);
+  std::set<OriginInBrowsingInstanceContext> live_origin_contexts;
+  for (const FrameNode* frame_node : graph_->GetAllFrameNodes()) {
+    std::optional<OriginInBrowsingInstanceContext> origin_context =
+        OriginInBrowsingInstanceContextForNode(
+            frame_node, frame_node->GetBrowsingInstanceId());
+    if (origin_context.has_value()) {
+      live_origin_contexts.insert(origin_context.value());
+    }
+  }
+  for (const WorkerNode* worker_node : graph_->GetAllWorkerNodes()) {
+    auto [_, client_browsing_instances] =
+        GetWorkerClientPagesAndBrowsingInstances(worker_node);
 
-      for (content::BrowsingInstanceId browsing_instance :
-           client_browsing_instances) {
-        std::optional<OriginInBrowsingInstanceContext>
-            origin_in_browsing_instance_context =
-                OriginInBrowsingInstanceContextForNode(worker_node,
-                                                       browsing_instance);
-        if (origin_in_browsing_instance_context.has_value()) {
-          live_origin_in_browsing_instance_contexts.insert(
-              origin_in_browsing_instance_context.value());
-        }
+    for (content::BrowsingInstanceId browsing_instance :
+         client_browsing_instances) {
+      std::optional<OriginInBrowsingInstanceContext> origin_context =
+          OriginInBrowsingInstanceContextForNode(worker_node,
+                                                 browsing_instance);
+      if (origin_context.has_value()) {
+        live_origin_contexts.insert(origin_context.value());
       }
     }
   }
-  return live_origin_in_browsing_instance_contexts;
+  return live_origin_contexts;
 }
 
 CPUMeasurementMonitor::ScopedCPUTimeResult::ScopedCPUTimeResult(
@@ -775,18 +761,16 @@
     const CPUTimeResult& result)
     : monitor_(monitor), context_(context), result_(result) {
   if (ContextIs<OriginInBrowsingInstanceContext>(context_)) {
-    auto [_, inserted] =
-        monitor_->origin_in_browsing_instance_weak_results_.emplace(
-            AsContext<OriginInBrowsingInstanceContext>(context_), this);
+    auto [_, inserted] = monitor_->weak_origin_results_.emplace(
+        AsContext<OriginInBrowsingInstanceContext>(context_), this);
     CHECK(inserted);
   }
 }
 
 CPUMeasurementMonitor::ScopedCPUTimeResult::~ScopedCPUTimeResult() {
   if (ContextIs<OriginInBrowsingInstanceContext>(context_)) {
-    size_t num_erased =
-        monitor_->origin_in_browsing_instance_weak_results_.erase(
-            AsContext<OriginInBrowsingInstanceContext>(context_));
+    size_t num_erased = monitor_->weak_origin_results_.erase(
+        AsContext<OriginInBrowsingInstanceContext>(context_));
     CHECK_EQ(num_erased, 1U);
   }
 }
diff --git a/components/performance_manager/resource_attribution/cpu_measurement_monitor.h b/components/performance_manager/resource_attribution/cpu_measurement_monitor.h
index 3065a1dc..68fdf302 100644
--- a/components/performance_manager/resource_attribution/cpu_measurement_monitor.h
+++ b/components/performance_manager/resource_attribution/cpu_measurement_monitor.h
@@ -7,7 +7,7 @@
 
 #include <map>
 #include <optional>
-#include <vector>
+#include <set>
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
@@ -147,9 +147,8 @@
   //
   // If the context is an `OriginInBrowsingInstanceContext`, the
   // constructor/destructor maintain a non-owning pointer to `this` in
-  // `origin_in_browsing_instance_weak_results_`, allowing
-  // `GetOrCreateResultForContext()` to reuse a result that is still referenced
-  // by `dead_context_results_`.
+  // `weak_origin_results_`, allowing `GetResultPtr()` to reuse a result that is
+  // still referenced by `dead_context_results_`.
   class ScopedCPUTimeResult : public base::RefCounted<ScopedCPUTimeResult> {
    public:
     ScopedCPUTimeResult(CPUMeasurementMonitor* monitor,
@@ -192,12 +191,10 @@
   void UpdateCPUMeasurements(const ProcessNode* process_node,
                              GraphChange graph_change = NoGraphChange());
 
-  // Retrieves the existing `CPUTimeResult` for `context`, or creates one if it
-  // doesn't exist. If a new result is created, it is initialized with
-  // `init_result` and the second element of the returned pair is true.
-  std::pair<CPUTimeResult&, bool> GetOrCreateResultForContext(
-      const ResourceContext& context,
-      const CPUTimeResult& init_result);
+  // Retrieves the `CPUTimeResult` for `context` from `measurement_results_`. If
+  // no result exists, creates an empty map entry and returns a reference to a
+  // null pointer, which the caller must initialize.
+  ScopedCPUTimeResultPtr& GetResultPtr(const ResourceContext& context);
 
   // Adds the new measurements in `measurement_deltas` to
   // `measurement_results_`. `graph_change` is the event that triggered the
@@ -222,9 +219,12 @@
   void ApplyOverlappingDelta(const ResourceContext& context,
                              const CPUTimeResult& delta);
 
-  // Moves the measurements for `contexts` from `measurement_results_` to
-  // `dead_context_results_`.
-  void SaveFinalMeasurements(const std::vector<ResourceContext>& contexts);
+  // Moves the measurements for `context` into `dead_context_results_`.
+  void SaveFinalMeasurement(const ResourceContext& context);
+
+  // Moves `result_ptr` into `dead_context_results_`. `result_ptr` is passed by
+  // move to ensure the caller drops its reference to the live result.
+  void SaveFinalMeasurement(ScopedCPUTimeResultPtr&& result_ptr);
 
   // Returns all `OriginInBrowsingInstanceContext`s associated with live frame
   // or worker contexts.
@@ -255,8 +255,7 @@
   // A map of non-owning pointers to all `ScopedCPUTimeResult` instances
   // associated with `OriginInBrowsingInstanceContext`.
   std::map<OriginInBrowsingInstanceContext, raw_ptr<ScopedCPUTimeResult>>
-      origin_in_browsing_instance_weak_results_
-          GUARDED_BY_CONTEXT(sequence_checker_);
+      weak_origin_results_ GUARDED_BY_CONTEXT(sequence_checker_);
 
   // CPU time results for dead contexts retained by ScopedResourceUsageQuery.
   //
@@ -281,8 +280,8 @@
 
     // Results kept alive until the next measurement for this query, in case the
     // associated context is revived. If a context is revived while this set has
-    // a reference to its last result, `GetOrCreateResultForContext()` will
-    // retrieve it instead of creating a new one.
+    // a reference to its last result, GetResultPtr() will retrieve it instead
+    // of creating a new one.
     //
     // When a measurement for a query contains a result for a dead
     // `OriginInBrowsingInstanceContext`, the result is kept in the `kept_alive`
diff --git a/components/performance_manager/scenarios/performance_scenario_data.h b/components/performance_manager/scenarios/performance_scenario_data.h
index 2d3ce46f..4abac50 100644
--- a/components/performance_manager/scenarios/performance_scenario_data.h
+++ b/components/performance_manager/scenarios/performance_scenario_data.h
@@ -5,16 +5,13 @@
 #ifndef COMPONENTS_PERFORMANCE_MANAGER_SCENARIOS_PERFORMANCE_SCENARIO_DATA_H_
 #define COMPONENTS_PERFORMANCE_MANAGER_SCENARIOS_PERFORMANCE_SCENARIO_DATA_H_
 
-#include <memory>
 #include <optional>
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/structured_shared_memory.h"
-#include "base/observer_list.h"
 #include "base/types/optional_util.h"
 #include "components/performance_manager/graph/node_inline_data.h"
-#include "components/performance_manager/public/scenarios/performance_scenario_observer.h"
 #include "third_party/blink/public/common/performance/performance_scenarios.h"
 #include "third_party/perfetto/include/perfetto/tracing/track.h"
 
@@ -92,9 +89,6 @@
   // The shared scenario memory region for the process.
   scoped_refptr<RefCountedScenarioState> state_ptr =
       RefCountedScenarioState::Create();
-
-  // Observers to notify when a scenario in the shared memory changes.
-  std::unique_ptr<base::ObserverList<PerformanceScenarioObserver>> observers;
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/scenarios/performance_scenario_oberver.cc b/components/performance_manager/scenarios/performance_scenario_oberver.cc
deleted file mode 100644
index 3ee811b..0000000
--- a/components/performance_manager/scenarios/performance_scenario_oberver.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "base/check_op.h"
-#include "base/observer_list.h"
-#include "base/sequence_checker.h"
-#include "components/performance_manager/public/graph/graph.h"
-#include "components/performance_manager/public/graph/process_node.h"
-#include "components/performance_manager/public/scenarios/performance_scenario_observer.h"
-#include "components/performance_manager/scenarios/performance_scenario_data.h"
-
-namespace performance_manager {
-
-PerformanceScenarioNotifier::PerformanceScenarioNotifier() = default;
-
-PerformanceScenarioNotifier::~PerformanceScenarioNotifier() = default;
-
-void PerformanceScenarioNotifier::AddGlobalObserver(
-    PerformanceScenarioObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  global_observers_.AddObserver(observer);
-}
-
-void PerformanceScenarioNotifier::RemoveGlobalObserver(
-    const PerformanceScenarioObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  global_observers_.RemoveObserver(observer);
-}
-
-void PerformanceScenarioNotifier::AddObserverForProcess(
-    const ProcessNode* process_node,
-    PerformanceScenarioObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK(process_node);
-  auto& data = PerformanceScenarioMemoryData::GetOrCreate(process_node);
-  if (!data.observers) {
-    data.observers = std::make_unique<ObserverList>();
-  }
-  data.observers->AddObserver(observer);
-}
-
-void PerformanceScenarioNotifier::RemoveObserverForProcess(
-    const ProcessNode* process_node,
-    const PerformanceScenarioObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CHECK(process_node);
-  auto& data = PerformanceScenarioMemoryData::GetOrCreate(process_node);
-  CHECK(data.observers);
-  data.observers->RemoveObserver(observer);
-}
-
-PerformanceScenarioNotifier::ObserverList*
-PerformanceScenarioNotifier::GetGlobalObservers() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return &global_observers_;
-}
-
-PerformanceScenarioNotifier::ObserverList*
-PerformanceScenarioNotifier::GetProcessObservers(
-    const ProcessNode* process_node) {
-  CHECK(process_node);
-  return PerformanceScenarioMemoryData::GetOrCreate(process_node)
-      .observers.get();
-}
-
-}  // namespace performance_manager
diff --git a/components/performance_manager/scenarios/performance_scenarios.cc b/components/performance_manager/scenarios/performance_scenarios.cc
index 6f63338b..694958a 100644
--- a/components/performance_manager/scenarios/performance_scenarios.cc
+++ b/components/performance_manager/scenarios/performance_scenarios.cc
@@ -15,12 +15,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
-#include "base/observer_list.h"
 #include "base/trace_event/typed_macros.h"
 #include "components/performance_manager/public/graph/graph.h"
 #include "components/performance_manager/public/graph/process_node.h"
 #include "components/performance_manager/public/performance_manager.h"
-#include "components/performance_manager/public/scenarios/performance_scenario_observer.h"
 #include "components/performance_manager/scenarios/performance_scenario_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -32,27 +30,6 @@
 
 using blink::performance_scenarios::ScenarioScope;
 
-// Shim to get observer lists from PerformanceScenarioNotifier.
-class PerformanceScenarioNotifierAccessor {
- public:
-  static base::ObserverList<PerformanceScenarioObserver>* GetGlobalObservers(
-      Graph* graph) {
-    if (auto* notifier = PerformanceScenarioNotifier::GetFromGraph(graph)) {
-      return notifier->GetGlobalObservers();
-    }
-    return nullptr;
-  }
-
-  static base::ObserverList<PerformanceScenarioObserver>* GetProcessObservers(
-      const ProcessNode* process_node) {
-    if (auto* notifier = PerformanceScenarioNotifier::GetFromGraph(
-            process_node->GetGraph())) {
-      return notifier->GetProcessObservers(process_node);
-    }
-    return nullptr;
-  }
-};
-
 namespace {
 
 // Generic methods that change according to the Scenario type.
@@ -68,15 +45,6 @@
 
   // Closes the trace event for `scenario` if a tracing track is registered.
   void MaybeEndTraceEvent(Scenario scenario) const;
-
-  // ProcessObserver methods called by ObserverList::Notify() for this scenario.
-  static constexpr void (PerformanceScenarioObserver::*kGlobalNotifyMethod)(
-      Scenario,
-      Scenario) = nullptr;
-  static constexpr void (PerformanceScenarioObserver::*kProcessNotifyMethod)(
-      const ProcessNode*,
-      Scenario,
-      Scenario) = nullptr;
 };
 
 template <>
@@ -129,17 +97,6 @@
     NOTREACHED();
   }
 
-  static constexpr void (PerformanceScenarioObserver::*kGlobalNotifyMethod)(
-      LoadingScenario,
-      LoadingScenario) =
-      &PerformanceScenarioObserver::OnGlobalLoadingScenarioChanged;
-
-  static constexpr void (PerformanceScenarioObserver::*kProcessNotifyMethod)(
-      const ProcessNode*,
-      LoadingScenario,
-      LoadingScenario) =
-      &PerformanceScenarioObserver::OnProcessLoadingScenarioChanged;
-
   scoped_refptr<RefCountedScenarioState> state_ptr;
 };
 
@@ -176,16 +133,6 @@
     NOTREACHED();
   }
 
-  static constexpr void (PerformanceScenarioObserver::*kGlobalNotifyMethod)(
-      InputScenario,
-      InputScenario) =
-      &PerformanceScenarioObserver::OnGlobalInputScenarioChanged;
-  static constexpr void (PerformanceScenarioObserver::*kProcessNotifyMethod)(
-      const ProcessNode*,
-      InputScenario,
-      InputScenario) =
-      &PerformanceScenarioObserver::OnProcessInputScenarioChanged;
-
   scoped_refptr<RefCountedScenarioState> state_ptr;
 };
 
@@ -214,10 +161,10 @@
 }
 
 // Sets the value for Scenario in the memory region held in `state_ptr` to
-// `new_scenario`, and returns the old value.
+// `new_scenario`.
 template <typename Scenario>
-Scenario SetScenarioValue(Scenario new_scenario,
-                          scoped_refptr<RefCountedScenarioState> state_ptr) {
+void SetScenarioValue(Scenario new_scenario,
+                      scoped_refptr<RefCountedScenarioState> state_ptr) {
   if (state_ptr) {
     ScenarioTraits<Scenario> traits(std::move(state_ptr));
     // std::memory_order_relaxed is sufficient since no other memory depends on
@@ -228,24 +175,6 @@
       traits.MaybeEndTraceEvent(old_scenario);
       traits.MaybeBeginTraceEvent(new_scenario);
     }
-    return old_scenario;
-  }
-  // Pretend the scenario already had this value, to not trigger observers.
-  return new_scenario;
-}
-
-template <typename Scenario>
-void SetScenarioValueForProcessNode(Scenario scenario,
-                                    const ProcessNode* process_node) {
-  Scenario old_scenario =
-      SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node));
-  if (old_scenario != scenario) {
-    auto* observers =
-        PerformanceScenarioNotifierAccessor::GetProcessObservers(process_node);
-    if (observers) {
-      observers->Notify(ScenarioTraits<Scenario>::kProcessNotifyMethod,
-                        process_node, old_scenario, scenario);
-    }
   }
 }
 
@@ -258,7 +187,8 @@
       base::BindOnce(
           [](Scenario scenario, base::WeakPtr<ProcessNode> process_node) {
             if (process_node) {
-              SetScenarioValueForProcessNode(scenario, process_node.get());
+              SetScenarioValue(
+                  scenario, GetSharedStateForProcessNode(process_node.get()));
             }
           },
           scenario,
@@ -267,32 +197,13 @@
 
 template <typename Scenario>
 void SetGlobalScenarioValue(Scenario scenario) {
-  Scenario old_scenario = SetScenarioValue(scenario, GetGlobalSharedState());
-  if (old_scenario == scenario) {
-    return;
+  SetScenarioValue(scenario, GetGlobalSharedState());
+  // Notify kGlobal observers in the browser process.
+  if (auto observers =
+          blink::performance_scenarios::PerformanceScenarioObserverList::
+              GetForScope(ScenarioScope::kGlobal)) {
+    observers->NotifyIfScenarioChanged();
   }
-  // The global scenario can be set on any thread, but the observers must be
-  // notified on the PM sequence.
-  PerformanceManager::CallOnGraph(
-      FROM_HERE,
-      base::BindOnce(
-          [](Scenario scenario, Scenario old_scenario, Graph* graph) {
-            auto* observers =
-                PerformanceScenarioNotifierAccessor::GetGlobalObservers(graph);
-            if (observers) {
-              observers->Notify(ScenarioTraits<Scenario>::kGlobalNotifyMethod,
-                                old_scenario, scenario);
-            }
-            // Also notify kGlobal blink observers in the browser process.
-            // TODO(crbug.com/365586676): Remove the performance_manager kGlobal
-            // observer, which is redundant with this one.
-            if (auto blink_observers = blink::performance_scenarios::
-                    PerformanceScenarioObserverList::GetForScope(
-                        ScenarioScope::kGlobal)) {
-              blink_observers->NotifyIfScenarioChanged();
-            }
-          },
-          scenario, old_scenario));
 }
 
 }  // namespace
@@ -336,7 +247,7 @@
 
 void SetLoadingScenarioForProcessNode(LoadingScenario scenario,
                                       const ProcessNode* process_node) {
-  SetScenarioValueForProcessNode(scenario, process_node);
+  SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node));
 }
 
 void SetGlobalLoadingScenario(LoadingScenario scenario) {
@@ -350,7 +261,7 @@
 
 void SetInputScenarioForProcessNode(InputScenario scenario,
                                     const ProcessNode* process_node) {
-  SetScenarioValueForProcessNode(scenario, process_node);
+  SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node));
 }
 
 void SetGlobalInputScenario(InputScenario scenario) {
diff --git a/components/performance_manager/scenarios/performance_scenarios_unittest.cc b/components/performance_manager/scenarios/performance_scenarios_unittest.cc
index 75067e6..563abda0 100644
--- a/components/performance_manager/scenarios/performance_scenarios_unittest.cc
+++ b/components/performance_manager/scenarios/performance_scenarios_unittest.cc
@@ -11,12 +11,10 @@
 #include "base/memory/weak_ptr.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/scoped_feature_list.h"
-#include "components/performance_manager/embedder/graph_features.h"
 #include "components/performance_manager/public/features.h"
 #include "components/performance_manager/public/graph/graph.h"
 #include "components/performance_manager/public/graph/process_node.h"
 #include "components/performance_manager/public/performance_manager.h"
-#include "components/performance_manager/public/scenarios/performance_scenario_observer.h"
 #include "components/performance_manager/test_support/performance_manager_test_harness.h"
 #include "components/performance_manager/test_support/run_in_graph.h"
 #include "content/public/browser/web_contents.h"
@@ -37,33 +35,10 @@
 using blink::performance_scenarios::ScenarioScope;
 using ::testing::_;
 
-class MockPerformanceScenarioObserver : public PerformanceScenarioObserver {
- public:
-  MOCK_METHOD(void,
-              OnGlobalLoadingScenarioChanged,
-              (LoadingScenario, LoadingScenario),
-              (override));
-  MOCK_METHOD(void,
-              OnGlobalInputScenarioChanged,
-              (InputScenario, InputScenario),
-              (override));
-  MOCK_METHOD(void,
-              OnProcessLoadingScenarioChanged,
-              (const ProcessNode*, LoadingScenario, LoadingScenario),
-              (override));
-  MOCK_METHOD(void,
-              OnProcessInputScenarioChanged,
-              (const ProcessNode*, InputScenario, InputScenario),
-              (override));
-};
-
-using StrictMockPerformanceScenarioObserver =
-    ::testing::StrictMock<MockPerformanceScenarioObserver>;
-
 // Since the browser process also maps in a read-only view of the global
 // scenario state for querying outside performance_manager, the blink observer
 // is also notified.
-class MockBlinkPerformanceScenarioObserver
+class MockPerformanceScenarioObserver
     : public blink::performance_scenarios::PerformanceScenarioObserver {
  public:
  public:
@@ -81,8 +56,8 @@
               (override));
 };
 
-using StrictMockBlinkPerformanceScenarioObserver =
-    ::testing::StrictMock<MockBlinkPerformanceScenarioObserver>;
+using StrictMockPerformanceScenarioObserver =
+    ::testing::StrictMock<MockPerformanceScenarioObserver>;
 
 class PerformanceScenariosTest : public PerformanceManagerTestHarness,
                                  public ::testing::WithParamInterface<bool> {
@@ -95,34 +70,12 @@
   }
 
   void SetUp() override {
-    // Enable the PerformanceScenarioNotifier.
-    GetGraphFeatures().EnablePerformanceScenarios();
-
     PerformanceManagerTestHarness::SetUp();
 
     // Load a page with FrameNodes and ProcessNodes.
     SetContents(CreateTestWebContents());
     content::NavigationSimulator::NavigateAndCommitFromBrowser(
         web_contents(), GURL("https://www.example.com"));
-
-    // Observe global scenario changes and scenarios for two ProcessNodes.
-    // (The browser process is a convenient 2nd process.)
-    base::WeakPtr<ProcessNode> process_node =
-        PerformanceManager::GetProcessNodeForRenderProcessHost(process());
-    base::WeakPtr<ProcessNode> browser_process_node =
-        PerformanceManager::GetProcessNodeForBrowserProcess();
-    RunInGraph([&](Graph* graph) {
-      auto* notifier = PerformanceScenarioNotifier::GetFromGraph(graph);
-      ASSERT_TRUE(notifier);
-      ASSERT_TRUE(process_node);
-      ASSERT_TRUE(browser_process_node);
-      notifier->AddGlobalObserver(&mock_observer_);
-      notifier->AddObserverForProcess(process_node.get(), &mock_observer_);
-
-      // This observer should never fire (verified by StrictMock).
-      notifier->AddObserverForProcess(browser_process_node.get(),
-                                      &mock_observer_);
-    });
   }
 
   // Returns the shared memory region handle for the main frame's process, or an
@@ -144,9 +97,6 @@
     return process_region;
   }
 
- protected:
-  StrictMockPerformanceScenarioObserver mock_observer_;
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
@@ -170,19 +120,8 @@
 TEST_P(PerformanceScenariosTest, SetWithSharedMemory) {
   base::WeakPtr<ProcessNode> process_node =
       PerformanceManager::GetProcessNodeForRenderProcessHost(process());
-  RunInGraph([&] {
-    ASSERT_TRUE(process_node);
-    EXPECT_CALL(mock_observer_, OnGlobalLoadingScenarioChanged(
-                                    LoadingScenario::kNoPageLoading,
-                                    LoadingScenario::kFocusedPageLoading));
-    EXPECT_CALL(mock_observer_,
-                OnProcessLoadingScenarioChanged(
-                    process_node.get(), LoadingScenario::kNoPageLoading,
-                    LoadingScenario::kVisiblePageLoading));
-  });
-
-  StrictMockBlinkPerformanceScenarioObserver mock_blink_observer;
-  EXPECT_CALL(mock_blink_observer,
+  StrictMockPerformanceScenarioObserver mock_observer;
+  EXPECT_CALL(mock_observer,
               OnLoadingScenarioChanged(ScenarioScope::kGlobal,
                                        LoadingScenario::kNoPageLoading,
                                        LoadingScenario::kFocusedPageLoading))
@@ -192,10 +131,10 @@
   // view of the memory in as well so changes immediately become visible to the
   // current (browser) process.
   ScopedGlobalScenarioMemory global_shared_memory;
-  auto blink_observer_list =
+  auto observer_list =
       PerformanceScenarioObserverList::GetForScope(ScenarioScope::kGlobal);
-  ASSERT_TRUE(blink_observer_list);
-  blink_observer_list->AddObserver(&mock_blink_observer);
+  ASSERT_TRUE(observer_list);
+  observer_list->AddObserver(&mock_observer);
 
   SetGlobalLoadingScenario(LoadingScenario::kFocusedPageLoading);
   EXPECT_EQ(GetLoadingScenario(ScenarioScope::kGlobal)
@@ -205,7 +144,7 @@
   // PerformanceScenarioObserverList is an ObserverListThreadSafe that posts
   // a message to notify. Need to wait for the message.
   task_environment()->RunUntilQuit();
-  ::testing::Mock::VerifyAndClearExpectations(&mock_blink_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
 
   // Create writable shared memory for a render process state. Since this is
   // called in the browser process and the state is for a different process, it
@@ -222,10 +161,6 @@
               LoadingScenario::kNoPageLoading);
   });
 
-  // Ensure that the ProcessNode observer was notified in the browser process,
-  // even though the child hasn't mapped in the memory yet.
-  ::testing::Mock::VerifyAndClearExpectations(&mock_observer_);
-
   // Map in the read-only view of `process_region`. Normally this would be done
   // in the renderer process as the "current process" state. The state should
   // now become visible.
@@ -236,7 +171,7 @@
                 ->load(std::memory_order_relaxed),
             LoadingScenario::kVisiblePageLoading);
 
-  blink_observer_list->RemoveObserver(&mock_blink_observer);
+  observer_list->RemoveObserver(&mock_observer);
 }
 
 // TODO(crbug.com/382551028): Test is flaky on Android.
@@ -248,19 +183,9 @@
 TEST_P(PerformanceScenariosTest, MAYBE_SetFromPMSequence) {
   base::WeakPtr<ProcessNode> process_node =
       PerformanceManager::GetProcessNodeForRenderProcessHost(process());
-  RunInGraph([&] {
-    ASSERT_TRUE(process_node);
-    EXPECT_CALL(mock_observer_, OnGlobalLoadingScenarioChanged(
-                                    LoadingScenario::kNoPageLoading,
-                                    LoadingScenario::kFocusedPageLoading));
-    EXPECT_CALL(mock_observer_,
-                OnProcessLoadingScenarioChanged(
-                    process_node.get(), LoadingScenario::kNoPageLoading,
-                    LoadingScenario::kVisiblePageLoading));
-  });
 
-  StrictMockBlinkPerformanceScenarioObserver mock_blink_observer;
-  EXPECT_CALL(mock_blink_observer,
+  StrictMockPerformanceScenarioObserver mock_observer;
+  EXPECT_CALL(mock_observer,
               OnLoadingScenarioChanged(ScenarioScope::kGlobal,
                                        LoadingScenario::kNoPageLoading,
                                        LoadingScenario::kFocusedPageLoading))
@@ -269,10 +194,10 @@
   // Create writable shared memory for the global state. This maps a read-only
   // view of the memory in as well.
   ScopedGlobalScenarioMemory global_shared_memory;
-  auto blink_observer_list =
+  auto observer_list =
       PerformanceScenarioObserverList::GetForScope(ScenarioScope::kGlobal);
-  ASSERT_TRUE(blink_observer_list);
-  blink_observer_list->AddObserver(&mock_blink_observer);
+  ASSERT_TRUE(observer_list);
+  observer_list->AddObserver(&mock_observer);
 
   // Create writable shared memory for a render process state. Since this is
   // called in the browser process and the state is for a different process, it
@@ -295,14 +220,10 @@
                 ->load(std::memory_order_relaxed),
             LoadingScenario::kFocusedPageLoading);
 
-  // Ensure that the ProcessNode observer was notified in the browser process,
-  // even though the child hasn't mapped in the memory yet.
-  ::testing::Mock::VerifyAndClearExpectations(&mock_observer_);
-
   // PerformanceScenarioObserverList is an ObserverListThreadSafe that posts
   // a message to notify. Need to wait for the message.
   task_environment()->RunUntilQuit();
-  ::testing::Mock::VerifyAndClearExpectations(&mock_blink_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
 
   // Map in the read-only view of `process_region`. Normally this would be done
   // in the renderer process as the "current process" state. The state should
@@ -314,40 +235,7 @@
                 ->load(std::memory_order_relaxed),
             LoadingScenario::kVisiblePageLoading);
 
-  blink_observer_list->RemoveObserver(&mock_blink_observer);
-}
-
-TEST_P(PerformanceScenariosTest, SetWithoutObservers) {
-  // Stop observing scenarios. StrictMock will complain if any observer method
-  // is called.
-  base::WeakPtr<ProcessNode> process_node =
-      PerformanceManager::GetProcessNodeForRenderProcessHost(process());
-  RunInGraph([&](Graph* graph) {
-    auto* notifier = PerformanceScenarioNotifier::GetFromGraph(graph);
-    ASSERT_TRUE(notifier);
-    ASSERT_TRUE(process_node);
-    notifier->RemoveGlobalObserver(&mock_observer_);
-    notifier->RemoveObserverForProcess(process_node.get(), &mock_observer_);
-  });
-
-  ScopedGlobalScenarioMemory global_shared_memory;
-  blink::performance_scenarios::ScopedReadOnlyScenarioMemory
-      process_shared_memory(ScenarioScope::kCurrentProcess,
-                            main_process_region());
-
-  SetGlobalLoadingScenario(LoadingScenario::kFocusedPageLoading);
-  SetLoadingScenarioForProcess(LoadingScenario::kVisiblePageLoading, process());
-
-  // SetLoadingScenarioForProcess posts to the PM thread. Wait until the message
-  // is received before reading.
-  RunInGraph([] {
-    EXPECT_EQ(GetLoadingScenario(ScenarioScope::kGlobal)
-                  ->load(std::memory_order_relaxed),
-              LoadingScenario::kFocusedPageLoading);
-    EXPECT_EQ(GetLoadingScenario(ScenarioScope::kCurrentProcess)
-                  ->load(std::memory_order_relaxed),
-              LoadingScenario::kVisiblePageLoading);
-  });
+  observer_list->RemoveObserver(&mock_observer);
 }
 
 }  // namespace
diff --git a/components/policy/resources/webui/BUILD.gn b/components/policy/resources/webui/BUILD.gn
index cd24138..a42efd2 100644
--- a/components/policy/resources/webui/BUILD.gn
+++ b/components/policy/resources/webui/BUILD.gn
@@ -9,8 +9,8 @@
 
   static_files = [
     "logs/policy_logs.html",
-    "policy.html",
     "policy.css",
+    "policy.html",
     "policy_shared_vars.css",
     "test/policy_test.html",
   ]
@@ -18,18 +18,18 @@
   # Files holding a Custom element definition AND have an equivalent .html file.
   web_component_files = [
     "policy_conflict.ts",
-    "policy_row.ts",
     "policy_precedence_row.ts",
-    "policy_table.ts",
     "policy_promotion.ts",
+    "policy_row.ts",
+    "policy_table.ts",
+    "status_box.ts",
     "test/policy_test_row.ts",
     "test/policy_test_table.ts",
-    "status_box.ts",
   ]
 
   non_web_component_files = [
-    "logs/types.ts",
     "logs/policy_logs.ts",
+    "logs/types.ts",
     "policy.ts",
     "policy_base.ts",
     "test/policy_test.ts",
diff --git a/components/segmentation_platform/embedder/home_modules/constants.h b/components/segmentation_platform/embedder/home_modules/constants.h
index 6935f20..fb505c9c 100644
--- a/components/segmentation_platform/embedder/home_modules/constants.h
+++ b/components/segmentation_platform/embedder/home_modules/constants.h
@@ -85,6 +85,8 @@
 // Labels for emphemeral android modules.
 const char kDefaultBrowserPromo[] = "DefaultBrowserPromo";
 const char kTabGroupPromo[] = "TabGroupPromo";
+const char kTabGroupSyncPromo[] = "TabGroupSyncPromo";
+const char kQuickDeletePromo[] = "QuickDeletePromo";
 
 // Commandline ASCII Switch key to indicate that the test module backend ranker
 // should be used.
diff --git a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.cc b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.cc
index 90690b5..108fc79 100644
--- a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.cc
+++ b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.cc
@@ -12,6 +12,7 @@
 #include "components/segmentation_platform/embedder/home_modules/card_selection_info.h"
 #include "components/segmentation_platform/embedder/home_modules/constants.h"
 #include "components/segmentation_platform/embedder/home_modules/default_browser_promo.h"
+#include "components/segmentation_platform/embedder/home_modules/ephemeral_module_utils.h"
 #include "components/segmentation_platform/embedder/home_modules/price_tracking_notification_promo.h"
 #include "components/segmentation_platform/embedder/home_modules/send_tab_notification_promo.h"
 #include "components/segmentation_platform/embedder/home_modules/tab_group_promo.h"
@@ -245,15 +246,33 @@
         profile_prefs_->GetInteger(kDefaultBrowserPromoImpressionCounterPref);
     profile_prefs_->SetInteger(kDefaultBrowserPromoImpressionCounterPref,
                                freshness_impression_count + 1);
-  } else if (strcmp(card_name, kTabGroupPromo) == 0) {
-    int freshness_impression_count =
-        profile_prefs_->GetInteger(kTabGroupPromoImpressionCounterPref);
-    profile_prefs_->SetInteger(kTabGroupPromoImpressionCounterPref,
-                               freshness_impression_count + 1);
+  } else if (ShouldNotifyCardShownPerSession(card_name)) {
+    // Educational tip cards, except for the default browser promo card, will
+    // send a notification when the card is shown once per session, rather than
+    // every time it is displayed.
+    if (strcmp(card_name, kTabGroupPromo) == 0) {
+      int freshness_impression_count =
+          profile_prefs_->GetInteger(kTabGroupPromoImpressionCounterPref);
+      profile_prefs_->SetInteger(kTabGroupPromoImpressionCounterPref,
+                                 freshness_impression_count + 1);
+    }
   }
 #endif
 }
 
+#if BUILDFLAG(IS_ANDROID)
+bool HomeModulesCardRegistry::ShouldNotifyCardShownPerSession(
+    const std::string& card_name) {
+  if (shown_in_current_session_.find(card_name) !=
+      shown_in_current_session_.end()) {
+    return false;
+  }
+
+  shown_in_current_session_.insert(card_name);
+  return true;
+}
+#endif
+
 void HomeModulesCardRegistry::NotifyCardInteracted(const char* card_name) {
 #if BUILDFLAG(IS_IOS)
   if (strcmp(card_name, kAddressBarPositionEphemeralModule) == 0) {
diff --git a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.h b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.h
index 144b6ef..f98e4f59 100644
--- a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.h
+++ b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry.h
@@ -75,6 +75,12 @@
 
   base::WeakPtr<HomeModulesCardRegistry> GetWeakPtr();
 
+#if BUILDFLAG(IS_ANDROID)
+  // Returns true if this is the first time the card is displayed to the user in
+  // the current session and the event should be recorded.
+  bool ShouldNotifyCardShownPerSession(const std::string& card_name);
+#endif
+
  private:
   // Populats `all_cards_by_priority_`.
   void CreateAllCards();
@@ -105,6 +111,13 @@
   // The total count of the inputs of all cards.
   size_t all_cards_input_size_{0};
 
+#if BUILDFLAG(IS_ANDROID)
+  // A list includes all educational tip card types (excluding the default
+  // browser promo card) that have been displayed to the user during the current
+  // session.
+  std::unordered_set<std::string> shown_in_current_session_;
+#endif
+
   base::WeakPtrFactory<HomeModulesCardRegistry> weak_ptr_factory_{this};
 };
 
diff --git a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry_unittest.cc b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry_unittest.cc
index f0286e2f..7317633 100644
--- a/components/segmentation_platform/embedder/home_modules/home_modules_card_registry_unittest.cc
+++ b/components/segmentation_platform/embedder/home_modules/home_modules_card_registry_unittest.cc
@@ -225,4 +225,20 @@
 #endif
 }
 
+// Tests that for educational tip cards, except for the default browser promo
+// card, could send a notification when the card is shown once per session,
+// rather than every time it is displayed.
+TEST_F(HomeModulesCardRegistryTest, TestShouldNotifyCardShownPerSession) {
+#if BUILDFLAG(IS_ANDROID)
+  feature_list_.InitWithFeatures({features::kEducationalTipModule}, {});
+  registry_ = std::make_unique<HomeModulesCardRegistry>(&pref_service_);
+  const char* card_name_1 = "TabGroupPromo";
+  const char* card_name_2 = "TabGroupSyncPromo";
+  EXPECT_TRUE(registry_->ShouldNotifyCardShownPerSession(card_name_1));
+  EXPECT_FALSE(registry_->ShouldNotifyCardShownPerSession(card_name_1));
+  EXPECT_TRUE(registry_->ShouldNotifyCardShownPerSession(card_name_2));
+  EXPECT_FALSE(registry_->ShouldNotifyCardShownPerSession(card_name_2));
+#endif
+}
+
 }  // namespace segmentation_platform::home_modules
diff --git a/components/segmentation_platform/embedder/home_modules/tab_group_promo.cc b/components/segmentation_platform/embedder/home_modules/tab_group_promo.cc
index afc40f6..637db05 100644
--- a/components/segmentation_platform/embedder/home_modules/tab_group_promo.cc
+++ b/components/segmentation_platform/embedder/home_modules/tab_group_promo.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/segmentation_platform/embedder/home_modules/constants.h"
+#include "components/segmentation_platform/embedder/home_modules/ephemeral_module_utils.h"
 #include "components/segmentation_platform/embedder/home_modules/home_modules_card_registry.h"
 #include "components/segmentation_platform/public/features.h"
 #include "components/segmentation_platform/public/proto/model_metadata.pb.h"
@@ -22,7 +23,7 @@
 const int kShownCountLimit = 3;
 
 const char kTabGroupPromoHistogramName[] =
-    "MagicStack.Clank.NewTabPage.Module.EducationalTip.Impression";
+    "MagicStack.Clank.NewTabPage.Module.TopImpressionV2";
 
 // TODO(crbug.com/382803396): The enum id of the tab group promo card. Could be
 // referenced after refactor.
@@ -59,6 +60,16 @@
 
 CardSelectionInfo::ShowResult TabGroupPromo::ComputeCardResult(
     const CardSelectionSignals& signals) const {
+  // Check for a forced `ShowResult`.
+  std::optional<CardSelectionInfo::ShowResult> forced_result =
+      GetForcedEphemeralModuleShowResult();
+
+  if (forced_result.has_value() &&
+      forced_result.value().result_label.has_value() &&
+      kTabGroupPromo == forced_result.value().result_label.value()) {
+    return forced_result.value();
+  }
+
   CardSelectionInfo::ShowResult result;
   result.result_label = kTabGroupPromo;
 
@@ -94,6 +105,15 @@
 }
 
 bool TabGroupPromo::IsEnabled(int impression_count) {
+  std::optional<CardSelectionInfo::ShowResult> forced_result =
+      GetForcedEphemeralModuleShowResult();
+
+  if (forced_result.has_value() &&
+      forced_result.value().result_label.has_value() &&
+      kTabGroupPromo == forced_result.value().result_label.value()) {
+    return true;
+  }
+
   if (!base::FeatureList::IsEnabled(features::kEducationalTipModule)) {
     return false;
   }
diff --git a/components/services/heap_profiling/json_exporter.cc b/components/services/heap_profiling/json_exporter.cc
index 8c04d4d..38555aa 100644
--- a/components/services/heap_profiling/json_exporter.cc
+++ b/components/services/heap_profiling/json_exporter.cc
@@ -12,15 +12,18 @@
 #include <inttypes.h>
 
 #include <map>
+#include <string>
 #include <unordered_map>
+#include <vector>
 
 #include "base/containers/adapters.h"
+#include "base/files/file_path.h"
 #include "base/json/json_writer.h"
 #include "base/json/string_escape.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/traced_value.h"
 #include "base/values.h"
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
 namespace heap_profiling {
 namespace {
@@ -126,10 +129,80 @@
   return result;
 }
 
+std::string ApplyPathFiltering(const std::string& file,
+                               bool is_argument_filtering_enabled) {
+  if (is_argument_filtering_enabled) {
+    base::FilePath::StringType path(file.begin(), file.end());
+    return base::FilePath(path).BaseName().AsUTF8Unsafe();
+  }
+  return file;
+}
+
+void MemoryMapsAsValueInto(
+    const std::vector<memory_instrumentation::mojom::VmRegionPtr>& memory_maps,
+    base::trace_event::TracedValue* value,
+    bool is_argument_filtering_enabled) {
+  static const char kHexFmt[] = "%" PRIx64;
+
+  // Refer to the design doc goo.gl/sxfFY8 for the semantics of these fields.
+  value->BeginArray("vm_regions");
+  for (const auto& region : memory_maps) {
+    value->BeginDictionary();
+
+    value->SetString("sa", base::StringPrintf(kHexFmt, region->start_address));
+    value->SetString("sz", base::StringPrintf(kHexFmt, region->size_in_bytes));
+    if (region->module_timestamp) {
+      value->SetString("ts",
+                       base::StringPrintf(kHexFmt, region->module_timestamp));
+    }
+    if (!region->module_debugid.empty()) {
+      value->SetString("id", region->module_debugid);
+    }
+    if (!region->module_debug_path.empty()) {
+      value->SetString("df", ApplyPathFiltering(region->module_debug_path,
+                                                is_argument_filtering_enabled));
+    }
+    value->SetInteger("pf", region->protection_flags);
+
+    // The module path will be the basename when argument filtering is
+    // activated. The allowlisting implemented for filtering string values
+    // doesn't allow rewriting. Therefore, a different path is produced here
+    // when argument filtering is activated.
+    value->SetString("mf", ApplyPathFiltering(region->mapped_file,
+                                              is_argument_filtering_enabled));
+
+// The following stats are only well defined on Linux-derived OSes.
+#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
+    value->BeginDictionary("bs");  // byte stats
+    value->SetString(
+        "pss",
+        base::StringPrintf(kHexFmt, region->byte_stats_proportional_resident));
+    value->SetString(
+        "pd",
+        base::StringPrintf(kHexFmt, region->byte_stats_private_dirty_resident));
+    value->SetString(
+        "pc",
+        base::StringPrintf(kHexFmt, region->byte_stats_private_clean_resident));
+    value->SetString(
+        "sd",
+        base::StringPrintf(kHexFmt, region->byte_stats_shared_dirty_resident));
+    value->SetString(
+        "sc",
+        base::StringPrintf(kHexFmt, region->byte_stats_shared_clean_resident));
+    value->SetString("sw",
+                     base::StringPrintf(kHexFmt, region->byte_stats_swapped));
+    value->EndDictionary();
+#endif
+
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
 base::Value BuildMemoryMaps(const ExportParams& params) {
   base::trace_event::TracedValueJSON traced_value;
-  memory_instrumentation::TracingObserverTracedValue::MemoryMapsAsValueInto(
-      params.maps, &traced_value, params.strip_path_from_mapped_files);
+  MemoryMapsAsValueInto(params.maps, &traced_value,
+                        params.strip_path_from_mapped_files);
   return std::move(*traced_value.ToBaseValue());
 }
 
diff --git a/components/webxr/android/java/src/org/chromium/components/webxr/WebXrAndroidFeatureMap.java b/components/webxr/android/java/src/org/chromium/components/webxr/WebXrAndroidFeatureMap.java
index 54478316..0dca727c 100644
--- a/components/webxr/android/java/src/org/chromium/components/webxr/WebXrAndroidFeatureMap.java
+++ b/components/webxr/android/java/src/org/chromium/components/webxr/WebXrAndroidFeatureMap.java
@@ -7,7 +7,10 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+
 @JNINamespace("webxr")
+@NullMarked
 public final class WebXrAndroidFeatureMap {
     /** Convenience method to check if OpenXR should be enabled due to complex state. */
     public static boolean isOpenXrEnabled() {
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index 60811c09..405c824c 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -55,12 +55,13 @@
 
 namespace {
 
+// This map contains key value pairs of a string to a tree search predicate. The
+// set of keys represents the ways in which an AT can navigate a page by HTML
+// element (by next or previous navigation). A Java-side AT sends a key with a
+// next/previous action request, and this map is used to map the string to the
+// correct predicate.
 using SearchKeyToPredicateMap =
     std::unordered_map<std::u16string, ui::AccessibilityMatchPredicate>;
-base::LazyInstance<SearchKeyToPredicateMap>::Leaky
-    g_search_key_to_predicate_map = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<std::u16string>::Leaky g_all_search_keys =
-    LAZY_INSTANCE_INITIALIZER;
 
 static const char kHtmlTypeRow[] = "ROW";
 static const char kHtmlTypeColumn[] = "COLUMN";
@@ -68,6 +69,75 @@
 static const char kHtmlTypeColumnBounds[] = "COLUMN_BOUNDS";
 static const char kHtmlTypeTableBounds[] = "TABLE_BOUNDS";
 
+// IMPORTANT!
+// These values are written to logs. Do not renumber or delete
+// existing items; add new entries to the end of the list.
+//
+// LINT.IfChange
+enum class AccessibilityPredicateType {
+  // Used for a string we do not support/recognize.
+  kUnknown = 0,
+
+  // Used for an empty string, which is default and maps to
+  // "IsInterestingOnAndroid".
+  kDefault = 1,
+
+  // Currently supported navigation types.
+  kArticle = 2,
+  kBlockQuote = 3,
+  kButton = 4,
+  kCheckbox = 5,
+  kCombobox = 6,
+  kControl = 7,
+  kFocusable = 8,
+  kFrame = 9,
+  kGraphic = 10,
+  kH1 = 11,
+  kH2 = 12,
+  kH3 = 13,
+  kH4 = 14,
+  kH5 = 15,
+  kH6 = 16,
+  kHeading = 17,
+  kHeadingSame = 18,
+  kLandmark = 19,
+  kLink = 20,
+  kList = 21,
+  kListItem = 22,
+  kLive = 23,
+  kMain = 24,
+  kMedia = 25,
+  kParagraph = 26,
+  kRadio = 27,
+  kRadioGroup = 28,
+  kSection = 29,
+  kTable = 30,
+  kTextfield = 31,
+  kTextBold = 32,
+  kTextItalic = 33,
+  kTextUnderline = 34,
+  kTree = 35,
+  kUnvisitedLink = 36,
+  kVisitedLink = 37,
+  kRow = 38,
+  kColumn = 39,
+  kRowBounds = 40,
+  kColumnBounds = 41,
+  kTableBounds = 42,
+
+  // Max value, must always be equal to the largest entry logged, remember to
+  // increment.
+  kMaxValue = 42
+};
+// LINT.ThenChange(/tools/metrics/histograms/metadata/accessibility/enums.xml:AccessibilityPredicateType)
+
+// This map contains key value pairs of a string to an internal enum identifying
+// a tree search predicate. A Java-side AT sends a key with a next/previous
+// action request, and this map is used to map the string to an enum so we can
+// log a histogram.
+using PredicateToEnumMap =
+    std::unordered_map<std::u16string, AccessibilityPredicateType>;
+
 bool AllInterestingNodesPredicate(ui::BrowserAccessibility* start,
                                   ui::BrowserAccessibility* node) {
   BrowserAccessibilityAndroid* android_node =
@@ -80,77 +150,137 @@
   return true;
 }
 
-void AddToPredicateMap(const char* search_key_ascii,
-                       ui::AccessibilityMatchPredicate predicate) {
-  std::u16string search_key_utf16 = base::ASCIIToUTF16(search_key_ascii);
-  g_search_key_to_predicate_map.Get()[search_key_utf16] = predicate;
-  if (!g_all_search_keys.Get().empty()) {
-    g_all_search_keys.Get() += u",";
+// Getter function for the search key to predicate map and all keys string.
+std::tuple<SearchKeyToPredicateMap&, std::u16string&, PredicateToEnumMap&>
+GetSearchKeyData() {
+  // These are special unofficial strings sent from TalkBack/BrailleBack
+  // to jump to certain categories of web elements.
+  static base::NoDestructor<SearchKeyToPredicateMap>
+      search_key_to_predicate_map;
+  static base::NoDestructor<std::u16string> all_search_keys;
+  static base::NoDestructor<PredicateToEnumMap> predicate_to_enum_map;
+  static bool initialized = false;
+
+  if (!initialized) {
+    initialized = true;
+    auto add_to_map = [&](const std::u16string& key,
+                          ui::AccessibilityMatchPredicate predicate,
+                          AccessibilityPredicateType type) {
+      (*search_key_to_predicate_map)[key] = predicate;
+      (*predicate_to_enum_map)[key] = type;
+
+      // Build the all_search_keys string.
+      if (!all_search_keys->empty()) {
+        *all_search_keys += u",";
+      }
+      *all_search_keys += key;
+    };
+
+    add_to_map(u"ARTICLE", ui::AccessibilityArticlePredicate,
+               AccessibilityPredicateType::kArticle);
+    add_to_map(u"BLOCKQUOTE", ui::AccessibilityBlockquotePredicate,
+               AccessibilityPredicateType::kBlockQuote);
+    add_to_map(u"BUTTON", ui::AccessibilityButtonPredicate,
+               AccessibilityPredicateType::kButton);
+    add_to_map(u"CHECKBOX", ui::AccessibilityCheckboxPredicate,
+               AccessibilityPredicateType::kCheckbox);
+    add_to_map(u"COMBOBOX", ui::AccessibilityComboboxPredicate,
+               AccessibilityPredicateType::kCombobox);
+    add_to_map(u"CONTROL", ui::AccessibilityControlPredicate,
+               AccessibilityPredicateType::kControl);
+    add_to_map(u"FOCUSABLE", ui::AccessibilityFocusablePredicate,
+               AccessibilityPredicateType::kFocusable);
+    add_to_map(u"FRAME", ui::AccessibilityFramePredicate,
+               AccessibilityPredicateType::kFrame);
+    add_to_map(u"GRAPHIC", ui::AccessibilityGraphicPredicate,
+               AccessibilityPredicateType::kGraphic);
+    add_to_map(u"H1", ui::AccessibilityH1Predicate,
+               AccessibilityPredicateType::kH1);
+    add_to_map(u"H2", ui::AccessibilityH2Predicate,
+               AccessibilityPredicateType::kH2);
+    add_to_map(u"H3", ui::AccessibilityH3Predicate,
+               AccessibilityPredicateType::kH3);
+    add_to_map(u"H4", ui::AccessibilityH4Predicate,
+               AccessibilityPredicateType::kH4);
+    add_to_map(u"H5", ui::AccessibilityH5Predicate,
+               AccessibilityPredicateType::kH5);
+    add_to_map(u"H6", ui::AccessibilityH6Predicate,
+               AccessibilityPredicateType::kH6);
+    add_to_map(u"HEADING", ui::AccessibilityHeadingPredicate,
+               AccessibilityPredicateType::kHeading);
+    add_to_map(u"HEADING_SAME", ui::AccessibilityHeadingSameLevelPredicate,
+               AccessibilityPredicateType::kHeadingSame);
+    add_to_map(u"LANDMARK", ui::AccessibilityLandmarkPredicate,
+               AccessibilityPredicateType::kLandmark);
+    add_to_map(u"LINK", ui::AccessibilityLinkPredicate,
+               AccessibilityPredicateType::kLink);
+    add_to_map(u"LIST", ui::AccessibilityListPredicate,
+               AccessibilityPredicateType::kList);
+    add_to_map(u"LIST_ITEM", ui::AccessibilityListItemPredicate,
+               AccessibilityPredicateType::kListItem);
+    add_to_map(u"LIVE", ui::AccessibilityLiveRegionPredicate,
+               AccessibilityPredicateType::kLive);
+    add_to_map(u"MAIN", ui::AccessibilityMainPredicate,
+               AccessibilityPredicateType::kMain);
+    add_to_map(u"MEDIA", ui::AccessibilityMediaPredicate,
+               AccessibilityPredicateType::kMedia);
+    add_to_map(u"PARAGRAPH", ui::AccessibilityParagraphPredicate,
+               AccessibilityPredicateType::kParagraph);
+    add_to_map(u"RADIO", ui::AccessibilityRadioButtonPredicate,
+               AccessibilityPredicateType::kRadio);
+    add_to_map(u"RADIO_GROUP", ui::AccessibilityRadioGroupPredicate,
+               AccessibilityPredicateType::kRadioGroup);
+    add_to_map(u"SECTION", ui::AccessibilitySectionPredicate,
+               AccessibilityPredicateType::kSection);
+    add_to_map(u"TABLE", ui::AccessibilityTablePredicate,
+               AccessibilityPredicateType::kTable);
+    add_to_map(u"TEXT_FIELD", ui::AccessibilityTextfieldPredicate,
+               AccessibilityPredicateType::kTextfield);
+    add_to_map(u"TEXT_BOLD", ui::AccessibilityTextStyleBoldPredicate,
+               AccessibilityPredicateType::kTextBold);
+    add_to_map(u"TEXT_ITALIC", ui::AccessibilityTextStyleItalicPredicate,
+               AccessibilityPredicateType::kTextItalic);
+    add_to_map(u"TEXT_UNDER", ui::AccessibilityTextStyleUnderlinePredicate,
+               AccessibilityPredicateType::kTextUnderline);
+    add_to_map(u"TREE", ui::AccessibilityTreePredicate,
+               AccessibilityPredicateType::kTree);
+    add_to_map(u"UNVISITED_LINK", ui::AccessibilityUnvisitedLinkPredicate,
+               AccessibilityPredicateType::kUnvisitedLink);
+    add_to_map(u"VISITED_LINK", ui::AccessibilityVisitedLinkPredicate,
+               AccessibilityPredicateType::kVisitedLink);
+
+    // These are surfaced simply to document the html types, but do not do a
+    // tree/predicate search.
+    add_to_map(u"ROW", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kRow);
+    add_to_map(u"ROW", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kRow);
+    add_to_map(u"COLUMN", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kColumn);
+    add_to_map(u"ROW_BOUNDS", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kRowBounds);
+    add_to_map(u"COLUMN_BOUNDS", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kColumnBounds);
+    add_to_map(u"TABLE_BOUNDS", AccessibilityNoOpPredicate,
+               AccessibilityPredicateType::kTableBounds);
+
+    // These do not have search predicates and are for metrics tracking.
+    (*predicate_to_enum_map)[u"UNKNOWN"] = AccessibilityPredicateType::kUnknown;
+    (*predicate_to_enum_map)[u"DEFAULT"] = AccessibilityPredicateType::kDefault;
   }
-  g_all_search_keys.Get() += search_key_utf16;
-}
-
-// These are special unofficial strings sent from TalkBack/BrailleBack
-// to jump to certain categories of web elements.
-void InitSearchKeyToPredicateMapIfNeeded() {
-  if (!g_search_key_to_predicate_map.Get().empty()) {
-    return;
-  }
-
-  AddToPredicateMap("ARTICLE", ui::AccessibilityArticlePredicate);
-  AddToPredicateMap("BLOCKQUOTE", ui::AccessibilityBlockquotePredicate);
-  AddToPredicateMap("BUTTON", ui::AccessibilityButtonPredicate);
-  AddToPredicateMap("CHECKBOX", ui::AccessibilityCheckboxPredicate);
-  AddToPredicateMap("COMBOBOX", ui::AccessibilityComboboxPredicate);
-  AddToPredicateMap("CONTROL", ui::AccessibilityControlPredicate);
-  AddToPredicateMap("FOCUSABLE", ui::AccessibilityFocusablePredicate);
-  AddToPredicateMap("FRAME", ui::AccessibilityFramePredicate);
-  AddToPredicateMap("GRAPHIC", ui::AccessibilityGraphicPredicate);
-  AddToPredicateMap("H1", ui::AccessibilityH1Predicate);
-  AddToPredicateMap("H2", ui::AccessibilityH2Predicate);
-  AddToPredicateMap("H3", ui::AccessibilityH3Predicate);
-  AddToPredicateMap("H4", ui::AccessibilityH4Predicate);
-  AddToPredicateMap("H5", ui::AccessibilityH5Predicate);
-  AddToPredicateMap("H6", ui::AccessibilityH6Predicate);
-  AddToPredicateMap("HEADING", ui::AccessibilityHeadingPredicate);
-  AddToPredicateMap("HEADING_SAME", ui::AccessibilityHeadingSameLevelPredicate);
-  AddToPredicateMap("LANDMARK", ui::AccessibilityLandmarkPredicate);
-  AddToPredicateMap("LINK", ui::AccessibilityLinkPredicate);
-  AddToPredicateMap("LIST", ui::AccessibilityListPredicate);
-  AddToPredicateMap("LIST_ITEM", ui::AccessibilityListItemPredicate);
-  AddToPredicateMap("LIVE", ui::AccessibilityLiveRegionPredicate);
-  AddToPredicateMap("MAIN", ui::AccessibilityMainPredicate);
-  AddToPredicateMap("MEDIA", ui::AccessibilityMediaPredicate);
-  AddToPredicateMap("PARAGRAPH", ui::AccessibilityParagraphPredicate);
-  AddToPredicateMap("RADIO", ui::AccessibilityRadioButtonPredicate);
-  AddToPredicateMap("RADIO_GROUP", ui::AccessibilityRadioGroupPredicate);
-  AddToPredicateMap("SECTION", ui::AccessibilitySectionPredicate);
-  AddToPredicateMap("TABLE", ui::AccessibilityTablePredicate);
-  AddToPredicateMap("TEXT_FIELD", ui::AccessibilityTextfieldPredicate);
-  AddToPredicateMap("TEXT_BOLD", ui::AccessibilityTextStyleBoldPredicate);
-  AddToPredicateMap("TEXT_ITALIC", ui::AccessibilityTextStyleItalicPredicate);
-  AddToPredicateMap("TEXT_UNDERLINE",
-                    ui::AccessibilityTextStyleUnderlinePredicate);
-  AddToPredicateMap("TREE", ui::AccessibilityTreePredicate);
-  AddToPredicateMap("UNVISITED_LINK", ui::AccessibilityUnvisitedLinkPredicate);
-  AddToPredicateMap("VISITED_LINK", ui::AccessibilityVisitedLinkPredicate);
-
-  // These are surfaced simply to document the html types, but do not do a
-  // tree/predicate search.
-  AddToPredicateMap(kHtmlTypeRow, AccessibilityNoOpPredicate);
-  AddToPredicateMap(kHtmlTypeColumn, AccessibilityNoOpPredicate);
-  AddToPredicateMap(kHtmlTypeRowBounds, AccessibilityNoOpPredicate);
-  AddToPredicateMap(kHtmlTypeColumnBounds, AccessibilityNoOpPredicate);
-  AddToPredicateMap(kHtmlTypeTableBounds, AccessibilityNoOpPredicate);
-  AddToPredicateMap(kHtmlTypeTableBounds, AccessibilityNoOpPredicate);
+  return std::make_tuple(std::ref(*search_key_to_predicate_map),
+                         std::ref(*all_search_keys),
+                         std::ref(*predicate_to_enum_map));
 }
 
 ui::AccessibilityMatchPredicate PredicateForSearchKey(
-    const std::u16string& element_type) {
-  InitSearchKeyToPredicateMapIfNeeded();
-  const auto& iter = g_search_key_to_predicate_map.Get().find(element_type);
-  if (iter != g_search_key_to_predicate_map.Get().end()) {
+    std::u16string& element_type) {
+  const auto& [search_map, all_keys, enum_map] = GetSearchKeyData();
+  const auto& iter = search_map.find(element_type);
+  if (iter != search_map.end()) {
     return iter->second;
+  } else {
+    element_type = u"UNKNOWN";
   }
 
   // If we don't recognize the selector, return any element that a
@@ -158,6 +288,17 @@
   return AllInterestingNodesPredicate;
 }
 
+AccessibilityPredicateType EnumForPredicate(
+    const std::u16string& element_type) {
+  const auto& [search_map, all_keys, enum_map] = GetSearchKeyData();
+  const auto& it = enum_map.find(element_type);
+  if (it != enum_map.end()) {
+    return it->second;
+  } else {
+    NOTREACHED();
+  }
+}
+
 // The element in the document for which we may be displaying an autofill popup.
 int32_t g_element_hosting_autofill_popup_unique_id = ui::kInvalidAXNodeID;
 
@@ -778,8 +919,8 @@
 
 base::android::ScopedJavaLocalRef<jstring>
 WebContentsAccessibilityAndroid::GetSupportedHtmlElementTypes(JNIEnv* env) {
-  InitSearchKeyToPredicateMapIfNeeded();
-  return GetCanonicalJNIString(env, g_all_search_keys.Get()).AsLocalRef(env);
+  const auto& [search_map, all_keys, enum_map] = GetSearchKeyData();
+  return GetCanonicalJNIString(env, all_keys).AsLocalRef(env);
 }
 
 jint WebContentsAccessibilityAndroid::GetRootId(JNIEnv* env) {
@@ -1263,7 +1404,9 @@
     const JavaParamRef<jstring>& element_type_str,
     jboolean forwards,
     jboolean can_wrap_to_last_element,
-    jboolean use_default_predicate) {
+    jboolean use_default_predicate,
+    jboolean is_talkback_enabled,
+    jboolean is_only_talkback_enabled) {
   base::ElapsedTimer timer;
   BrowserAccessibilityAndroid* start_node = GetAXFromUniqueID(start_id);
   if (!start_node) {
@@ -1283,10 +1426,12 @@
 
   // If |element_type_str| was empty, we can skip to the default predicate.
   ui::AccessibilityMatchPredicate predicate;
+  std::u16string element_type;
   if (use_default_predicate) {
     predicate = AllInterestingNodesPredicate;
+    element_type = u"DEFAULT";
   } else {
-    const auto element_type =
+    element_type =
         base::android::ConvertJavaStringToUTF16(env, element_type_str);
     if (std::optional<int> ret =
             MaybeFindRowColumn(start_node, element_type, forwards);
@@ -1300,6 +1445,24 @@
     predicate = PredicateForSearchKey(element_type);
   }
 
+  // Record the type of element that was used for navigation, splitting by
+  // whether or not TalkBack was running to see how frequently other apps use
+  // this functionality.
+  if (is_only_talkback_enabled) {
+    base::UmaHistogramEnumeration(
+        "Accessibility.Android.FindElementType.Usage.OnlyTalkBackRunning",
+        EnumForPredicate(element_type));
+  } else if (is_talkback_enabled) {
+    base::UmaHistogramEnumeration(
+        "Accessibility.Android.FindElementType.Usage."
+        "TalkBackRunningWithOtherAT",
+        EnumForPredicate(element_type));
+  } else {
+    base::UmaHistogramEnumeration(
+        "Accessibility.Android.FindElementType.Usage.NotTalkBackAT",
+        EnumForPredicate(element_type));
+  }
+
   ui::OneShotAccessibilityTreeSearch tree_search(root);
   tree_search.SetStartNode(start_node);
   tree_search.SetDirection(forwards
diff --git a/content/browser/accessibility/web_contents_accessibility_android.h b/content/browser/accessibility/web_contents_accessibility_android.h
index 6c65c7c8..e61270f 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.h
+++ b/content/browser/accessibility/web_contents_accessibility_android.h
@@ -196,7 +196,9 @@
                        const base::android::JavaParamRef<jstring>& element_type,
                        jboolean forwards,
                        jboolean can_wrap_to_last_element,
-                       jboolean use_default_predicate);
+                       jboolean use_default_predicate,
+                       jboolean is_talkback_enabled,
+                       jboolean is_only_talkback_enabled);
 
   // Respond to a ACTION_[NEXT/PREVIOUS]_AT_MOVEMENT_GRANULARITY action
   // and move the cursor/selection within the given node id. We keep track
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index dacaf31..f1d1b46 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -893,8 +893,9 @@
   FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE, base::BindLambdaForTesting([&]() {
-        root->navigator().BeforeUnloadCompleted(root, true /* proceed */,
-                                                base::TimeTicks::Now());
+        root->navigator().BeforeUnloadCompleted(
+            root, /*proceed=*/true, base::TimeTicks::Now(),
+            /*for_legacy=*/false, /*showed_dialog=*/false);
       }));
 
   // 7) Evict entry B. This will post a task (task #3) to restart the navigation
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index 3fdc9c1..df29825 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -21120,56 +21120,6 @@
   EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url);
 }
 
-class AuctionRunnerPassRecencyToGenerateBidDisabledTest
-    : public AuctionRunnerTest {
- public:
-  AuctionRunnerPassRecencyToGenerateBidDisabledTest() {
-    feature_list_.InitAndDisableFeature(
-        blink::features::kFledgePassRecencyToGenerateBid);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_F(AuctionRunnerPassRecencyToGenerateBidDisabledTest, NotPassed) {
-  const char kBidScript[] = R"(
-    function generateBid(
-        interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
-        browserSignals) {
-      // PassRecencyToGenerateBid is disabled, so recency shouldn't be set.
-      if (typeof browserSignals.recency !== "undefined") {
-        throw "Wrong recency " + browserSignals.recency;
-      }
-      return {bid: 1,
-              render: interestGroup.ads[0].renderURL};
-    }
-
-    function reportWin(
-        auctionSignals, perBuyerSignals, sellerSignals, browserSignals) {
-    }
-  )";
-
-  const std::string kSellerScript = R"(
-    function scoreAd(adMetadata, bid, auctionConfig, browserSignals) {
-      return bid;
-    }
-
-    function reportResult(auctionConfig, browserSignals) {
-    }
-  )";
-
-  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kBidder1Url,
-                                         kBidScript);
-  auction_worklet::AddJavascriptResponse(&url_loader_factory_, kSellerUrl,
-                                         kSellerScript);
-
-  RunStandardAuction(/*request_trusted_bidding_signals=*/false);
-  EXPECT_FALSE(result_.aborted_by_script);
-  EXPECT_EQ(kBidder1Key, result_.winning_group_id);
-  EXPECT_EQ(GURL("https://ad1.com/"), result_.ad_descriptor->url);
-}
-
 TEST_F(RoundingTest, BidRounded) {
   const char kBidScript[] = R"(
     function generateBid(
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index 7be3abda..0f3dec57 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -2215,14 +2215,8 @@
  protected:
   InterestGroupPrivateNetworkBrowserTest()
       : remote_test_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {
-    feature_list_.InitWithFeatures(
-        /*`enabled_features`=*/
-        {features::kPrivateNetworkAccessRespectPreflightResults},
-        /*disabled_features=*/
-        // TODO(crbug.com/40261655): Enable same-origin exemption when
-        // the initiator is fixed.
-        {network::features::
-             kLocalNetworkAccessAllowPotentiallyTrustworthySameOrigin});
+    feature_list_.InitAndEnableFeature(
+        features::kPrivateNetworkAccessRespectPreflightResults);
 
     remote_test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
     remote_test_server_.AddDefaultHandlers(GetTestDataFilePath());
@@ -17342,10 +17336,11 @@
 
 // Make sure that the IPAddressSpace of the frame that triggers the update is
 // respected for the update request. Does this by adding an interest group,
-// trying to update it from a public page, and expecting the request to be
-// blocked, and then adding another interest group and updating it from a
-// private page, which should succeed. Have to use two interest groups to avoid
-// the delay between updates.
+// trying to update it from a public page. The update since updates are
+// considered same-origin requests and the private networking logic exempts
+// those from needing preflights. Checks the IPAddressSpace passed to the
+// network layer, though, to make sure the correct one is passed in. Have to use
+// two interest groups to avoid the delay between updates.
 IN_PROC_BROWSER_TEST_F(InterestGroupPrivateNetworkBrowserTest,
                        UpdatePublicVsPrivateNetwork) {
   const char kPubliclyUpdateGroupName[] = "Publicly updated group";
@@ -17417,51 +17412,45 @@
     ASSERT_TRUE(request.trusted_params->isolation_info.network_isolation_key()
                     .IsTransient());
 
-    // The request should be blocked in the public address space case.
-    if (public_address_space) {
-      EXPECT_EQ(
-          net::ERR_BLOCKED_BY_PRIVATE_NETWORK_ACCESS_CHECKS,
-          url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
-    } else {
-      EXPECT_EQ(
-          net::OK,
-          url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
-    }
+    // The request should succeed in both cases, due to being same-origin.
+    EXPECT_EQ(
+        net::OK,
+        url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
 
     url_loader_monitor.ClearRequests();
   }
 
-  // Wait for the kLocallyUpdateGroupName interest group to have an updated
-  // bidding URL, while expecting the kPubliclyUpdateGroupName to continue to
-  // have the original bidding URL. Have to wait because just because
+  // Wait for both groups to be updated. Have to wait because just because
   // URLLoaderMonitor has seen the request completed successfully doesn't mean
   // that the InterestGroup has been updated yet.
   WaitForInterestGroupsSatisfying(
       url::Origin::Create(initial_bidding_url),
       base::BindLambdaForTesting(
           [&](scoped_refptr<StorageInterestGroups> storage_groups) {
-            bool found_updated_group = false;
+            bool publicly_updated_group_updated = false;
+            bool locally_updated_group_updated = false;
             for (const auto& storage_group :
                  storage_groups->GetInterestGroups()) {
               const blink::InterestGroup& group = storage_group->interest_group;
               if (group.name == kPubliclyUpdateGroupName) {
-                EXPECT_EQ(initial_bidding_url, group.bidding_url);
+                publicly_updated_group_updated =
+                    (new_bidding_url == group.bidding_url);
               } else {
                 EXPECT_EQ(group.name, kLocallyUpdateGroupName);
-                found_updated_group = (new_bidding_url == group.bidding_url);
+                locally_updated_group_updated =
+                    (new_bidding_url == group.bidding_url);
               }
             }
-            return found_updated_group;
+            return publicly_updated_group_updated &&
+                   locally_updated_group_updated;
           }));
 }
 
 // Create three interest groups, each belonging to different origins. Update one
 // on a private network, but delay its server response. Update the second on a
-// public network (thus expecting the request to be blocked). Update the final
-// interest group on a private interest group -- it should be updated after the
-// first two. After the server responds to the first update request, all updates
-// should proceed -- the first should succeed, and the second should be blocked
-// since the page is on a public network, and the third should succeed.
+// public network. Update the final interest group on a private interest group
+// -- it should be updated after the first two. After the server responds to the
+// first update request, all updates should proceed, and succeed.
 IN_PROC_BROWSER_TEST_F(InterestGroupPrivateNetworkBrowserTest,
                        PrivateNetProtectionsApplyToSubsequentUpdates) {
   constexpr char kLocallyUpdateGroupName[] = "Locally updated group";
@@ -17528,8 +17517,7 @@
 
   // Now, create an interest group in b.test and start updating it from a
   // public site. The update will be delayed because the first interest group
-  // hasn't finished updating, and it should get blocked because we are on a
-  // public page.
+  // hasn't finished updating.
   ASSERT_TRUE(NavigateToURL(
       shell(),
       embedded_https_test_server().GetURL(
@@ -17549,8 +17537,7 @@
 
   EXPECT_EQ("done", UpdateInterestGroupsInJS());
 
-  // Finally, create and update the last interest group on a private network --
-  // this update shouldn't be blocked.
+  // Finally, create and update the last interest group on a private network.
   ASSERT_TRUE(NavigateToURL(
       shell(), embedded_https_test_server().GetURL("c.test", "/echo")));
 
@@ -17572,8 +17559,23 @@
   network_responder_->DoDeferredUpdateResponse(
       JsReplace(kUpdateContentTemplate, new_bidding_url_a));
 
-  // Wait for the c.test to update -- after it updates, all the other interest
-  // groups should have updated too.
+  // Wait for all the interest groups to update.
+  WaitForInterestGroupsSatisfying(
+      url::Origin::Create(initial_bidding_url_a),
+      base::BindLambdaForTesting(
+          [&](scoped_refptr<StorageInterestGroups> storage_groups) {
+            return storage_groups->size() == 1 &&
+                   storage_groups->GetInterestGroups()[0]
+                           ->interest_group.bidding_url == new_bidding_url_a;
+          }));
+  WaitForInterestGroupsSatisfying(
+      url::Origin::Create(initial_bidding_url_b),
+      base::BindLambdaForTesting(
+          [&](scoped_refptr<StorageInterestGroups> storage_groups) {
+            return storage_groups->size() == 1 &&
+                   storage_groups->GetInterestGroups()[0]
+                           ->interest_group.bidding_url == new_bidding_url_b;
+          }));
   WaitForInterestGroupsSatisfying(
       url::Origin::Create(initial_bidding_url_c),
       base::BindLambdaForTesting(
@@ -17582,30 +17584,12 @@
                    storage_groups->GetInterestGroups()[0]
                            ->interest_group.bidding_url == new_bidding_url_c;
           }));
-
-  // By this point, all the interest group updates should have completed.
-  scoped_refptr<StorageInterestGroups> a_groups =
-      GetInterestGroupsForOwner(url::Origin::Create(initial_bidding_url_a));
-  ASSERT_EQ(a_groups->size(), 1u);
-  EXPECT_EQ(a_groups->GetInterestGroups()[0]->interest_group.bidding_url,
-            new_bidding_url_a);
-
-  scoped_refptr<StorageInterestGroups> b_groups =
-      GetInterestGroupsForOwner(url::Origin::Create(initial_bidding_url_b));
-  ASSERT_EQ(b_groups->size(), 1u);
-
-  // Because it was updated on a public address, the update for b.test didn't
-  // happen.
-  EXPECT_EQ(b_groups->GetInterestGroups()[0]->interest_group.bidding_url,
-            initial_bidding_url_b);
 }
 
 // Join interest groups with local (private) update URLs, and run auctions from
 // both a a main frame loaded with public address space, and with a private
-// address space. The auctions trigger updates the interest groups, but only the
-// frame using a private address space successfully updates the IG, since frames
-// from public address spaces are blocked from making requests to servers with
-// private addresses.
+// address space. Check that the address space of the main frame is always used
+// for the updated.
 //
 // Different interest groups (with different origins) are used for the public
 // and private auction, to avoid running into update rate limits.
@@ -17614,16 +17598,6 @@
   // Fetches for the interest group-related scripts and updates are always
   // local, it's where they're updated from that matters. Interest group A will
   // be updated from an auction on a public origin, and B from a private one.
-  // Only the second update will succeed.
-  //
-  // It's important to do the successful update last, so that the first update
-  // would have most likely succeeded by that point in time, if it were going
-  // to, since there's no exposed API to wait for an interest group update to
-  // fail, though the test does wait for the update network request itself to
-  // succeed / fail. As of this writing, the current updating queuing should
-  // guarantee updates for one origin start only after previously requested
-  // updates for another origin have completed (successfully or unsuccessfully),
-  // but this test should be robust against changes in that logic.
   const url::Origin interest_group_a_origin =
       embedded_https_test_server().GetOrigin("a.test");
   const url::Origin interest_group_b_origin =
@@ -17699,7 +17673,7 @@
         test_case.interest_group_origin));
     if (test_case.run_auction_from_public_address_space) {
       // The auction fails because the scripts get blocked; the update request
-      // should still happen, though it will also ultimately be blocked.
+      // should still happen.
       EXPECT_EQ(nullptr, auction_result);
     } else {
       TestFencedFrameURLMappingResultObserver observer;
@@ -17717,19 +17691,17 @@
       EXPECT_EQ(
           network::mojom::IPAddressSpace::kPublic,
           request.trusted_params->client_security_state->ip_address_space);
-      // The request should be blocked in the public address space case.
-      EXPECT_EQ(
-          net::ERR_BLOCKED_BY_PRIVATE_NETWORK_ACCESS_CHECKS,
-          url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
     } else {
       EXPECT_EQ(
           network::mojom::IPAddressSpace::kLocal,
           request.trusted_params->client_security_state->ip_address_space);
-      EXPECT_EQ(
-          net::OK,
-          url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
     }
 
+    // The update should succeed in both cases.
+    EXPECT_EQ(
+        net::OK,
+        url_loader_monitor.WaitForRequestCompletion(update_url).error_code);
+
     // Not the main purpose of this test, but it should be using a transient
     // NetworkIsolationKey as well.
     ASSERT_TRUE(request.trusted_params->isolation_info.network_isolation_key()
@@ -17758,14 +17730,14 @@
   WaitForInterestGroupsSatisfying(interest_group_b_origin,
                                   check_for_new_ad_url);
 
-  // Check that interest group A's ad URL was not updated.
+  // Check that interest group A's ad URL was also updated.
   auto storage_groups = GetInterestGroupsForOwner(interest_group_a_origin);
   ASSERT_EQ(storage_groups->size(), 1u);
   const blink::InterestGroup& group =
       storage_groups->GetInterestGroups()[0]->interest_group;
   ASSERT_TRUE(group.ads.has_value());
   ASSERT_EQ(group.ads->size(), 1u);
-  EXPECT_EQ(initial_ad_url, group.ads.value()[0].render_url());
+  EXPECT_EQ(new_ad_url, group.ads.value()[0].render_url());
 }
 
 // Interest group APIs succeeded (i.e., feature join-ad-interest-group is
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index cc3a158..11b5a15 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -2241,6 +2241,7 @@
           common_params_->url.spec(), "Net Error Code", net_error_);
       MaybeRecordTraceEventsAndHistograms();
     }
+    MaybeRecordNavigationStartAdjustments();
 
     // Abandon the prerender host reserved for activation if it exists.
     if (IsPrerenderedPageActivation()) {
@@ -2416,6 +2417,20 @@
   BeginNavigationImpl();
 }
 
+void NavigationRequest::UpdateNavigationStartTime(const base::TimeTicks& time,
+                                                  bool for_legacy,
+                                                  bool showed_dialog) {
+  // Should be called at most once per NavigationRequest.
+  CHECK(original_navigation_start_.is_null());
+
+  // Track the adjustment details for https://crbug.com/385170155.
+  original_navigation_start_ = common_params_->navigation_start;
+  navigation_start_adjustment_for_legacy_ = for_legacy;
+  beforeunload_dialog_shown_ = showed_dialog;
+
+  common_params_->navigation_start = time;
+}
+
 bool NavigationRequest::MaybeStartPrerenderingActivationChecks() {
   // Find an available prerendered page for this request. If it's found, this
   // request may activate it instead of loading a page via network.
@@ -11032,6 +11047,64 @@
 #undef MAYBE_RECORD_TRACE_AND_HISTOGRAM1
 }
 
+void NavigationRequest::MaybeRecordNavigationStartAdjustments() {
+  // Only record metrics if we have a navigation start time.
+  if (common_params().navigation_start.is_null()) {
+    return;
+  }
+
+  // Some navigations do not adjust the start time, in which case
+  // `original_navigation_start_` is left as null.
+  if (original_navigation_start_.is_null()) {
+    base::UmaHistogramEnumeration("Navigation.StartAdjustment",
+                                  NavigationStartAdjustmentType::kNone);
+    return;
+  }
+
+  // Compute the adjustment made and what percentage of the total navigation
+  // time it includes (approximating now as the end of the navigation).
+  base::TimeDelta adjustment =
+      common_params().navigation_start - original_navigation_start_;
+  base::TimeDelta original_start_to_finish =
+      base::TimeTicks::Now() - original_navigation_start_;
+  // Note that in unit tests, all timestamps can be the same. Skip recording
+  // duration metrics if no time has elapsed during the navigation.
+  if (original_start_to_finish.is_zero()) {
+    return;
+  }
+  size_t percentage = 100 * adjustment / original_start_to_finish;
+
+  // Report the adjustment in UMA metrics specific to the case that occurred.
+  NavigationStartAdjustmentType adjustment_type =
+      NavigationStartAdjustmentType::kNone;
+  std::string histogram_name = "Navigation.StartAdjustment";
+  if (navigation_start_adjustment_for_legacy_) {
+    // No beforeunload handlers actually run in legacy mode.
+    CHECK(!beforeunload_dialog_shown_);
+    adjustment_type = NavigationStartAdjustmentType::kLegacyPostTask;
+    histogram_name += ".LegacyPostTask";
+  } else if (!beforeunload_dialog_shown_) {
+    adjustment_type = NavigationStartAdjustmentType::kBeforeUnloadHandlers;
+    histogram_name += ".BeforeUnloadHandlers";
+  } else {
+    adjustment_type = NavigationStartAdjustmentType::kBeforeUnloadDialog;
+    histogram_name += ".BeforeUnloadDialog";
+  }
+  base::UmaHistogramEnumeration("Navigation.StartAdjustment", adjustment_type);
+  base::UmaHistogramTimes(histogram_name, adjustment);
+  base::UmaHistogramPercentage(histogram_name + ".Percentage", percentage);
+
+  // Show trace events indicating where the adjustment occurred in time.
+  const auto trace_id = TRACE_ID_WITH_SCOPE("NavigationStartAdjustment",
+                                            TRACE_ID_LOCAL(navigation_id_));
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
+      "navigation", "NavigationStartAdjustment", trace_id,
+      original_navigation_start_, "Percentage", percentage);
+  TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
+      "navigation", "NavigationStartAdjustment", trace_id,
+      common_params().navigation_start);
+}
+
 void NavigationRequest::SanitizeDocumentIsolationPolicyHeader() {
   if (!response_head_) {
     return;
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index ca67aa8c..a17ca3b 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -481,10 +481,30 @@
     return *commit_params_;
   }
 
-  // Updates the navigation start time.
-  void set_navigation_start_time(const base::TimeTicks& time) {
-    common_params_->navigation_start = time;
-  }
+  // This describes the cases where the navigation start time is adjusted to be
+  // later in time, after BeforeUnloadCompleted. This enum is used in UMA
+  // histograms, so existing values should be neither reordered nor removed.
+  enum class NavigationStartAdjustmentType {
+    // No adjustment to the navigation start time was made.
+    kNone = 0,
+    // The start time was adjusted so that the navigation could proceed via a
+    // posted task, even though there were no beforeunload handlers registered.
+    kLegacyPostTask = 1,
+    // The start time was adjusted because beforeunload handlers ran, but no
+    // dialog was displayed to the user.
+    kBeforeUnloadHandlers = 2,
+    // The start time was adjusted because a beforeunload dialog was shown.
+    kBeforeUnloadDialog = 3,
+    kMaxValue = kBeforeUnloadDialog,
+  };
+
+  // Updates the navigation start time, after beforeunload has completed.
+  // `for_legacy` indicates that the navigation proceeded in a separate task for
+  // legacy reasons, without running beforeunload handlers. `showed_dialog`
+  // indicates whether the beforeunload handlers actually displayed a dialog.
+  void UpdateNavigationStartTime(const base::TimeTicks& time,
+                                 bool for_legacy,
+                                 bool showed_dialog);
 
   void set_is_cross_site_cross_browsing_context_group(
       bool is_cross_site_cross_browsing_context_group) {
@@ -2096,6 +2116,11 @@
 
   void MaybeRecordTraceEventsAndHistograms();
 
+  // Records how much the navigation start time was adjusted for beforeunload
+  // handlers, for various scenarios (legacy, beforeunload handlers only, and
+  // beforeunload dialogs). See https://crbug.com/385170155.
+  void MaybeRecordNavigationStartAdjustments();
+
   void ResetViewTransitionState();
 
   // This check is to prevent a race condition where a parent fenced frame
@@ -2371,6 +2396,18 @@
   // Timing information of loading for the navigation. Used for recording UMAs.
   NavigationHandleTiming navigation_handle_timing_;
 
+  // The original value of navigation start for a given navigation, before any
+  // adjustment is made to avoid counting beforeunload dialogs. This is null
+  // (i.e., `TimeTicks()`) unless an adjustment was made.
+  base::TimeTicks original_navigation_start_;
+
+  // Tracks whether an adjustment to the navigation start time was done for
+  // legacy PostTask reasons rather than for running a beforeunload handler.
+  bool navigation_start_adjustment_for_legacy_ = false;
+
+  // Tracks whether a beforeunload dialog was shown as part of this navigation.
+  bool beforeunload_dialog_shown_ = false;
+
   // The time this navigation was ready to commit.
   base::TimeTicks ready_to_commit_time_;
 
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc
index bc6d0bae..e1816f1 100644
--- a/content/browser/renderer_host/navigator.cc
+++ b/content/browser/renderer_host/navigator.cc
@@ -1123,7 +1123,9 @@
 
 void Navigator::BeforeUnloadCompleted(FrameTreeNode* frame_tree_node,
                                       bool proceed,
-                                      const base::TimeTicks& proceed_time) {
+                                      const base::TimeTicks& proceed_time,
+                                      bool for_legacy,
+                                      bool showed_dialog) {
   DCHECK(frame_tree_node);
 
   NavigationRequest* navigation_request = frame_tree_node->navigation_request();
@@ -1157,7 +1159,8 @@
 
   // Update the navigation start: it should be when it was determined that the
   // navigation will proceed.
-  navigation_request->set_navigation_start_time(proceed_time);
+  navigation_request->UpdateNavigationStartTime(proceed_time, for_legacy,
+                                                showed_dialog);
 
   DCHECK_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
             navigation_request->state());
diff --git a/content/browser/renderer_host/navigator.h b/content/browser/renderer_host/navigator.h
index 22051fa..5db1e21ef 100644
--- a/content/browser/renderer_host/navigator.h
+++ b/content/browser/renderer_host/navigator.h
@@ -177,12 +177,16 @@
           std::nullopt);
 
   // Called after BeforeUnloadCompleted callback is invoked from the renderer.
-  // If |frame_tree_node| has a NavigationRequest waiting for the renderer
+  // If `frame_tree_node` has a NavigationRequest waiting for the renderer
   // response, then the request is either started or canceled, depending on the
-  // value of |proceed|.
+  // value of `proceed`. If `for_legacy` is true, then this beforeunload flow
+  // was only used to post a task and no beforeunload handlers were run. If
+  // `showed_dialog` is true, then a beforeunload dialog was displayed.
   void BeforeUnloadCompleted(FrameTreeNode* frame_tree_node,
                              bool proceed,
-                             const base::TimeTicks& proceed_time);
+                             const base::TimeTicks& proceed_time,
+                             bool for_legacy,
+                             bool showed_dialog);
 
   // Used to start a new renderer-initiated navigation, following a
   // BeginNavigation IPC from the renderer.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index ea77770f..61e054b 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6235,6 +6235,8 @@
         send_before_unload_start_time_, for_legacy);
   }
 
+  bool showed_dialog = has_shown_beforeunload_dialog_;
+
   // Resets beforeunload waiting state.
   is_waiting_for_beforeunload_completion_ = false;
   has_shown_beforeunload_dialog_ = false;
@@ -6249,7 +6251,8 @@
   base::OnceClosure task = base::BindOnce(
       [](base::WeakPtr<RenderFrameHostImpl> self,
          const base::TimeTicks& before_unload_end_time, bool proceed,
-         bool unload_ack_is_for_navigation) {
+         bool unload_ack_is_for_navigation, bool for_legacy,
+         bool showed_dialog) {
         if (!self)
           return;
         FrameTreeNode* frame = self->frame_tree_node();
@@ -6258,7 +6261,8 @@
         // RenderFrameHostManager which handles closing.
         if (unload_ack_is_for_navigation) {
           frame->navigator().BeforeUnloadCompleted(frame, proceed,
-                                                   before_unload_end_time);
+                                                   before_unload_end_time,
+                                                   for_legacy, showed_dialog);
         } else {
           frame->render_manager()->BeforeUnloadCompleted(proceed);
         }
@@ -6269,7 +6273,7 @@
       // which is tricky.
       weak_ptr_factory_.GetWeakPtr(),
       before_unload_end_time - browser_to_renderer_ipc_time_delta, proceed,
-      unload_ack_is_for_navigation_);
+      unload_ack_is_for_navigation_, for_legacy, showed_dialog);
 
   if (is_frame_being_destroyed) {
     DCHECK(proceed);
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 8eb9c811..490f489e1 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -217,6 +217,9 @@
 class RenderFrameHostImplBrowserTest : public ContentBrowserTest {
  public:
   using LifecycleStateImpl = RenderFrameHostImpl::LifecycleStateImpl;
+  using NavigationStartAdjustmentType =
+      NavigationRequest::NavigationStartAdjustmentType;
+
   RenderFrameHostImplBrowserTest()
       : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
   ~RenderFrameHostImplBrowserTest() override = default;
@@ -743,8 +746,13 @@
   TestJavaScriptDialogManager dialog_manager;
   web_contents()->SetDelegate(&dialog_manager);
 
-  EXPECT_TRUE(NavigateToURL(
-      shell(), GetTestUrl("render_frame_host", "beforeunload.html")));
+  {
+    base::HistogramTester histogram_tester;
+    EXPECT_TRUE(NavigateToURL(
+        shell(), GetTestUrl("render_frame_host", "beforeunload.html")));
+    histogram_tester.ExpectUniqueSample(
+        "Navigation.StartAdjustment", NavigationStartAdjustmentType::kNone, 1);
+  }
   // Disable the hang monitor, otherwise there will be a race between the
   // beforeunload dialog and the beforeunload hang timer.
   web_contents()
@@ -753,8 +761,18 @@
 
   // Reload. There should be no beforeunload dialog because there was no gesture
   // on the page. If there was, this WaitForLoadStop call will hang.
-  web_contents()->GetController().Reload(ReloadType::NORMAL, false);
-  EXPECT_TRUE(WaitForLoadStop(web_contents()));
+  {
+    base::HistogramTester histogram_tester;
+    web_contents()->GetController().Reload(ReloadType::NORMAL, false);
+    EXPECT_TRUE(WaitForLoadStop(web_contents()));
+    histogram_tester.ExpectUniqueSample(
+        "Navigation.StartAdjustment",
+        NavigationStartAdjustmentType::kBeforeUnloadHandlers, 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.BeforeUnloadHandlers", 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.BeforeUnloadHandlers.Percentage", 1);
+  }
 
   // Give the page a user gesture and try reloading again. This time there
   // should be a dialog. If there is no dialog, the call to Wait will hang.
@@ -762,12 +780,22 @@
       ->GetPrimaryMainFrame()
       ->ExecuteJavaScriptWithUserGestureForTests(
           std::u16string(), base::NullCallback(), ISOLATED_WORLD_ID_GLOBAL);
-  web_contents()->GetController().Reload(ReloadType::NORMAL, false);
-  dialog_manager.Wait();
+  {
+    base::HistogramTester histogram_tester;
+    web_contents()->GetController().Reload(ReloadType::NORMAL, false);
+    dialog_manager.Wait();
 
-  // Answer the dialog.
-  dialog_manager.Run(true, std::u16string());
-  EXPECT_TRUE(WaitForLoadStop(web_contents()));
+    // Answer the dialog.
+    dialog_manager.Run(true, std::u16string());
+    EXPECT_TRUE(WaitForLoadStop(web_contents()));
+    histogram_tester.ExpectUniqueSample(
+        "Navigation.StartAdjustment",
+        NavigationStartAdjustmentType::kBeforeUnloadDialog, 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.BeforeUnloadDialog", 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.BeforeUnloadDialog.Percentage", 1);
+  }
 
   // The reload should have cleared the user gesture bit, so upon leaving again
   // there should be no beforeunload dialog.
@@ -2139,8 +2167,21 @@
                   ->GetHasPostData());
 
   // Reload and verify the form was submitted.
-  web_contents()->GetController().Reload(ReloadType::NORMAL, false);
-  EXPECT_TRUE(WaitForLoadStop(web_contents()));
+  {
+    base::HistogramTester histogram_tester;
+    web_contents()->GetController().Reload(ReloadType::NORMAL, false);
+    EXPECT_TRUE(WaitForLoadStop(web_contents()));
+
+    // This browser-initiated reload adjusts navigation start time for a legacy
+    // PostTask, without any beforeunload handlers present.
+    histogram_tester.ExpectUniqueSample(
+        "Navigation.StartAdjustment",
+        NavigationStartAdjustmentType::kLegacyPostTask, 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.LegacyPostTask", 1);
+    histogram_tester.ExpectTotalCount(
+        "Navigation.StartAdjustment.LegacyPostTask.Percentage", 1);
+  }
   EXPECT_EQ("text=&select=a", base::UTF16ToASCII(web_contents()->GetTitle()));
   CHECK_EQ(2, post_counter);
 }
diff --git a/content/browser/resources/attribution_reporting/BUILD.gn b/content/browser/resources/attribution_reporting/BUILD.gn
index b1405d4..441e0d6 100644
--- a/content/browser/resources/attribution_reporting/BUILD.gn
+++ b/content/browser/resources/attribution_reporting/BUILD.gn
@@ -8,15 +8,15 @@
   grd_prefix = "attribution_internals"
 
   static_files = [
-    "attribution_internals.html",
     "attribution_internals.css",
+    "attribution_internals.html",
   ]
 
   non_web_component_files = [ "attribution_internals.ts" ]
 
   web_component_files = [
-    "attribution_internals_table.ts",
     "attribution_detail_table.ts",
+    "attribution_internals_table.ts",
   ]
 
   ts_deps = [
@@ -32,19 +32,19 @@
   network_folder = "services/network/public/mojom"
 
   mojo_files = [
+    "$root_gen_dir/$attribution_reporting_component_folder/debug_types.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_component_folder/registration.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_component_folder/source_registration_time_config.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_component_folder/source_type.mojom-webui.ts",
-    "$root_gen_dir/$attribution_reporting_component_folder/debug_types.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_component_folder/trigger_data_matching.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_content_folder/aggregatable_result.mojom-webui.ts",
-    "$root_gen_dir/$attribution_reporting_content_folder/process_aggregatable_debug_report_result.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_content_folder/attribution_internals.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_content_folder/attribution_reporting.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_content_folder/event_level_result.mojom-webui.ts",
+    "$root_gen_dir/$attribution_reporting_content_folder/process_aggregatable_debug_report_result.mojom-webui.ts",
     "$root_gen_dir/$attribution_reporting_content_folder/store_source_result.mojom-webui.ts",
-    "$root_gen_dir/$network_folder/schemeful_site.mojom-webui.ts",
     "$root_gen_dir/$network_folder/attribution.mojom-webui.ts",
+    "$root_gen_dir/$network_folder/schemeful_site.mojom-webui.ts",
   ]
 
   mojo_files_deps = [
diff --git a/content/browser/resources/indexed_db/BUILD.gn b/content/browser/resources/indexed_db/BUILD.gn
index 8dd5f94..ba45a78 100644
--- a/content/browser/resources/indexed_db/BUILD.gn
+++ b/content/browser/resources/indexed_db/BUILD.gn
@@ -9,8 +9,8 @@
 
   static_files = [
     "common.css",
-    "indexeddb_internals.html",
     "indexeddb_internals.css",
+    "indexeddb_internals.html",
   ]
 
   web_component_files = [
diff --git a/content/browser/resources/private_aggregation/BUILD.gn b/content/browser/resources/private_aggregation/BUILD.gn
index 4dbd06e..9ea388b 100644
--- a/content/browser/resources/private_aggregation/BUILD.gn
+++ b/content/browser/resources/private_aggregation/BUILD.gn
@@ -8,8 +8,8 @@
   grd_prefix = "private_aggregation_internals"
 
   static_files = [
-    "private_aggregation_internals.html",
     "private_aggregation_internals.css",
+    "private_aggregation_internals.html",
   ]
 
   non_web_component_files = [
diff --git a/content/browser/resources/quota/BUILD.gn b/content/browser/resources/quota/BUILD.gn
index 6f7b2a4..28fa1a7 100644
--- a/content/browser/resources/quota/BUILD.gn
+++ b/content/browser/resources/quota/BUILD.gn
@@ -8,8 +8,8 @@
   grd_prefix = "quota_internals"
 
   static_files = [
-    "quota_internals.html",
     "quota_internals.css",
+    "quota_internals.html",
   ]
 
   non_web_component_files = [
diff --git a/content/browser/resources/traces_internals/BUILD.gn b/content/browser/resources/traces_internals/BUILD.gn
index 72e01f4..5c1b16ae 100644
--- a/content/browser/resources/traces_internals/BUILD.gn
+++ b/content/browser/resources/traces_internals/BUILD.gn
@@ -8,26 +8,26 @@
   grd_prefix = "traces_internals"
 
   static_files = [
-    "trace_report_internals.html",
     "trace_report_internals.css",
+    "trace_report_internals.html",
   ]
 
   non_web_component_files = [
-    "app.ts",
     "app.html.ts",
-    "trace_report_browser_proxy.ts",
-    "trace_report_list.ts",
-    "trace_report_list.html.ts",
-    "trace_report.ts",
+    "app.ts",
     "trace_report.html.ts",
+    "trace_report.ts",
+    "trace_report_browser_proxy.ts",
+    "trace_report_list.html.ts",
+    "trace_report_list.ts",
     "tracing_scenarios_config.html.ts",
     "tracing_scenarios_config.ts",
   ]
 
   css_files = [
     "app.css",
-    "trace_report_list.css",
     "trace_report.css",
+    "trace_report_list.css",
     "tracing_scenarios_config.css",
   ]
 
diff --git a/content/browser/resources/webxr_internals/BUILD.gn b/content/browser/resources/webxr_internals/BUILD.gn
index bffad25..20d99b6 100644
--- a/content/browser/resources/webxr_internals/BUILD.gn
+++ b/content/browser/resources/webxr_internals/BUILD.gn
@@ -10,8 +10,8 @@
   grd_prefix = "webxr_internals"
 
   static_files = [
-    "webxr_internals.html",
     "webxr_internals.css",
+    "webxr_internals.html",
   ]
 
   web_component_files = [
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityHistogramRecorder.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityHistogramRecorder.java
index 41fd8fb..6bfb9e9c 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityHistogramRecorder.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityHistogramRecorder.java
@@ -454,7 +454,7 @@
         if (mHasRecordedTimeToFirstAccessibilityFocus) return;
 
         // We are only interested in this for TalkBack, which always focuses the root node on load.
-        if (!AccessibilityState.isTalkBackEnabled()) return;
+        if (!AccessibilityState.getTalkBackEnabledState().first) return;
 
         // TODO(mschillaci): This uses a 5 sec max, check scale after initial data collection.
         RecordHistogram.recordCustomTimesHistogram(
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index 72eed2d..0abb9cc 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -64,6 +64,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Bundle;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -1460,6 +1461,7 @@
             boolean forwards,
             boolean canWrap,
             boolean setSequentialFocus) {
+        Pair<Boolean, Boolean> talkbackEnabledState = AccessibilityState.getTalkBackEnabledState();
         int id =
                 WebContentsAccessibilityImplJni.get()
                         .findElementType(
@@ -1468,7 +1470,9 @@
                                 elementType,
                                 forwards,
                                 canWrap,
-                                elementType.isEmpty());
+                                elementType.isEmpty(),
+                                talkbackEnabledState.first,
+                                talkbackEnabledState.second);
         if (id == 0) return false;
 
         if (setSequentialFocus) {
@@ -2276,7 +2280,9 @@
                 String elementType,
                 boolean forwards,
                 boolean canWrapToLastElement,
-                boolean useDefaultPredicate);
+                boolean useDefaultPredicate,
+                boolean isTalkbackEnabled,
+                boolean isOnlyTalkbackEnabled);
 
         void setTextFieldValue(long nativeWebContentsAccessibilityAndroid, int id, String newValue);
 
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc
index 44767fcd1..e83e167 100644
--- a/content/services/auction_worklet/bidder_worklet.cc
+++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -1703,9 +1703,7 @@
       (SupportMultiBid() &&
        !browser_signals_dict.Set("multiBidLimit",
                                  static_cast<uint32_t>(multi_bid_limit))) ||
-      (base::FeatureList::IsEnabled(
-           blink::features::kFledgePassRecencyToGenerateBid) &&
-       !browser_signals_dict.Set("recency",
+      (!browser_signals_dict.Set("recency",
                                  browser_signal_recency.InMilliseconds())) ||
       !SetDataVersion(trusted_signals_relation, bidding_signals_data_version,
                       browser_signals_dict) ||
diff --git a/device/vr/public/java/src/org/chromium/device/vr/XrFeatureStatus.java b/device/vr/public/java/src/org/chromium/device/vr/XrFeatureStatus.java
index c337a89..7d85699 100644
--- a/device/vr/public/java/src/org/chromium/device/vr/XrFeatureStatus.java
+++ b/device/vr/public/java/src/org/chromium/device/vr/XrFeatureStatus.java
@@ -8,9 +8,11 @@
 import org.jni_zero.JNINamespace;
 
 import org.chromium.base.PackageManagerUtils;
+import org.chromium.build.annotations.NullMarked;
 
 /** A wrapper to allow querying feature status that depends on java state from native. */
 @JNINamespace("device")
+@NullMarked
 public class XrFeatureStatus {
     @CalledByNative
     public static boolean hasImmersiveFeature() {
diff --git a/docs/website b/docs/website
index 7026ffa..1229734 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit 7026ffa285a6bf16008b0bf927d0bf63985e89ae
+Subproject commit 1229734e08d74bf1d5ce69051ed70d2b392d356c
diff --git a/extensions/browser/api/alarms/alarms_api_unittest.cc b/extensions/browser/api/alarms/alarms_api_unittest.cc
index 8ca3eea..df9c3a82 100644
--- a/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 // This file tests the chrome.alarms extension API.
 
 #include "extensions/browser/api/alarms/alarms_api.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <memory>
 #include <optional>
 #include <string>
@@ -116,7 +112,7 @@
   void CreateAlarms(size_t num_alarms) {
     CHECK_LE(num_alarms, 3U);
 
-    const char* const kCreateArgs[] = {
+    static constexpr std::array kCreateArgs = {
         "[null, {\"periodInMinutes\": 0.001}]",
         "[\"7\", {\"periodInMinutes\": 7}]",
         "[\"0\", {\"delayInMinutes\": 0}]",
@@ -720,7 +716,7 @@
 // subjected to minimum polling interval.
 // Regression test for https://crbug.com/618540.
 TEST_F(ExtensionAlarmsSchedulingTest, PollFrequencyFromStoredAlarm) {
-  struct {
+  static constexpr struct {
     bool is_unpacked;
     int manifest_version;
     base::TimeDelta delay_minimum;
@@ -733,7 +729,7 @@
   };
 
   // Test once for unpacked and once for crx extension.
-  for (size_t i = 0; i < std::size(test_data); ++i) {
+  for (const auto& entry : test_data) {
     test_clock_.SetNow(base::Time::FromSecondsSinceUnixEpoch(10));
 
     // Mimic retrieving an alarm from StateStore.
@@ -741,7 +737,7 @@
         "[{\"name\": \"hello\", \"scheduledTime\": 10000, "
         "\"periodInMinutes\": 0.0001}]";
     base::TimeDelta min_delay = alarms_api_constants::GetMinimumDelay(
-        test_data[i].is_unpacked, test_data[i].manifest_version);
+        entry.is_unpacked, entry.manifest_version);
 
     alarm_manager_->ReadFromStorage(extension()->id(), min_delay,
                                     base::test::ParseJson(alarm_args));
@@ -760,7 +756,7 @@
         // 10s initial clock.
         base::Time::FromSecondsSinceUnixEpoch(10) +
         // 10ms in FrequencyTestGetAlarmsCallback.
-        base::Milliseconds(10) + test_data[i].delay_minimum;
+        base::Milliseconds(10) + entry.delay_minimum;
     // The alarm should not trigger before our expected poll time...
     EXPECT_GE(alarm_manager_->next_poll_time_, expected_poll_time);
     // And should trigger within a few seconds of it (to account for test
diff --git a/extensions/browser/api/content_settings/content_settings_unittest.cc b/extensions/browser/api/content_settings/content_settings_unittest.cc
index 90f1421..4f9f70dd 100644
--- a/extensions/browser/api/content_settings/content_settings_unittest.cc
+++ b/extensions/browser/api/content_settings/content_settings_unittest.cc
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stddef.h>
 
+#include <string>
+
 #include "extensions/browser/api/content_settings/content_settings_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -16,43 +13,43 @@
 namespace helpers = content_settings_helpers;
 
 TEST(ExtensionContentSettingsHelpersTest, ParseExtensionPattern) {
-  const struct {
+  static constexpr struct {
     const char* extension_pattern;
     const char* content_settings_pattern;
   } kTestPatterns[] = {
-    { "<all_urls>", "*" },
-    { "*://*.google.com/*", "[*.]google.com" },
-    { "http://www.example.com/*", "http://www.example.com" },
-    { "*://www.example.com/*", "www.example.com" },
-    { "http://www.example.com:8080/*", "http://www.example.com:8080" },
-    { "https://*/*", "https://*" },
-    { "file:///foo/bar/baz", "file:///foo/bar/baz" },
+      {"<all_urls>", "*"},
+      {"*://*.google.com/*", "[*.]google.com"},
+      {"http://www.example.com/*", "http://www.example.com"},
+      {"*://www.example.com/*", "www.example.com"},
+      {"http://www.example.com:8080/*", "http://www.example.com:8080"},
+      {"https://*/*", "https://*"},
+      {"file:///foo/bar/baz", "file:///foo/bar/baz"},
   };
-  for (size_t i = 0; i < std::size(kTestPatterns); ++i) {
+  for (const auto& entry : kTestPatterns) {
     std::string error;
-    std::string pattern_str = helpers::ParseExtensionPattern(
-        kTestPatterns[i].extension_pattern, &error).ToString();
-    EXPECT_EQ(kTestPatterns[i].content_settings_pattern, pattern_str)
-        << "Unexpected error parsing " << kTestPatterns[i].extension_pattern
-        << ": " << error;
+    std::string pattern_str =
+        helpers::ParseExtensionPattern(entry.extension_pattern, &error)
+            .ToString();
+    EXPECT_EQ(entry.content_settings_pattern, pattern_str)
+        << "Unexpected error parsing " << entry.extension_pattern << ": "
+        << error;
   }
 
-  const struct {
+  static constexpr struct {
     const char* extension_pattern;
     const char* expected_error;
   } kInvalidTestPatterns[] = {
-    { "http://www.example.com/path", "Specific paths are not allowed." },
-    { "file:///foo/bar/*",
-      "Path wildcards in file URL patterns are not allowed." },
+      {"http://www.example.com/path", "Specific paths are not allowed."},
+      {"file:///foo/bar/*",
+       "Path wildcards in file URL patterns are not allowed."},
   };
-  for (size_t i = 0; i < std::size(kInvalidTestPatterns); ++i) {
+  for (const auto& entry : kInvalidTestPatterns) {
     std::string error;
-    ContentSettingsPattern pattern = helpers::ParseExtensionPattern(
-        kInvalidTestPatterns[i].extension_pattern, &error);
+    ContentSettingsPattern pattern =
+        helpers::ParseExtensionPattern(entry.extension_pattern, &error);
     EXPECT_FALSE(pattern.IsValid());
-    EXPECT_EQ(kInvalidTestPatterns[i].expected_error, error)
-        << "Unexpected error parsing "
-        << kInvalidTestPatterns[i].extension_pattern;
+    EXPECT_EQ(entry.expected_error, error)
+        << "Unexpected error parsing " << entry.extension_pattern;
   }
 }
 
diff --git a/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc b/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
index 15292f4a..d577c29d 100644
--- a/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/composite_matcher_unittest.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/declarative_net_request/composite_matcher.h"
 
+#include <array>
 #include <string>
 #include <utility>
 #include <vector>
@@ -536,12 +532,13 @@
       std::move(matchers), /*extension_id=*/"",
       HostPermissionsAlwaysRequired::kTrue);
 
-  struct TestCases {
+  struct TestCase {
     const char* url;
     const PageAccess access;
     const bool expected_notify_withheld;
     std::optional<int> expected_matched_rule_id;
-  } cases[] = {
+  };
+  const auto cases = std::to_array<TestCase>({
       {"https://example.com", PageAccess::kAllowed, false, block_rule.id},
       {"https://example.com", PageAccess::kWithheld, true, std::nullopt},
       {"https://foo.com", PageAccess::kAllowed, false, allow_rule.id},
@@ -552,7 +549,7 @@
       {"http://upgrade.com", PageAccess::kWithheld, true, std::nullopt},
       {"http://nomatch.com", PageAccess::kAllowed, false, std::nullopt},
       {"http://nomatch.com", PageAccess::kWithheld, false, std::nullopt},
-  };
+  });
 
   for (size_t i = 0; i < std::size(cases); i++) {
     SCOPED_TRACE(base::StringPrintf("Testing case %zu", i));
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index f0e6212..d487144 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <memory>
 #include <utility>
 
@@ -152,12 +148,11 @@
 // applicable in all stages.
 TEST(WebRequestConditionAttributeTest, Stages) {
   typedef std::pair<RequestStage, const char*> StageNamePair;
-  static const StageNamePair active_stages[] = {
-    StageNamePair(ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum),
-    StageNamePair(ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum),
-    StageNamePair(ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum),
-    StageNamePair(ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum)
-  };
+  static constexpr auto active_stages = std::to_array<StageNamePair>(
+      {{ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum},
+       {ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum},
+       {ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum},
+       {ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum}});
 
   // Check that exactly all active stages are considered in this test.
   unsigned int covered_stages = 0;
@@ -222,24 +217,22 @@
 
 namespace {
 
-// Builds a vector of vectors of string pointers from an array of strings.
-// |array| is in fact a sequence of arrays. The array |sizes| captures the sizes
-// of all parts of |array|, and |size| is the length of |sizes| itself.
+// Builds a vector of vectors of string pointers from a vector of strings.
+// `strings` is in fact a sequence of arrays. The vector `sizes` captures the
+// sizes of all parts of `strings`.
 // Example (this is pseudo-code, not C++):
-// array = { "a", "b", "c", "d", "e", "f" }
+// strings = { "a", "b", "c", "d", "e", "f" }
 // sizes = { 2, 0, 4 }
-// size = 3
 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} }
-void GetArrayAsVector(const std::string array[],
-                      const size_t sizes[],
-                      const size_t size,
-                      std::vector< std::vector<const std::string*> >* out) {
+void GetArrayAsVector(const std::vector<std::string>& strings,
+                      const std::vector<size_t>& sizes,
+                      std::vector<std::vector<const std::string*>>* out) {
   out->clear();
   size_t next = 0;
-  for (size_t i = 0; i < size; ++i) {
+  for (size_t i = 0; i < sizes.size(); ++i) {
     out->push_back(std::vector<const std::string*>());
     for (size_t j = next; j < next + sizes[i]; ++j) {
-      out->back().push_back(&(array[j]));
+      out->back().push_back(&strings[j]);
     }
     next += sizes[i];
   }
@@ -323,14 +316,13 @@
   const RequestStage stage = ON_BEFORE_SEND_HEADERS;
 
   // First set of test data -- passing conjunction.
-  const std::string kPassingCondition[] = {
-    keys::kNameContainsKey, "CuStOm",  // Header names are case insensitive.
-    keys::kNameEqualsKey, "custom-header",
-    keys::kValueSuffixKey, "alue",
-    keys::kValuePrefixKey, "custom/value"
-  };
-  const size_t kPassingConditionSizes[] = {std::size(kPassingCondition)};
-  GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
+  const std::vector<std::string> kPassingCondition = {
+      keys::kNameContainsKey, "CuStOm",  // Header names are case insensitive.
+      keys::kNameEqualsKey,   "custom-header", keys::kValueSuffixKey, "alue",
+      keys::kValuePrefixKey,  "custom/value"};
+  const std::vector<size_t> kPassingConditionSizes = {
+      std::size(kPassingCondition)};
+  GetArrayAsVector(kPassingCondition, kPassingConditionSizes, &tests);
   // Positive filter, passing (conjunction of tests).
   MatchAndCheck(tests, keys::kRequestHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
@@ -340,14 +332,14 @@
   EXPECT_FALSE(result);
 
   // Second set of test data -- failing disjunction.
-  const std::string kFailCondition[] = {
-    keys::kNameSuffixKey, "Custom",      // Test 1.
-    keys::kNameEqualsKey, "ustom-valu",  // Test 2.
-    keys::kValuePrefixKey, "custom ",    // Test 3.
-    keys::kValueContainsKey, " value"    // Test 4.
+  const std::vector<std::string> kFailCondition = {
+      keys::kNameSuffixKey,    "Custom",      // Test 1.
+      keys::kNameEqualsKey,    "ustom-valu",  // Test 2.
+      keys::kValuePrefixKey,   "custom ",     // Test 3.
+      keys::kValueContainsKey, " value"       // Test 4.
   };
-  const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
-  GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
+  const std::vector<size_t> kFailConditionSizes = {2u, 2u, 2u, 2u};
+  GetArrayAsVector(kFailCondition, kFailConditionSizes, &tests);
   // Positive filter, failing (disjunction of tests).
   MatchAndCheck(tests, keys::kRequestHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
@@ -357,7 +349,7 @@
   EXPECT_TRUE(result);
 
   // Third set of test data, corner case -- empty disjunction.
-  GetArrayAsVector(nullptr, nullptr, 0u, &tests);
+  GetArrayAsVector({}, {}, &tests);
   // Positive filter, failing (no test to pass).
   MatchAndCheck(tests, keys::kRequestHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
@@ -367,8 +359,8 @@
   EXPECT_TRUE(result);
 
   // Fourth set of test data, corner case -- empty conjunction.
-  const size_t kEmptyConjunctionSizes[] = { 0u };
-  GetArrayAsVector(nullptr, kEmptyConjunctionSizes, 1u, &tests);
+  const std::vector<size_t> kEmptyConjunctionSizes = {0u};
+  GetArrayAsVector({}, kEmptyConjunctionSizes, &tests);
   // Positive filter, passing (trivial test).
   MatchAndCheck(tests, keys::kRequestHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
@@ -410,151 +402,142 @@
   const RequestStage stage = ON_HEADERS_RECEIVED;
 
   // 1.a. -- All these tests should pass.
-  const std::string kPassingCondition[] = {
-    keys::kNamePrefixKey, "Custom",
-    keys::kNameSuffixKey, "m-header",  // Header names are case insensitive.
-    keys::kValueContainsKey, "alu",
-    keys::kValueEqualsKey, "custom/value"
-  };
-  const size_t kPassingConditionSizes[] = {std::size(kPassingCondition)};
-  GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
+  const std::vector<std::string> kPassingCondition = {
+      keys::kNamePrefixKey,
+      "Custom",
+      keys::kNameSuffixKey,
+      "m-header",  // Header names are case insensitive.
+      keys::kValueContainsKey,
+      "alu",
+      keys::kValueEqualsKey,
+      "custom/value"};
+  const std::vector<size_t> kPassingConditionSizes = {
+      std::size(kPassingCondition)};
+  GetArrayAsVector(kPassingCondition, kPassingConditionSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 1.b. -- None of the following tests in the discjunction should pass.
-  const std::string kFailCondition[] = {
-    keys::kNamePrefixKey, " Custom",  // Test 1.
-    keys::kNameContainsKey, " -",     // Test 2.
-    keys::kValueSuffixKey, "alu",     // Test 3.
-    keys::kValueEqualsKey, "custom"   // Test 4.
+  const std::vector<std::string> kFailCondition = {
+      keys::kNamePrefixKey,   " Custom",  // Test 1.
+      keys::kNameContainsKey, " -",       // Test 2.
+      keys::kValueSuffixKey,  "alu",      // Test 3.
+      keys::kValueEqualsKey,  "custom"    // Test 4.
   };
-  const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
-  GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
+  const std::vector<size_t> kFailConditionSizes = {2u, 2u, 2u, 2u};
+  GetArrayAsVector(kFailCondition, kFailConditionSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
 
   // 1.c. -- This should fail (mixing name and value from different headers)
-  const std::string kMixingCondition[] = {
-    keys::kNameSuffixKey, "Header-B",
-    keys::kValueEqualsKey, "custom/value"
-  };
-  const size_t kMixingConditionSizes[] = {std::size(kMixingCondition)};
-  GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests);
+  const std::vector<std::string> kMixingCondition = {
+      keys::kNameSuffixKey, "Header-B", keys::kValueEqualsKey, "custom/value"};
+  const std::vector<size_t> kMixingConditionSizes = {
+      std::size(kMixingCondition)};
+  GetArrayAsVector(kMixingCondition, kMixingConditionSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
 
   // 1.d. -- Test handling multiple values for one header (both should pass).
-  const std::string kMoreValues1[] = {
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValueEqualsKey, "valueA"
-  };
-  const size_t kMoreValues1Sizes[] = {std::size(kMoreValues1)};
-  GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests);
+  const std::vector<std::string> kMoreValues1 = {
+      keys::kNameEqualsKey, "Custom-header-b", keys::kValueEqualsKey, "valueA"};
+  const std::vector<size_t> kMoreValues1Sizes = {std::size(kMoreValues1)};
+  GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
-  const std::string kMoreValues2[] = {
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValueEqualsKey, "valueB"
-  };
-  const size_t kMoreValues2Sizes[] = {std::size(kMoreValues2)};
-  GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests);
+  const std::vector<std::string> kMoreValues2 = {
+      keys::kNameEqualsKey, "Custom-header-b", keys::kValueEqualsKey, "valueB"};
+  const std::vector<size_t> kMoreValues2Sizes = {std::size(kMoreValues2)};
+  GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 1.e. -- This should fail as conjunction but pass as disjunction.
-  const std::string kConflict[] = {
-    keys::kNameSuffixKey, "Header",      // True for some header.
-    keys::kNameContainsKey, "Header-B"   // True for a different header.
+  const std::vector<std::string> kConflict = {
+      keys::kNameSuffixKey, "Header",     // True for some header.
+      keys::kNameContainsKey, "Header-B"  // True for a different header.
   };
   // First disjunction, no conflict.
-  const size_t kNoConflictSizes[] = { 2u, 2u };
-  GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests);
+  const std::vector<size_t> kNoConflictSizes = {2u, 2u};
+  GetArrayAsVector(kConflict, kNoConflictSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
   // Then conjunction, conflict.
-  const size_t kConflictSizes[] = {std::size(kConflict)};
-  GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests);
+  const std::vector<size_t> kConflictSizes = {std::size(kConflict)};
+  GetArrayAsVector(kConflict, kConflictSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
 
   // 1.f. -- This should pass, checking for correct treatment of ',' in values.
-  const std::string kComma[] = {
-    keys::kNameSuffixKey, "Header-C",
-    keys::kValueEqualsKey, "valueC, valueD"
-  };
-  const size_t kCommaSizes[] = {std::size(kComma)};
-  GetArrayAsVector(kComma, kCommaSizes, 1u, &tests);
+  const std::vector<std::string> kComma = {keys::kNameSuffixKey, "Header-C",
+                                           keys::kValueEqualsKey,
+                                           "valueC, valueD"};
+  const std::vector<size_t> kCommaSizes = {std::size(kComma)};
+  GetArrayAsVector(kComma, kCommaSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 1.g. -- This should pass, empty values are values as well.
-  const std::string kEmpty[] = {
-    keys::kNameEqualsKey, "custom-header-d",
-    keys::kValueEqualsKey, ""
-  };
-  const size_t kEmptySizes[] = {std::size(kEmpty)};
-  GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests);
+  const std::vector<std::string> kEmpty = {
+      keys::kNameEqualsKey, "custom-header-d", keys::kValueEqualsKey, ""};
+  const std::vector<size_t> kEmptySizes = {std::size(kEmpty)};
+  GetArrayAsVector(kEmpty, kEmptySizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 1.h. -- Values are case-sensitive, this should fail.
-  const std::string kLowercase[] = {
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValuePrefixKey, "valueb",  // valueb != valueB
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValueSuffixKey, "valueb",
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValueContainsKey, "valueb",
-    keys::kNameEqualsKey, "Custom-header-b",
-    keys::kValueEqualsKey, "valueb"
-  };
-  const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u };  // As disjunction.
-  GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests);
+  const std::vector<std::string> kLowercase = {
+      keys::kNameEqualsKey,    "Custom-header-b",
+      keys::kValuePrefixKey,   "valueb",  // valueb != valueB
+      keys::kNameEqualsKey,    "Custom-header-b",
+      keys::kValueSuffixKey,   "valueb",
+      keys::kNameEqualsKey,    "Custom-header-b",
+      keys::kValueContainsKey, "valueb",
+      keys::kNameEqualsKey,    "Custom-header-b",
+      keys::kValueEqualsKey,   "valueb"};
+  const std::vector<size_t> kLowercaseSizes = {4u, 4u, 4u,
+                                               4u};  // As disjunction.
+  GetArrayAsVector(kLowercase, kLowercaseSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_FALSE(result);
 
   // 1.i. -- Names are case-insensitive, this should pass.
-  const std::string kUppercase[] = {
-    keys::kNamePrefixKey, "CUSTOM-HEADER-B",
-    keys::kNameSuffixKey, "CUSTOM-HEADER-B",
-    keys::kNameEqualsKey, "CUSTOM-HEADER-B",
-    keys::kNameContainsKey, "CUSTOM-HEADER-B"
-  };
-  const size_t kUppercaseSizes[] = {std::size(kUppercase)};  // Conjunction.
-  GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests);
+  const std::vector<std::string> kUppercase = {
+      keys::kNamePrefixKey,   "CUSTOM-HEADER-B",    keys::kNameSuffixKey,
+      "CUSTOM-HEADER-B",      keys::kNameEqualsKey, "CUSTOM-HEADER-B",
+      keys::kNameContainsKey, "CUSTOM-HEADER-B"};
+  const std::vector<size_t> kUppercaseSizes = {
+      std::size(kUppercase)};  // Conjunction.
+  GetArrayAsVector(kUppercase, kUppercaseSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 2.a. -- This should pass as disjunction, because one of the tests passes.
-  const std::string kDisjunction[] = {
-    keys::kNamePrefixKey, "Non-existing",  // This one fails.
-    keys::kNameSuffixKey, "Non-existing",  // This one fails.
-    keys::kValueEqualsKey, "void",         // This one fails.
-    keys::kValueContainsKey, "alu"         // This passes.
+  const std::vector<std::string> kDisjunction = {
+      keys::kNamePrefixKey,    "Non-existing",  // This one fails.
+      keys::kNameSuffixKey,    "Non-existing",  // This one fails.
+      keys::kValueEqualsKey,   "void",          // This one fails.
+      keys::kValueContainsKey, "alu"            // This passes.
   };
-  const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u };
-  GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests);
+  const std::vector<size_t> kDisjunctionSizes = {2u, 2u, 2u, 2u};
+  GetArrayAsVector(kDisjunction, kDisjunctionSizes, &tests);
   MatchAndCheck(tests, keys::kResponseHeadersKey, stage, request_info, &result);
   EXPECT_TRUE(result);
 
   // 3.a. -- This should pass.
-  const std::string kNonExistent[] = {
-    keys::kNameEqualsKey, "Non-existing",
-    keys::kValueEqualsKey, "void"
-  };
-  const size_t kNonExistentSizes[] = {std::size(kNonExistent)};
-  GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests);
+  const std::vector<std::string> kNonExistent = {
+      keys::kNameEqualsKey, "Non-existing", keys::kValueEqualsKey, "void"};
+  const std::vector<size_t> kNonExistentSizes = {std::size(kNonExistent)};
+  GetArrayAsVector(kNonExistent, kNonExistentSizes, &tests);
   MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, request_info,
                 &result);
   EXPECT_TRUE(result);
 
   // 3.b. -- This should fail.
-  const std::string kExisting[] = {
-    keys::kNameEqualsKey, "custom-header-b",
-    keys::kValueEqualsKey, "valueB"
-  };
-  const size_t kExistingSize[] = {std::size(kExisting)};
-  GetArrayAsVector(kExisting, kExistingSize, 1u, &tests);
+  const std::vector<std::string> kExisting = {
+      keys::kNameEqualsKey, "custom-header-b", keys::kValueEqualsKey, "valueB"};
+  const std::vector<size_t> kExistingSize = {std::size(kExisting)};
+  GetArrayAsVector(kExisting, kExistingSize, &tests);
   MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage, request_info,
                 &result);
   EXPECT_FALSE(result);
@@ -578,9 +561,10 @@
   std::vector<std::vector<const std::string*>> tests;
   bool result;
   const RequestStage stage = ON_HEADERS_RECEIVED;
-  const std::string kCondition[] = {keys::kValueEqualsKey, "custom/value"};
-  const size_t kConditionSizes[] = {std::size(kCondition)};
-  GetArrayAsVector(kCondition, kConditionSizes, 1u, &tests);
+  const std::vector<std::string> kCondition = {keys::kValueEqualsKey,
+                                               "custom/value"};
+  const std::vector<size_t> kConditionSizes = {std::size(kCondition)};
+  GetArrayAsVector(kCondition, kConditionSizes, &tests);
 
   {
     // Default client does not hide the response header.
diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc
index 7185f8d3..be5563d 100644
--- a/extensions/browser/api/file_system/file_system_api.cc
+++ b/extensions/browser/api/file_system/file_system_api.cc
@@ -163,9 +163,9 @@
 
 // Key for the path of the directory of the file last chosen by the user in
 // response to a chrome.fileSystem.chooseEntry() call.
-const char kLastChooseEntryDirectory[] = "last_choose_file_directory";
+constexpr char kLastChooseEntryDirectory[] = "last_choose_file_directory";
 
-const int kGraylistedPaths[] = {
+constexpr int kGraylistedPaths[] = {
     base::DIR_HOME,
 #if BUILDFLAG(IS_WIN)
     base::DIR_PROGRAM_FILES,
@@ -551,8 +551,10 @@
     if (!base::PathService::Get(graylisted_path_key, &graylisted_path)) {
       continue;
     }
-    if (check_path != graylisted_path && !check_path.IsParent(graylisted_path))
+    if (check_path != graylisted_path &&
+        !check_path.IsParent(graylisted_path)) {
       continue;
+    }
 
     if (g_test_options && g_test_options->skip_directory_confirmation) {
       if (g_test_options->allow_directory_access) {
diff --git a/extensions/browser/api/hid/hid_apitest.cc b/extensions/browser/api/hid/hid_apitest.cc
index 0fed25ce..495277c 100644
--- a/extensions/browser/api/hid/hid_apitest.cc
+++ b/extensions/browser/api/hid/hid_apitest.cc
@@ -2,14 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stddef.h>
 #include <stdint.h>
 
+#include <iterator>
 #include <memory>
 
 #include "base/functional/bind.h"
@@ -178,12 +174,13 @@
                  std::string serial_number) {
     std::vector<uint8_t> report_descriptor;
     if (report_id) {
-      report_descriptor.insert(
-          report_descriptor.begin(), kReportDescriptorWithIDs,
-          kReportDescriptorWithIDs + sizeof(kReportDescriptorWithIDs));
+      report_descriptor.insert(report_descriptor.begin(),
+                               std::begin(kReportDescriptorWithIDs),
+                               std::end(kReportDescriptorWithIDs));
     } else {
-      report_descriptor.insert(report_descriptor.begin(), kReportDescriptor,
-                               kReportDescriptor + sizeof(kReportDescriptor));
+      report_descriptor.insert(report_descriptor.begin(),
+                               std::begin(kReportDescriptor),
+                               std::end(kReportDescriptor));
     }
 
     std::vector<device::mojom::HidCollectionInfoPtr> collections;
diff --git a/extensions/browser/api/messaging/message_service.cc b/extensions/browser/api/messaging/message_service.cc
index b335098..a67f09a 100644
--- a/extensions/browser/api/messaging/message_service.cc
+++ b/extensions/browser/api/messaging/message_service.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/messaging/message_service.h"
 
 #include <stdint.h>
@@ -165,7 +160,7 @@
                   extended_lifetime_urls.size());
 
   // Add default values.
-  for (const std::string& default_value : kDefaultSWExtendedLifetimeList) {
+  for (const char* default_value : kDefaultSWExtendedLifetimeList) {
     url::Origin origin = url::Origin::Create(GURL(default_value));
     origins.push_back(std::move(origin));
   }
diff --git a/extensions/browser/api/socket/socket.cc b/extensions/browser/api/socket/socket.cc
index fb0fb83..ed6a8c31 100644
--- a/extensions/browser/api/socket/socket.cc
+++ b/extensions/browser/api/socket/socket.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/socket/socket.h"
 
 #include "base/functional/bind.h"
@@ -59,9 +54,11 @@
   WriteRequest& request = write_queue_.front();
 
   DCHECK(request.byte_count >= request.bytes_written);
-  io_buffer_write_ = base::MakeRefCounted<net::WrappedIOBuffer>(
-      base::span(request.io_buffer->data(), request.byte_count)
-          .subspan(request.bytes_written));
+  auto span = request.io_buffer->span()
+                  .subspan(0u, request.byte_count)
+                  .subspan(request.bytes_written);
+  io_buffer_write_ =
+      base::MakeRefCounted<net::WrappedIOBuffer>(std::move(span));
   int result = WriteImpl(
       io_buffer_write_.get(), io_buffer_write_->size(),
       base::BindOnce(&Socket::OnWriteComplete, base::Unretained(this)));
diff --git a/extensions/browser/api/socket/socket_api.cc b/extensions/browser/api/socket/socket_api.cc
index 6ddf8ca..6069670 100644
--- a/extensions/browser/api/socket/socket_api.cc
+++ b/extensions/browser/api/socket/socket_api.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/socket/socket_api.h"
 
 #include <memory>
@@ -593,8 +588,7 @@
   result.Set(kResultCodeKey, bytes_read);
   base::span<const uint8_t> data_span;
   if (bytes_read > 0) {
-    data_span = base::as_bytes(
-        base::span(io_buffer->data(), static_cast<size_t>(bytes_read)));
+    data_span = io_buffer->span().subspan(0u, static_cast<size_t>(bytes_read));
   }
   result.Set(kDataKey, base::Value(data_span));
   Respond(WithArguments(std::move(result)));
@@ -674,8 +668,7 @@
   result.Set(kResultCodeKey, bytes_read);
   base::span<const uint8_t> data_span;
   if (bytes_read > 0) {
-    data_span = base::as_bytes(
-        base::span(io_buffer->data(), static_cast<size_t>(bytes_read)));
+    data_span = io_buffer->span().subspan(0u, static_cast<size_t>(bytes_read));
   }
   result.Set(kDataKey, base::Value(data_span));
   result.Set(kAddressKey, address);
diff --git a/extensions/browser/api/socket/socket_api.h b/extensions/browser/api/socket/socket_api.h
index 7fbc0ce..74cc9a4 100644
--- a/extensions/browser/api/socket/socket_api.h
+++ b/extensions/browser/api/socket/socket_api.h
@@ -345,7 +345,7 @@
 
   // SocketApiFunction:
   ResponseAction Work() override;
-  void OnCompleted(int result,
+  void OnCompleted(int bytes_read,
                    scoped_refptr<net::IOBuffer> io_buffer,
                    bool socket_destroying);
 };
diff --git a/extensions/browser/api/socket/udp_socket.cc b/extensions/browser/api/socket/udp_socket.cc
index b35e91e..47e72cf 100644
--- a/extensions/browser/api/socket/udp_socket.cc
+++ b/extensions/browser/api/socket/udp_socket.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/socket/udp_socket.h"
 
 #include <utility>
@@ -130,11 +125,11 @@
 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer,
                          int io_buffer_size,
                          net::CompletionOnceCallback callback) {
-  if (!IsConnected())
+  if (!IsConnected()) {
     return net::ERR_SOCKET_NOT_CONNECTED;
-  base::span<const uint8_t> data(
-      reinterpret_cast<const uint8_t*>(io_buffer->data()),
-      static_cast<size_t>(io_buffer_size));
+  }
+  base::span<const uint8_t> data =
+      io_buffer->span().subspan(0u, static_cast<size_t>(io_buffer_size));
   socket_->Send(
       data,
       net::MutableNetworkTrafficAnnotationTag(
@@ -180,9 +175,8 @@
     return;
   }
 
-  base::span<const uint8_t> data(
-      reinterpret_cast<const uint8_t*>(io_buffer->data()),
-      static_cast<size_t>(byte_count));
+  base::span<const uint8_t> data =
+      io_buffer->span().subspan(0u, static_cast<size_t>(byte_count));
   socket_->SendTo(
       address, data,
       net::MutableNetworkTrafficAnnotationTag(
diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc
index 2165daa..01c7242 100644
--- a/extensions/browser/api/usb/usb_api.cc
+++ b/extensions/browser/api/usb/usb_api.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/usb/usb_api.h"
 
 #include <algorithm>
@@ -1288,7 +1283,7 @@
   buffer.reserve(length);
 
   UsbTransferStatus status = UsbTransferStatus::COMPLETED;
-  const char* data_ptr = reinterpret_cast<const char*>(data.data());
+  size_t index = 0;
   for (const auto& packet : packets) {
     // Capture the error status of the first unsuccessful packet.
     if (status == UsbTransferStatus::COMPLETED &&
@@ -1296,9 +1291,10 @@
       status = packet->status;
     }
 
-    buffer.insert(buffer.end(), data_ptr,
-                  data_ptr + packet->transferred_length);
-    data_ptr += packet->length;
+    buffer.insert(buffer.end(), reinterpret_cast<const char*>(&data[index]),
+                  reinterpret_cast<const char*>(
+                      &data[index + packet->transferred_length]));
+    index += packet->transferred_length;
   }
 
   base::Value::Dict transfer_info;
diff --git a/extensions/browser/api/web_request/form_data_parser_unittest.cc b/extensions/browser/api/web_request/form_data_parser_unittest.cc
index 309bb49..86cb7ef 100644
--- a/extensions/browser/api/web_request/form_data_parser_unittest.cc
+++ b/extensions/browser/api/web_request/form_data_parser_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/api/web_request/form_data_parser.h"
 
 #include <stddef.h>
@@ -181,26 +176,26 @@
   const std::string kMultipart =
       std::string("multipart/form-data; boundary=") + kBoundary;
   // Expected output.
-  const char* kPairs[] = {"text",
-                          "test\rtext\nwith non-CRLF line breaks",
-                          "file",
-                          "test",
-                          "password",
-                          "test password",
-                          "radio",
-                          "Yes",
-                          "check",
-                          "option A",
-                          "check",
-                          "option B",
-                          "txtarea",
-                          "Some text.\r\nOther.\r\n",
-                          "select",
-                          "one",
-                          "binary",
-                          ("\u0420\u043e\u0434\u0436\u0435\u0440 "
-                           "\u0416\u0435\u043b\u044f\u0437\u043d\u044b")};
-  const std::vector<std::string> kExpected(kPairs, kPairs + std::size(kPairs));
+  const std::vector<std::string> kExpected = {
+      "text",
+      "test\rtext\nwith non-CRLF line breaks",
+      "file",
+      "test",
+      "password",
+      "test password",
+      "radio",
+      "Yes",
+      "check",
+      "option A",
+      "check",
+      "option B",
+      "txtarea",
+      "Some text.\r\nOther.\r\n",
+      "select",
+      "one",
+      "binary",
+      "\u0420\u043e\u0434\u0436\u0435\u0440 "
+      "\u0416\u0435\u043b\u044f\u0437\u043d\u044b"};
 
   std::vector<const std::string_view*> input;
   std::vector<std::string> output;
diff --git a/extensions/browser/computed_hashes.cc b/extensions/browser/computed_hashes.cc
index a4a05d0..da429bba 100644
--- a/extensions/browser/computed_hashes.cc
+++ b/extensions/browser/computed_hashes.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/computed_hashes.h"
 
 #include <memory>
@@ -29,12 +24,12 @@
 namespace extensions {
 
 namespace computed_hashes {
-const char kBlockHashesKey[] = "block_hashes";
-const char kBlockSizeKey[] = "block_size";
-const char kFileHashesKey[] = "file_hashes";
-const char kPathKey[] = "path";
-const char kVersionKey[] = "version";
-const int kVersion = 2;
+constexpr char kBlockHashesKey[] = "block_hashes";
+constexpr char kBlockSizeKey[] = "block_size";
+constexpr char kFileHashesKey[] = "file_hashes";
+constexpr char kPathKey[] = "path";
+constexpr char kVersionKey[] = "version";
+constexpr int kVersion = 2;
 }  // namespace computed_hashes
 
 namespace {
@@ -301,7 +296,7 @@
   // Even when the contents is empty, we want to output at least one hash
   // block (the hash of the empty string).
   do {
-    const char* block_start = contents.data() + offset;
+    const char* block_start = &contents[offset];
     DCHECK(offset <= contents.size());
     size_t bytes_to_read = std::min(contents.size() - offset, block_size);
     std::unique_ptr<crypto::SecureHash> hash(
diff --git a/extensions/browser/extension_creator_filter_unittest.cc b/extensions/browser/extension_creator_filter_unittest.cc
index d08df98..15e7333 100644
--- a/extensions/browser/extension_creator_filter_unittest.cc
+++ b/extensions/browser/extension_creator_filter_unittest.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/extension_creator_filter.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <memory>
 
 #include "base/files/file_util.h"
@@ -72,7 +68,7 @@
 };
 
 TEST_F(ExtensionCreatorFilterTest, NormalCases) {
-  const struct UnaryBooleanTestData cases[] = {
+  const auto cases = std::to_array<UnaryBooleanTestData>({
       {FILE_PATH_LITERAL("foo"), true},
       {FILE_PATH_LITERAL(".foo"), false},
       {FILE_PATH_LITERAL("~foo"), true},
@@ -85,7 +81,7 @@
       {FILE_PATH_LITERAL(".DS_Store"), false},
       {FILE_PATH_LITERAL("desktop.ini"), false},
       {FILE_PATH_LITERAL("Thumbs.db"), false},
-  };
+  });
 
   for (size_t i = 0; i < std::size(cases); ++i) {
     base::FilePath input(cases[i].input);
@@ -98,13 +94,13 @@
 }
 
 TEST_F(ExtensionCreatorFilterTest, MetadataFolderExcluded) {
-  const struct UnaryBooleanTestData cases[] = {
+  const auto cases = std::to_array<UnaryBooleanTestData>({
       {FILE_PATH_LITERAL("_metadata/foo"), false},
       {FILE_PATH_LITERAL("_metadata/abc/foo"), false},
       {FILE_PATH_LITERAL("_metadata/abc/xyz/foo"), false},
       {FILE_PATH_LITERAL("abc/_metadata/xyz"), true},
       {FILE_PATH_LITERAL("xyz/_metadata"), true},
-  };
+  });
 
   // Create and test the filepaths.
   for (size_t i = 0; i < std::size(cases); ++i) {
@@ -117,14 +113,14 @@
   }
 
   // Also test directories.
-  const struct UnaryBooleanTestData directory_cases[] = {
+  const auto directory_cases = std::to_array<UnaryBooleanTestData>({
       {FILE_PATH_LITERAL("_metadata"), false},
       {FILE_PATH_LITERAL("_metadata/abc"), false},
       {FILE_PATH_LITERAL("_metadata/abc/xyz"), false},
       {FILE_PATH_LITERAL("abc"), true},
       {FILE_PATH_LITERAL("abc/_metadata"), true},
       {FILE_PATH_LITERAL("xyz"), true},
-  };
+  });
   for (size_t i = 0; i < std::size(directory_cases); ++i) {
     base::FilePath directory = extension_dir_.Append(directory_cases[i].input);
     bool observed = filter_->ShouldPackageFile(directory);
@@ -143,13 +139,13 @@
 // Ignore the files in special directories, including ".git", ".svn",
 // "__MACOSX".
 TEST_F(ExtensionCreatorFilterTest, IgnoreFilesInSpecialDir) {
-  const struct StringStringWithBooleanTestData cases[] = {
+  const auto cases = std::to_array<StringStringWithBooleanTestData>({
       {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL(".git"), false},
       {FILE_PATH_LITERAL("goo"), FILE_PATH_LITERAL(".svn"), false},
       {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("__MACOSX"), false},
       {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("foo"), true},
       {FILE_PATH_LITERAL("index.js"), FILE_PATH_LITERAL("scripts"), true},
-  };
+  });
 
   for (size_t i = 0; i < std::size(cases); ++i) {
     base::FilePath test_file(
@@ -168,14 +164,14 @@
 };
 
 TEST_F(ExtensionCreatorFilterTest, WindowsHiddenFiles) {
-  const struct StringBooleanWithBooleanTestData cases[] = {
+  const auto cases = std::to_array<StringBooleanWithBooleanTestData>({
       {FILE_PATH_LITERAL("a-normal-file"), false, true},
       {FILE_PATH_LITERAL(".a-dot-file"), false, false},
       {FILE_PATH_LITERAL(".a-dot-file-that-we-have-set-to-hidden"), true,
        false},
       {FILE_PATH_LITERAL("a-file-that-we-have-set-to-hidden"), true, false},
       {FILE_PATH_LITERAL("a-file-that-we-have-not-set-to-hidden"), false, true},
-  };
+  });
 
   for (size_t i = 0; i < std::size(cases); ++i) {
     base::FilePath input(cases[i].input_char);
diff --git a/extensions/browser/extension_function_crash_keys.cc b/extensions/browser/extension_function_crash_keys.cc
index 78f73bfd..fe173f0 100644
--- a/extensions/browser/extension_function_crash_keys.cc
+++ b/extensions/browser/extension_function_crash_keys.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/extension_function_crash_keys.h"
 
+#include <array>
 #include <utility>
 #include <vector>
 
@@ -60,19 +56,21 @@
   std::sort(calls.begin(), calls.end(), std::greater<>());
   // Set up crash keys.
   using ArrayItemKey = crash_reporter::CrashKeyString<64>;
-  static ArrayItemKey crash_keys[] = {
-      {"extension-function-caller-1", ArrayItemKey::Tag::kArray},
-      {"extension-function-caller-2", ArrayItemKey::Tag::kArray},
-      {"extension-function-caller-3", ArrayItemKey::Tag::kArray},
+  static constexpr int kMaxCrashKeys = 3;
+  static std::array<ArrayItemKey, kMaxCrashKeys> crash_keys = {
+      ArrayItemKey{"extension-function-caller-1", ArrayItemKey::Tag::kArray},
+      ArrayItemKey{"extension-function-caller-2", ArrayItemKey::Tag::kArray},
+      ArrayItemKey{"extension-function-caller-3", ArrayItemKey::Tag::kArray},
   };
   // Store up to 3 crash keys with extension IDs.
   int index = 0;
-  for (auto it = calls.begin(); it != calls.end() && index < 3; ++it, ++index) {
+  for (auto it = calls.begin(); it != calls.end() && index < kMaxCrashKeys;
+       ++it, ++index) {
     const ExtensionId* extension_id = it->second;
     crash_keys[index].Set(*extension_id);
   }
   // Clear the remaining crash keys.
-  for (; index < 3; ++index) {
+  for (; index < kMaxCrashKeys; ++index) {
     crash_keys[index].Clear();
   }
 }
diff --git a/extensions/browser/extension_pref_value_map_unittest.cc b/extensions/browser/extension_pref_value_map_unittest.cc
index 76c5fd33..ac4d80c 100644
--- a/extensions/browser/extension_pref_value_map_unittest.cc
+++ b/extensions/browser/extension_pref_value_map_unittest.cc
@@ -2,20 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/extension_pref_value_map.h"
 
 #include <stdint.h>
 
+#include <array>
 #include <memory>
 
 #include "base/memory/ref_counted.h"
@@ -383,16 +374,9 @@
 
 TEST_P(ExtensionPrefValueMapTestIncognitoTests, OverrideIncognito) {
   OverrideIncognitoTestCase test = GetParam();
-  const char* strings[] = {
+  static constexpr std::array strings = {
       "",  // undefined
-      "val1",
-      "val2",
-      "val3",
-      "val4",
-      "val5",
-      "val6",
-      "val7",
-      "val8",
+      "val1", "val2", "val3", "val4", "val5", "val6", "val7", "val8",
   };
 
   const bool kEnabled = true;
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc
index 8601946..38f9059 100644
--- a/extensions/browser/image_loader_unittest.cc
+++ b/extensions/browser/image_loader_unittest.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/browser/image_loader.h"
 
 #include <stddef.h>
 
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/json/json_file_value_serializer.h"
@@ -190,14 +191,16 @@
   ASSERT_TRUE(extension.get() != nullptr);
 
   std::vector<ImageLoader::ImageRepresentation> info_list;
-  int sizes[] = {extension_misc::EXTENSION_ICON_BITTY,
-                 extension_misc::EXTENSION_ICON_SMALLISH, };
-  for (size_t i = 0; i < std::size(sizes); ++i) {
+  static constexpr int sizes[] = {
+      extension_misc::EXTENSION_ICON_BITTY,
+      extension_misc::EXTENSION_ICON_SMALLISH,
+  };
+  for (const auto& entry : sizes) {
     ExtensionResource resource = IconsInfo::GetIconResource(
-        extension.get(), sizes[i], ExtensionIconSet::Match::kExactly);
+        extension.get(), entry, ExtensionIconSet::Match::kExactly);
     info_list.push_back(ImageLoader::ImageRepresentation(
         resource, ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
-        gfx::Size(sizes[i], sizes[i]), 1.f));
+        gfx::Size(entry, entry), 1.f));
   }
 
   ImageLoader loader;
@@ -233,14 +236,14 @@
   ASSERT_TRUE(extension.get() != nullptr);
 
   std::vector<ImageLoader::ImageRepresentation> info_list;
-  int sizes[] = {extension_misc::EXTENSION_ICON_BITTY,
-                 extension_misc::EXTENSION_ICON_SMALLISH, };
-  for (size_t i = 0; i < std::size(sizes); ++i) {
+  static constexpr int sizes[] = {extension_misc::EXTENSION_ICON_BITTY,
+                                  extension_misc::EXTENSION_ICON_SMALLISH};
+  for (int size : sizes) {
     ExtensionResource resource = IconsInfo::GetIconResource(
-        extension.get(), sizes[i], ExtensionIconSet::Match::kExactly);
+        extension.get(), size, ExtensionIconSet::Match::kExactly);
     info_list.push_back(ImageLoader::ImageRepresentation(
         resource, ImageLoader::ImageRepresentation::NEVER_RESIZE,
-        gfx::Size(sizes[i], sizes[i]), 1.f));
+        gfx::Size(size, size), 1.f));
   }
 
   // Add a second icon of 200P which should get grouped with the smaller icon's
@@ -269,9 +272,9 @@
   EXPECT_EQ(1, image_loaded_count());
 
   // Check that all images were loaded.
-  for (size_t i = 0; i < std::size(sizes); ++i) {
-    const gfx::Image* image = image_family_.GetBest(sizes[i], sizes[i]);
-    EXPECT_EQ(sizes[i], image->Width());
+  for (int size : sizes) {
+    const gfx::Image* image = image_family_.GetBest(size, size);
+    EXPECT_EQ(size, image->Width());
   }
 
   // Check the smaller image has 2 representations of different scale factors.
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc
index a6c5664..50bcc7c2 100644
--- a/extensions/browser/user_script_loader.cc
+++ b/extensions/browser/user_script_loader.cc
@@ -72,9 +72,12 @@
     return false;
   }
 
-  std::string temp(line.substr(index + prefix.length()));
-  if (temp.empty() || !base::IsAsciiWhitespace(temp[0]))
+  std::string_view temp = line.substr(index + prefix.length(),
+                                      line.length() - index - prefix.length());
+
+  if (temp.empty() || !base::IsAsciiWhitespace(temp[0])) {
     return false;
+  }
 
   base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
   return true;
@@ -106,20 +109,21 @@
   size_t line_end = line_start;
   bool in_metadata = false;
 
-  static const std::string_view kUserScriptBegin("// ==UserScript==");
-  static const std::string_view kUserScriptEng("// ==/UserScript==");
-  static const std::string_view kNamespaceDeclaration("// @namespace");
-  static const std::string_view kNameDeclaration("// @name");
-  static const std::string_view kVersionDeclaration("// @version");
-  static const std::string_view kDescriptionDeclaration("// @description");
-  static const std::string_view kIncludeDeclaration("// @include");
-  static const std::string_view kExcludeDeclaration("// @exclude");
-  static const std::string_view kMatchDeclaration("// @match");
-  static const std::string_view kExcludeMatchDeclaration("// @exclude_match");
-  static const std::string_view kRunAtDeclaration("// @run-at");
-  static const std::string_view kRunAtDocumentStartValue("document-start");
-  static const std::string_view kRunAtDocumentEndValue("document-end");
-  static const std::string_view kRunAtDocumentIdleValue("document-idle");
+  static constexpr std::string_view kUserScriptBegin("// ==UserScript==");
+  static constexpr std::string_view kUserScriptEng("// ==/UserScript==");
+  static constexpr std::string_view kNamespaceDeclaration("// @namespace");
+  static constexpr std::string_view kNameDeclaration("// @name");
+  static constexpr std::string_view kVersionDeclaration("// @version");
+  static constexpr std::string_view kDescriptionDeclaration("// @description");
+  static constexpr std::string_view kIncludeDeclaration("// @include");
+  static constexpr std::string_view kExcludeDeclaration("// @exclude");
+  static constexpr std::string_view kMatchDeclaration("// @match");
+  static constexpr std::string_view kExcludeMatchDeclaration(
+      "// @exclude_match");
+  static constexpr std::string_view kRunAtDeclaration("// @run-at");
+  static constexpr std::string_view kRunAtDocumentStartValue("document-start");
+  static constexpr std::string_view kRunAtDocumentEndValue("document-end");
+  static constexpr std::string_view kRunAtDocumentIdleValue("document-idle");
 
   while (line_start < script_text.length()) {
     line_end = script_text.find('\n', line_start);
diff --git a/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc b/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
index e650f817..5da91fbf 100644
--- a/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
+++ b/extensions/common/api/sockets/sockets_manifest_permission_unittest.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/api/sockets/sockets_manifest_permission.h"
 
+#include <iterator>
 #include <set>
 #include <tuple>
 
@@ -122,7 +118,7 @@
                                             const CheckFormatEntry& op1) {
   CheckFormatEntry entries[] = {op1};
   return CheckFormat(
-      std::multiset<CheckFormatEntry>(entries, entries + std::size(entries)),
+      std::multiset<CheckFormatEntry>(std::begin(entries), std::end(entries)),
       json);
 }
 
@@ -131,7 +127,7 @@
                                             const CheckFormatEntry& op2) {
   CheckFormatEntry entries[] = {op1, op2};
   return CheckFormat(
-      std::multiset<CheckFormatEntry>(entries, entries + std::size(entries)),
+      std::multiset<CheckFormatEntry>(std::begin(entries), std::end(entries)),
       json);
 }
 
@@ -147,7 +143,7 @@
                                             const CheckFormatEntry& op9) {
   CheckFormatEntry entries[] = {op1, op2, op3, op4, op5, op6, op7, op8, op9};
   return CheckFormat(
-      std::multiset<CheckFormatEntry>(entries, entries + std::size(entries)),
+      std::multiset<CheckFormatEntry>(std::begin(entries), std::end(entries)),
       json);
 }
 
diff --git a/extensions/common/command_unittest.cc b/extensions/common/command_unittest.cc
index c8f9d81d..4cde92e8 100644
--- a/extensions/common/command_unittest.cc
+++ b/extensions/common/command_unittest.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/command.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <memory>
 #include <utility>
 
@@ -137,7 +133,7 @@
   const ui::Accelerator stop =
       ui::Accelerator(ui::VKEY_MEDIA_STOP, ui::EF_NONE);
 
-  ConstCommandsTestData kTests[] = {
+  static const auto kTests = std::to_array<ConstCommandsTestData>({
       // Negative test (one or more missing required fields). We don't need to
       // test |command_name| being blank as it is used as a key in the manifest,
       // so it can't be blank (and we CHECK() when it is). A blank shortcut is
@@ -195,16 +191,16 @@
       {false, none, "_execute_browser_action", "MediaNextTrack", ""},
       {false, none, "_execute_page_action", "MediaPrevTrack", ""},
       {false, none, "command", "Ctrl+Shift+MediaPrevTrack", "description"},
-  };
+  });
   std::vector<std::string> all_platforms;
   all_platforms.push_back("default");
   all_platforms.push_back("chromeos");
   all_platforms.push_back("linux");
   all_platforms.push_back("mac");
   all_platforms.push_back("windows");
-
-  for (size_t i = 0; i < std::size(kTests); ++i)
+  for (size_t i = 0; i < std::size(kTests); ++i) {
     CheckParse(kTests[i], i, false, all_platforms);
+  }
 }
 
 // TODO(https://crbug.com/356905053): Add/adjust command key support on
@@ -312,29 +308,31 @@
   ui::Accelerator search_shift_z(ui::VKEY_Z,
                                  ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
 
-  ConstCommandsTestData kChromeOsTests[] = {
+  const auto kChromeOsTests = std::to_array<ConstCommandsTestData>({
       {true, search_shift_z, "command", "Search+Shift+Z", "description"},
       {true, search_a, "command", "Search+A", "description"},
       // Command is not valid on Chrome OS.
       {false, search_shift_z, "command", "Command+Shift+Z", "description"},
-  };
+  });
 
   std::vector<std::string> chromeos;
   chromeos.push_back("chromeos");
-  for (size_t i = 0; i < std::size(kChromeOsTests); ++i)
+  for (size_t i = 0; i < std::size(kChromeOsTests); ++i) {
     CheckParse(kChromeOsTests[i], i, true, chromeos);
+  }
 
-  ConstCommandsTestData kNonChromeOsSearchTests[] = {
+  const auto kNonChromeOsSearchTests = std::to_array<ConstCommandsTestData>({
       {false, search_shift_z, "command", "Search+Shift+Z", "description"},
-  };
+  });
   std::vector<std::string> non_chromeos;
   non_chromeos.push_back("default");
   non_chromeos.push_back("windows");
   non_chromeos.push_back("mac");
   non_chromeos.push_back("linux");
 
-  for (size_t i = 0; i < std::size(kNonChromeOsSearchTests); ++i)
+  for (size_t i = 0; i < kNonChromeOsSearchTests.size(); ++i) {
     CheckParse(kNonChromeOsSearchTests[i], i, true, non_chromeos);
+  }
 }
 
 }  // namespace extensions
diff --git a/extensions/common/features/simple_feature_unittest.cc b/extensions/common/features/simple_feature_unittest.cc
index acc76fcd..fc0c236d 100644
--- a/extensions/common/features/simple_feature_unittest.cc
+++ b/extensions/common/features/simple_feature_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/features/simple_feature.h"
 
 #include <stddef.h>
@@ -127,8 +122,7 @@
        Feature::IS_AVAILABLE}};
 
   SimpleFeature feature;
-  for (size_t i = 0; i < std::size(tests); ++i) {
-    const IsAvailableTestData& test = tests[i];
+  for (const auto& test : tests) {
     EXPECT_EQ(test.expected_result,
               feature
                   .IsAvailableToManifest(HashedExtensionId(test.extension_id),
@@ -540,30 +534,30 @@
        mojom::FeatureSessionType::kAutolaunchedKiosk,
        {mojom::FeatureSessionType::kKiosk}}};
 
-  for (size_t i = 0; i < std::size(kTestData); ++i) {
+  for (const auto& entry : kTestData) {
     std::unique_ptr<base::AutoReset<mojom::FeatureSessionType>> current_session(
-        ScopedCurrentFeatureSessionType(kTestData[i].current_session_type));
+        ScopedCurrentFeatureSessionType(entry.current_session_type));
 
     SimpleFeature feature;
-    feature.set_session_types(kTestData[i].feature_session_types);
+    feature.set_session_types(entry.feature_session_types);
 
-    EXPECT_EQ(kTestData[i].expected_availability,
+    EXPECT_EQ(entry.expected_availability,
               feature
                   .IsAvailableToContext(
                       extension.get(), mojom::ContextType::kPrivilegedExtension,
                       Feature::CHROMEOS_PLATFORM, kUnspecifiedContextId,
                       TestContextData())
                   .result())
-        << "Failed test '" << kTestData[i].desc << "'.";
+        << "Failed test '" << entry.desc << "'.";
 
-    EXPECT_EQ(kTestData[i].expected_availability,
+    EXPECT_EQ(entry.expected_availability,
               feature
                   .IsAvailableToManifest(
                       extension->hashed_id(), Manifest::TYPE_UNKNOWN,
                       ManifestLocation::kInvalidLocation, -1,
                       Feature::CHROMEOS_PLATFORM, kUnspecifiedContextId)
                   .result())
-        << "Failed test '" << kTestData[i].desc << "'.";
+        << "Failed test '" << entry.desc << "'.";
   }
 }
 
diff --git a/extensions/common/manifest_handlers/externally_connectable_unittest.cc b/extensions/common/manifest_handlers/externally_connectable_unittest.cc
index 0c27a85..d80e633 100644
--- a/extensions/common/manifest_handlers/externally_connectable_unittest.cc
+++ b/extensions/common/manifest_handlers/externally_connectable_unittest.cc
@@ -2,16 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/manifest_handlers/externally_connectable.h"
 
 #include <stddef.h>
 
 #include <algorithm>
+#include <iterator>
 
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest_constants.h"
@@ -198,28 +194,31 @@
 
 TEST_F(ExternallyConnectableTest, IdCanConnect) {
   // Not in order to test that ExternallyConnectableInfo sorts it.
-  ExtensionId matches_ids_array[] = {"g", "h", "c", "i", "a", "z", "b"};
-  std::vector<ExtensionId> matches_ids(
-      matches_ids_array, matches_ids_array + std::size(matches_ids_array));
+  const std::vector<ExtensionId> matches_ids = {"g", "h", "c", "i",
+                                                "a", "z", "b"};
 
-  ExtensionId nomatches_ids_array[] = {"2", "3", "1"};
+  const std::vector<ExtensionId> nomatches_ids = {"2", "3", "1"};
 
   // all_ids = false.
   {
     ExternallyConnectableInfo info(URLPatternSet(), matches_ids, false, false);
-    for (size_t i = 0; i < matches_ids.size(); ++i)
-      EXPECT_TRUE(info.IdCanConnect(matches_ids[i]));
-    for (size_t i = 0; i < std::size(nomatches_ids_array); ++i)
-      EXPECT_FALSE(info.IdCanConnect(nomatches_ids_array[i]));
+    for (const auto& entry : matches_ids) {
+      EXPECT_TRUE(info.IdCanConnect(entry));
+    }
+    for (const auto& entry : nomatches_ids) {
+      EXPECT_FALSE(info.IdCanConnect(entry));
+    }
   }
 
   // all_ids = true.
   {
     ExternallyConnectableInfo info(URLPatternSet(), matches_ids, true, false);
-    for (size_t i = 0; i < matches_ids.size(); ++i)
-      EXPECT_TRUE(info.IdCanConnect(matches_ids[i]));
-    for (size_t i = 0; i < std::size(nomatches_ids_array); ++i)
-      EXPECT_TRUE(info.IdCanConnect(nomatches_ids_array[i]));
+    for (const auto& entry : matches_ids) {
+      EXPECT_TRUE(info.IdCanConnect(entry));
+    }
+    for (const auto& entry : nomatches_ids) {
+      EXPECT_TRUE(info.IdCanConnect(entry));
+    }
   }
 }
 
diff --git a/extensions/common/message_bundle_unittest.cc b/extensions/common/message_bundle_unittest.cc
index 1061f5e..63c0992 100644
--- a/extensions/common/message_bundle_unittest.cc
+++ b/extensions/common/message_bundle_unittest.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/message_bundle.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -335,46 +331,45 @@
   const char* kPlaceholderBegin = MessageBundle::kPlaceholderBegin;
   const char* kPlaceholderEnd = MessageBundle::kPlaceholderEnd;
 
-  static ReplaceVariables test_cases[] = {
-    // Message replacement.
-    { "This is __MSG_siMPle__ message", "This is simple message",
-      "", kMessageBegin, kMessageEnd, true },
-    { "This is __MSG_", "This is __MSG_",
-      "", kMessageBegin, kMessageEnd, true },
-    { "This is __MSG__simple__ message", "This is __MSG__simple__ message",
-      "Variable __MSG__simple__ used but not defined.",
-      kMessageBegin, kMessageEnd, false },
-    { "__MSG_LoNg__", "A pretty long replacement",
-      "", kMessageBegin, kMessageEnd, true },
-    { "A __MSG_SimpLE__MSG_ a", "A simpleMSG_ a",
-      "", kMessageBegin, kMessageEnd, true },
-    { "A __MSG_simple__MSG_long__", "A simpleMSG_long__",
-      "", kMessageBegin, kMessageEnd, true },
-    { "A __MSG_simple____MSG_long__", "A simpleA pretty long replacement",
-      "", kMessageBegin, kMessageEnd, true },
-    { "__MSG_d1g1ts_are_ok__", "I are d1g1t",
-      "", kMessageBegin, kMessageEnd, true },
-    // Placeholder replacement.
-    { "This is $sImpLe$ message", "This is simple message",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "This is $", "This is $",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "This is $$sIMPle$ message", "This is $simple message",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "$LONG_V$", "A pretty long replacement",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "A $simple$$ a", "A simple$ a",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "A $simple$long_v$", "A simplelong_v$",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "A $simple$$long_v$", "A simpleA pretty long replacement",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "This is $bad name$", "This is $bad name$",
-       "", kPlaceholderBegin, kPlaceholderEnd, true },
-    { "This is $missing$", "This is $missing$",
-       "Variable $missing$ used but not defined.",
-       kPlaceholderBegin, kPlaceholderEnd, false },
-  };
+  static auto test_cases = std::to_array<ReplaceVariables>({
+      // Message replacement.
+      {"This is __MSG_siMPle__ message", "This is simple message", "",
+       kMessageBegin, kMessageEnd, true},
+      {"This is __MSG_", "This is __MSG_", "", kMessageBegin, kMessageEnd,
+       true},
+      {"This is __MSG__simple__ message", "This is __MSG__simple__ message",
+       "Variable __MSG__simple__ used but not defined.", kMessageBegin,
+       kMessageEnd, false},
+      {"__MSG_LoNg__", "A pretty long replacement", "", kMessageBegin,
+       kMessageEnd, true},
+      {"A __MSG_SimpLE__MSG_ a", "A simpleMSG_ a", "", kMessageBegin,
+       kMessageEnd, true},
+      {"A __MSG_simple__MSG_long__", "A simpleMSG_long__", "", kMessageBegin,
+       kMessageEnd, true},
+      {"A __MSG_simple____MSG_long__", "A simpleA pretty long replacement", "",
+       kMessageBegin, kMessageEnd, true},
+      {"__MSG_d1g1ts_are_ok__", "I are d1g1t", "", kMessageBegin, kMessageEnd,
+       true},
+      // Placeholder replacement.
+      {"This is $sImpLe$ message", "This is simple message", "",
+       kPlaceholderBegin, kPlaceholderEnd, true},
+      {"This is $", "This is $", "", kPlaceholderBegin, kPlaceholderEnd, true},
+      {"This is $$sIMPle$ message", "This is $simple message", "",
+       kPlaceholderBegin, kPlaceholderEnd, true},
+      {"$LONG_V$", "A pretty long replacement", "", kPlaceholderBegin,
+       kPlaceholderEnd, true},
+      {"A $simple$$ a", "A simple$ a", "", kPlaceholderBegin, kPlaceholderEnd,
+       true},
+      {"A $simple$long_v$", "A simplelong_v$", "", kPlaceholderBegin,
+       kPlaceholderEnd, true},
+      {"A $simple$$long_v$", "A simpleA pretty long replacement", "",
+       kPlaceholderBegin, kPlaceholderEnd, true},
+      {"This is $bad name$", "This is $bad name$", "", kPlaceholderBegin,
+       kPlaceholderEnd, true},
+      {"This is $missing$", "This is $missing$",
+       "Variable $missing$ used but not defined.", kPlaceholderBegin,
+       kPlaceholderEnd, false},
+  });
 
   MessageBundle::SubstitutionMap messages;
   messages.insert(std::make_pair("simple", "simple"));
@@ -383,16 +378,13 @@
   messages.insert(std::make_pair("bad name", "Doesn't matter"));
   messages.insert(std::make_pair("d1g1ts_are_ok", "I are d1g1t"));
 
-  for (size_t i = 0; i < std::size(test_cases); ++i) {
-    std::string text = test_cases[i].original;
+  for (const auto& entry : test_cases) {
+    std::string text = entry.original;
     std::string error;
-    EXPECT_EQ(test_cases[i].pass,
-              MessageBundle::ReplaceVariables(messages,
-                                              test_cases[i].begin_delimiter,
-                                              test_cases[i].end_delimiter,
-                                              &text,
-                                              &error));
-    EXPECT_EQ(test_cases[i].result, text);
+    EXPECT_EQ(entry.pass, MessageBundle::ReplaceVariables(
+                              messages, entry.begin_delimiter,
+                              entry.end_delimiter, &text, &error));
+    EXPECT_EQ(entry.result, text);
   }
 }
 
diff --git a/extensions/common/url_pattern.cc b/extensions/common/url_pattern.cc
index 1b233c1..457d226 100644
--- a/extensions/common/url_pattern.cc
+++ b/extensions/common/url_pattern.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/url_pattern.h"
 
 #include <stddef.h>
 
+#include <array>
 #include <ostream>
 #include <string_view>
 
@@ -33,7 +29,7 @@
 
 // TODO(aa): What about more obscure schemes like javascript: ?
 // Note: keep this array in sync with kValidSchemeMasks.
-const char* const kValidSchemes[] = {
+constexpr std::array kValidSchemes = {
     url::kHttpScheme,          url::kHttpsScheme,
     url::kFileScheme,          url::kFtpScheme,
     content::kChromeUIScheme,  extensions::kExtensionScheme,
@@ -42,7 +38,7 @@
     url::kUuidInPackageScheme,
 };
 
-const int kValidSchemeMasks[] = {
+constexpr std::array kValidSchemeMasks = {
     URLPattern::SCHEME_HTTP,
     URLPattern::SCHEME_HTTPS,
     URLPattern::SCHEME_FILE,
@@ -70,16 +66,16 @@
 const char kParseErrorInvalidHost[] = "Invalid host.";
 
 // Message explaining each URLPattern::ParseResult.
-const char* const kParseResultMessages[] = {
-  kParseSuccess,
-  kParseErrorMissingSchemeSeparator,
-  kParseErrorInvalidScheme,
-  kParseErrorWrongSchemeType,
-  kParseErrorEmptyHost,
-  kParseErrorInvalidHostWildcard,
-  kParseErrorEmptyPath,
-  kParseErrorInvalidPort,
-  kParseErrorInvalidHost,
+constexpr std::array kParseResultMessages = {
+    kParseSuccess,
+    kParseErrorMissingSchemeSeparator,
+    kParseErrorInvalidScheme,
+    kParseErrorWrongSchemeType,
+    kParseErrorEmptyHost,
+    kParseErrorInvalidHostWildcard,
+    kParseErrorEmptyPath,
+    kParseErrorInvalidPort,
+    kParseErrorInvalidHost,
 };
 
 static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc
index f084cd0..1e367bc8 100644
--- a/extensions/common/url_pattern_unittest.cc
+++ b/extensions/common/url_pattern_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/common/url_pattern.h"
 
 #include <stddef.h>
@@ -24,7 +19,7 @@
 
 // See url_pattern.h for examples of valid and invalid patterns.
 
-static const int kAllSchemes =
+static constexpr int kAllSchemes =
     URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
     URLPattern::SCHEME_FILE | URLPattern::SCHEME_FTP |
     URLPattern::SCHEME_CHROMEUI | URLPattern::SCHEME_EXTENSION |
@@ -33,7 +28,7 @@
     URLPattern::SCHEME_UUID_IN_PACKAGE;
 
 TEST(ExtensionURLPatternTest, ParseInvalid) {
-  const struct {
+  static constexpr struct {
     const char* pattern;
     URLPattern::ParseResult expected_result;
   } kInvalidPatterns[] = {
@@ -52,11 +47,10 @@
       {"http://bar", URLPattern::ParseResult::kEmptyPath},
       {"http://foo.*/bar", URLPattern::ParseResult::kInvalidHostWildcard}};
 
-  for (size_t i = 0; i < std::size(kInvalidPatterns); ++i) {
+  for (const auto& entry : kInvalidPatterns) {
     URLPattern pattern(URLPattern::SCHEME_ALL);
-    EXPECT_EQ(kInvalidPatterns[i].expected_result,
-              pattern.Parse(kInvalidPatterns[i].pattern))
-        << kInvalidPatterns[i].pattern;
+    EXPECT_EQ(entry.expected_result, pattern.Parse(entry.pattern))
+        << entry.pattern;
   }
 
   {
@@ -95,19 +89,17 @@
       {"http://*.foo/bar:1234", URLPattern::ParseResult::kSuccess, "*"},
       {"http://foo/bar:1234/path", URLPattern::ParseResult::kSuccess, "*"}};
 
-  for (size_t i = 0; i < std::size(kTestPatterns); ++i) {
+  for (const auto& entry : kTestPatterns) {
     URLPattern pattern(URLPattern::SCHEME_ALL);
-    EXPECT_EQ(kTestPatterns[i].expected_result,
-              pattern.Parse(kTestPatterns[i].pattern))
-        << "Got unexpected result for URL pattern: "
-        << kTestPatterns[i].pattern;
-    EXPECT_EQ(kTestPatterns[i].expected_port, pattern.port())
-        << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern;
+    EXPECT_EQ(entry.expected_result, pattern.Parse(entry.pattern))
+        << "Got unexpected result for URL pattern: " << entry.pattern;
+    EXPECT_EQ(entry.expected_port, pattern.port())
+        << "Got unexpected port for URL pattern: " << entry.pattern;
   }
 }
 
 TEST(ExtensionURLPatternTest, IPv6Patterns) {
-  constexpr struct {
+  static constexpr struct {
     const char* pattern;
     const char* expected_host;
     const char* expected_port;
@@ -448,28 +440,26 @@
   EXPECT_FALSE(pattern.MatchesURL(GURL("javascript:")));
 }
 
-static const struct MatchPatterns {
+static constexpr struct MatchPatterns {
   const char* pattern;
   const char* matches;
 } kMatch13UrlPatternTestCases[] = {
-  {"about:*", "about:blank"},
-  {"about:blank", "about:blank"},
-  {"about:*", "about:version"},
-  {"chrome-extension://*/*", "chrome-extension://FTW"},
-  {"data:*", "data:monkey"},
-  {"javascript:*", "javascript:atemyhomework"},
+    {"about:*", "about:blank"},
+    {"about:blank", "about:blank"},
+    {"about:*", "about:version"},
+    {"chrome-extension://*/*", "chrome-extension://FTW"},
+    {"data:*", "data:monkey"},
+    {"javascript:*", "javascript:atemyhomework"},
 };
 
 // SCHEME_ALL and specific schemes.
 TEST(ExtensionURLPatternTest, Match13) {
-  for (size_t i = 0; i < std::size(kMatch13UrlPatternTestCases); ++i) {
+  for (const auto& entry : kMatch13UrlPatternTestCases) {
     URLPattern pattern(URLPattern::SCHEME_ALL);
-    EXPECT_EQ(URLPattern::ParseResult::kSuccess,
-              pattern.Parse(kMatch13UrlPatternTestCases[i].pattern))
-        << " while parsing " << kMatch13UrlPatternTestCases[i].pattern;
-    EXPECT_TRUE(pattern.MatchesURL(
-        GURL(kMatch13UrlPatternTestCases[i].matches)))
-        << " while matching " << kMatch13UrlPatternTestCases[i].matches;
+    EXPECT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse(entry.pattern))
+        << " while parsing " << entry.pattern;
+    EXPECT_TRUE(pattern.MatchesURL(GURL(entry.matches)))
+        << " while matching " << entry.matches;
   }
 
   // Negative test.
@@ -586,32 +576,30 @@
       GURL("filesystem:chrome-extension://ftw/t/file.txt")));
 }
 
-static const struct GetAsStringPatterns {
-  const std::string pattern;
-} kGetAsStringTestCases[] = {
-    {"http://www/"},
-    {"http://*/*"},
-    {content::GetWebUIURLString("*/*")},
-    {content::GetWebUIURLString("newtab/")},
-    {"about:*"},
-    {"about:blank"},
-    {"chrome-extension://*/*"},
-    {"chrome-extension://ftw/"},
-    {"data:*"},
-    {"data:monkey"},
-    {"javascript:*"},
-    {"javascript:atemyhomework"},
-    {"http://www.example.com:8080/foo"},
-};
-
 TEST(ExtensionURLPatternTest, GetAsString) {
-  for (size_t i = 0; i < std::size(kGetAsStringTestCases); ++i) {
+  const struct GetAsStringPatterns {
+    const std::string pattern;
+  } kGetAsStringTestCases[] = {
+      {"http://www/"},
+      {"http://*/*"},
+      {content::GetWebUIURLString("*/*")},
+      {content::GetWebUIURLString("newtab/")},
+      {"about:*"},
+      {"about:blank"},
+      {"chrome-extension://*/*"},
+      {"chrome-extension://ftw/"},
+      {"data:*"},
+      {"data:monkey"},
+      {"javascript:*"},
+      {"javascript:atemyhomework"},
+      {"http://www.example.com:8080/foo"},
+  };
+
+  for (const auto& entry : kGetAsStringTestCases) {
     URLPattern pattern(URLPattern::SCHEME_ALL);
-    EXPECT_EQ(URLPattern::ParseResult::kSuccess,
-              pattern.Parse(kGetAsStringTestCases[i].pattern))
-        << "Error parsing " << kGetAsStringTestCases[i].pattern;
-    EXPECT_EQ(kGetAsStringTestCases[i].pattern,
-              pattern.GetAsString());
+    EXPECT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse(entry.pattern))
+        << "Error parsing " << entry.pattern;
+    EXPECT_EQ(entry.pattern, pattern.GetAsString());
   }
 }
 
@@ -745,96 +733,59 @@
 }
 
 TEST(ExtensionURLPatternTest, Equals) {
-  const struct {
+  static constexpr struct {
     const char* pattern1;
     const char* pattern2;
     bool expected_equal;
   } kEqualsTestCases[] = {
-    // schemes
-    { "http://en.google.com/blah/*/foo",
-      "https://en.google.com/blah/*/foo",
-      false
-    },
-    { "https://en.google.com/blah/*/foo",
-      "https://en.google.com/blah/*/foo",
-      true
-    },
-    { "https://en.google.com/blah/*/foo",
-      "ftp://en.google.com/blah/*/foo",
-      false
-    },
+      // schemes
+      {"http://en.google.com/blah/*/foo", "https://en.google.com/blah/*/foo",
+       false},
+      {"https://en.google.com/blah/*/foo", "https://en.google.com/blah/*/foo",
+       true},
+      {"https://en.google.com/blah/*/foo", "ftp://en.google.com/blah/*/foo",
+       false},
 
-    // subdomains
-    { "https://en.google.com/blah/*/foo",
-      "https://fr.google.com/blah/*/foo",
-      false
-    },
-    { "https://www.google.com/blah/*/foo",
-      "https://*.google.com/blah/*/foo",
-      false
-    },
-    { "https://*.google.com/blah/*/foo",
-      "https://*.google.com/blah/*/foo",
-      true
-    },
+      // subdomains
+      {"https://en.google.com/blah/*/foo", "https://fr.google.com/blah/*/foo",
+       false},
+      {"https://www.google.com/blah/*/foo", "https://*.google.com/blah/*/foo",
+       false},
+      {"https://*.google.com/blah/*/foo", "https://*.google.com/blah/*/foo",
+       true},
 
-    // domains
-    { "http://en.example.com/blah/*/foo",
-      "http://en.google.com/blah/*/foo",
-      false
-    },
+      // domains
+      {"http://en.example.com/blah/*/foo", "http://en.google.com/blah/*/foo",
+       false},
 
-    // ports
-    { "http://en.google.com:8000/blah/*/foo",
-      "http://en.google.com/blah/*/foo",
-      false
-    },
-    { "http://fr.google.com:8000/blah/*/foo",
-      "http://fr.google.com:8000/blah/*/foo",
-      true
-    },
-    { "http://en.google.com:8000/blah/*/foo",
-      "http://en.google.com:8080/blah/*/foo",
-      false
-    },
+      // ports
+      {"http://en.google.com:8000/blah/*/foo",
+       "http://en.google.com/blah/*/foo", false},
+      {"http://fr.google.com:8000/blah/*/foo",
+       "http://fr.google.com:8000/blah/*/foo", true},
+      {"http://en.google.com:8000/blah/*/foo",
+       "http://en.google.com:8080/blah/*/foo", false},
 
-    // paths
-    { "http://en.google.com/blah/*/foo",
-      "http://en.google.com/blah/*",
-      false
-    },
-    { "http://en.google.com/*",
-      "http://en.google.com/",
-      false
-    },
-    { "http://en.google.com/*",
-      "http://en.google.com/*",
-      true
-    },
+      // paths
+      {"http://en.google.com/blah/*/foo", "http://en.google.com/blah/*", false},
+      {"http://en.google.com/*", "http://en.google.com/", false},
+      {"http://en.google.com/*", "http://en.google.com/*", true},
 
-    // all_urls
-    { "<all_urls>",
-      "<all_urls>",
-      true
-    },
-    { "<all_urls>",
-      "http://*/*",
-      false
-    }
-  };
+      // all_urls
+      {"<all_urls>", "<all_urls>", true},
+      {"<all_urls>", "http://*/*", false}};
 
-  for (size_t i = 0; i < std::size(kEqualsTestCases); ++i) {
-    std::string message = kEqualsTestCases[i].pattern1;
+  for (const auto& entry : kEqualsTestCases) {
+    std::string message = entry.pattern1;
     message += " ";
-    message += kEqualsTestCases[i].pattern2;
+    message += entry.pattern2;
 
     URLPattern pattern1(URLPattern::SCHEME_ALL);
     URLPattern pattern2(URLPattern::SCHEME_ALL);
 
-    pattern1.Parse(kEqualsTestCases[i].pattern1);
-    pattern2.Parse(kEqualsTestCases[i].pattern2);
-    EXPECT_EQ(kEqualsTestCases[i].expected_equal, pattern1 == pattern2)
-        << message;
+    pattern1.Parse(entry.pattern1);
+    pattern2.Parse(entry.pattern2);
+    EXPECT_EQ(entry.expected_equal, pattern1 == pattern2) << message;
   }
 }
 
diff --git a/extensions/renderer/api/messaging/messaging_util.cc b/extensions/renderer/api/messaging/messaging_util.cc
index d412695..bd77e33 100644
--- a/extensions/renderer/api/messaging/messaging_util.cc
+++ b/extensions/renderer/api/messaging/messaging_util.cc
@@ -117,8 +117,6 @@
 const char kOnConnectExternalEvent[] = "runtime.onConnectExternal";
 const char kOnConnectNativeEvent[] = "runtime.onConnectNative";
 
-const int kNoFrameId = -1;
-
 std::unique_ptr<Message> MessageFromV8(v8::Local<v8::Context> context,
                                        v8::Local<v8::Value> value,
                                        mojom::SerializationFormat format,
diff --git a/extensions/renderer/api/messaging/messaging_util.h b/extensions/renderer/api/messaging/messaging_util.h
index a08480a..6e9194f 100644
--- a/extensions/renderer/api/messaging/messaging_util.h
+++ b/extensions/renderer/api/messaging/messaging_util.h
@@ -43,7 +43,7 @@
 extern const char kOnUserScriptConnectEvent[];
 extern const char kOnConnectNativeEvent[];
 
-extern const int kNoFrameId;
+inline constexpr int kNoFrameId = -1;
 
 // Parses the message from a v8 value, returning null on failure. On error,
 // will populate `error_out`.
diff --git a/extensions/renderer/api/messaging/messaging_util_unittest.cc b/extensions/renderer/api/messaging/messaging_util_unittest.cc
index ff059adb..f6a989c5 100644
--- a/extensions/renderer/api/messaging/messaging_util_unittest.cc
+++ b/extensions/renderer/api/messaging/messaging_util_unittest.cc
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "extensions/renderer/api/messaging/messaging_util.h"
 
+#include <array>
 #include <memory>
+#include <string>
 #include <string_view>
 
 #include "base/strings/stringprintf.h"
@@ -27,6 +24,16 @@
 
 namespace extensions {
 
+namespace {
+
+struct TestCase {
+  v8::Local<v8::Value> passed_id;
+  std::string_view expected_id;
+  bool should_pass;
+};
+
+}  // anonymous namespace
+
 using MessagingUtilTest = APIBindingTest;
 
 TEST_F(MessagingUtilTest, TestMaximumMessageSize) {
@@ -49,7 +56,7 @@
   v8::HandleScope handle_scope(isolate());
   v8::Local<v8::Context> context = MainContext();
 
-  struct {
+  static constexpr struct {
     int expected_frame_id;
     const char* string_options;
   } test_cases[] = {
@@ -204,11 +211,7 @@
   script_context->set_url(extension->url());
 
   std::string other_id(32, 'a');
-  struct {
-    v8::Local<v8::Value> passed_id;
-    std::string_view expected_id;
-    bool should_pass;
-  } test_cases[] = {
+  const auto test_cases = std::to_array<TestCase>({
       // If the extension ID is not provided, the bindings use the calling
       // extension's.
       {v8::Null(isolate()), extension->id(), true},
@@ -219,7 +222,7 @@
       {gin::StringToV8(isolate(), extension->id()), extension->id(), true},
       {gin::StringToV8(isolate(), other_id), other_id, true},
       {gin::StringToV8(isolate(), "invalid id"), std::string_view(), false},
-  };
+  });
 
   for (size_t i = 0; i < std::size(test_cases); ++i) {
     SCOPED_TRACE(base::StringPrintf("Test Case: %d", static_cast<int>(i)));
@@ -244,17 +247,13 @@
   script_context->set_url(GURL("https://example.com"));
 
   std::string other_id(32, 'a');
-  struct {
-    v8::Local<v8::Value> passed_id;
-    std::string_view expected_id;
-    bool should_pass;
-  } test_cases[] = {
+  const auto test_cases = std::to_array<TestCase>({
       // A web page should always have to specify the extension id.
       {gin::StringToV8(isolate(), other_id), other_id, true},
       {v8::Null(isolate()), std::string_view(), false},
       {gin::StringToV8(isolate(), ""), std::string_view(), false},
       {gin::StringToV8(isolate(), "invalid id"), std::string_view(), false},
-  };
+  });
 
   for (size_t i = 0; i < std::size(test_cases); ++i) {
     SCOPED_TRACE(base::StringPrintf("Test Case: %d", static_cast<int>(i)));
@@ -282,11 +281,7 @@
   script_context->set_url(extension->url());
 
   std::string other_id(32, 'a');
-  struct {
-    v8::Local<v8::Value> passed_id;
-    std::string_view expected_id;
-    bool should_pass;
-  } test_cases[] = {
+  const auto test_cases = std::to_array<TestCase>({
       // If the extension ID is not provided, the bindings use the calling
       // extension's.
       {v8::Null(isolate()), extension->id(), true},
@@ -297,7 +292,7 @@
       {gin::StringToV8(isolate(), extension->id()), extension->id(), true},
       // User scripts may not target other extensions.
       {gin::StringToV8(isolate(), other_id), std::string_view(), false},
-  };
+  });
 
   for (size_t i = 0; i < std::size(test_cases); ++i) {
     SCOPED_TRACE(base::StringPrintf("Test Case: %d", static_cast<int>(i)));
diff --git a/extensions/renderer/extension_throttle_simulation_unittest.cc b/extensions/renderer/extension_throttle_simulation_unittest.cc
index ff05bc2c..3684d38 100644
--- a/extensions/renderer/extension_throttle_simulation_unittest.cc
+++ b/extensions/renderer/extension_throttle_simulation_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 // The tests in this file attempt to verify the following through simulation:
 // a) That a server experiencing overload will actually benefit from the
 //    anti-DDoS throttling logic, i.e. that its traffic spike will subside
@@ -20,6 +15,7 @@
 #include <stdarg.h>
 #include <stddef.h>
 
+#include <array>
 #include <cmath>
 #include <limits>
 #include <memory>
@@ -658,7 +654,7 @@
   // type of behavior of the client and the downtime, e.g. the difference
   // in behavior between a client making requests every few minutes vs.
   // one that makes a request every 15 seconds).
-  Trial trials[] = {
+  auto trials = std::to_array<Trial>({
       {base::Seconds(10), base::Seconds(3)},
       {base::Seconds(30), base::Seconds(7)},
       {base::Minutes(5), base::Seconds(30)},
@@ -679,7 +675,7 @@
 
       // Most brutal?
       {base::Minutes(45), base::Milliseconds(500)},
-  };
+  });
 
   // If things don't converge by the time we've done 100K trials, then
   // clearly one or more of the expected intervals are wrong.
diff --git a/extensions/renderer/extension_throttle_unittest.cc b/extensions/renderer/extension_throttle_unittest.cc
index 6cd440c..41d2734 100644
--- a/extensions/renderer/extension_throttle_unittest.cc
+++ b/extensions/renderer/extension_throttle_unittest.cc
@@ -2,11 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
+#include <array>
 #include <memory>
 
 #include "base/strings/string_number_conversions.h"
@@ -213,7 +209,7 @@
       base::Milliseconds(MockExtensionThrottleEntry::kDefaultEntryLifetimeMs);
   const base::TimeDelta kFiveMs = base::Milliseconds(5);
 
-  TimeAndBool test_values[] = {
+  const std::array<TimeAndBool, 6> test_values = {
       TimeAndBool(now_, false, __LINE__),
       TimeAndBool(now_ - kFiveMs, false, __LINE__),
       TimeAndBool(now_ + kFiveMs, false, __LINE__),
@@ -286,7 +282,7 @@
 
 TEST(ExtensionThrottleManagerTest, IsUrlStandardised) {
   MockExtensionThrottleManager manager;
-  GurlAndString test_values[] = {
+  const std::array<GurlAndString, 8> test_values = {
       GurlAndString(GURL("http://www.example.com"),
                     std::string("http://www.example.com/"), __LINE__),
       GurlAndString(GURL("http://www.Example.com"),
diff --git a/gpu/vulkan/vulkan_instance.cc b/gpu/vulkan/vulkan_instance.cc
index 9be0a1dc..c9424c6c8 100644
--- a/gpu/vulkan/vulkan_instance.cc
+++ b/gpu/vulkan/vulkan_instance.cc
@@ -25,10 +25,6 @@
 #include <sys/sysmacros.h>
 #endif
 
-#if BUILDFLAG(IS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
 namespace gpu {
 
 namespace {
@@ -207,13 +203,7 @@
   VkResult result =
       vkCreateInstance(&instance_create_info, nullptr, &owned_vk_instance_);
   if (VK_SUCCESS != result) {
-#if BUILDFLAG(IS_ANDROID)
-    // TODO(crbug.com/381535049): Remove deqp level printing after figuring out
-    // device initialization discrepancies.
-    const auto* build_info = base::android::BuildInfo::GetInstance();
-    LOG(ERROR) << "deqp_level=" << build_info->vulkan_deqp_level();
-#endif
-    LOG(ERROR) << "vkCreateInstance() failed: " << static_cast<int>(result);
+    LOG(ERROR) << "vkCreateInstance() failed: " << result;
     return false;
   }
   vk_instance_ = owned_vk_instance_;
diff --git a/internal b/internal
index 574ed45..98f86ef 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 574ed45332eea47966af2212641b55e7aa9d7030
+Subproject commit 98f86ef6116bb6582bf385d8ffd1efb255f50c5c
diff --git a/ios_internal b/ios_internal
index ed7bda3..156f000 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit ed7bda3f92a8d250ee6463bff9d730d01cf23bda
+Subproject commit 156f0000208f3f45680ec110953276b784deec94
diff --git a/pdf/pdf_ink_ids.h b/pdf/pdf_ink_ids.h
index 1127c20..d96f181 100644
--- a/pdf/pdf_ink_ids.h
+++ b/pdf/pdf_ink_ids.h
@@ -14,7 +14,7 @@
 
 namespace chrome_pdf {
 
-// Identifies ink::ModeledShape objects.
+// Identifies ink::PartitionedMesh objects.
 using InkModeledShapeId = base::StrongAlias<class InkModeledShapeIdTag, size_t>;
 
 // Identifies ink::Stroke objects.
diff --git a/pdf/pdf_ink_module.cc b/pdf/pdf_ink_module.cc
index acbb75ae..2595ed0 100644
--- a/pdf/pdf_ink_module.cc
+++ b/pdf/pdf_ink_module.cc
@@ -40,7 +40,7 @@
 #include "third_party/ink/src/ink/brush/brush.h"
 #include "third_party/ink/src/ink/geometry/affine_transform.h"
 #include "third_party/ink/src/ink/geometry/intersects.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/rect.h"
 #include "third_party/ink/src/ink/rendering/skia/native/skia_renderer.h"
 #include "third_party/ink/src/ink/strokes/in_progress_stroke.h"
@@ -689,7 +689,7 @@
 
       // No transform needed, as `eraser_rect` is already using transformed
       // coordinates from `canonical_position`.
-      const ink::ModeledShape& shape = stroke.stroke.GetShape();
+      const ink::PartitionedMesh& shape = stroke.stroke.GetShape();
       if (!ink::Intersects(eraser_rect, shape, kIdentityTransform)) {
         continue;
       }
@@ -1209,7 +1209,7 @@
 
 PdfInkModule::FinishedStrokeState::~FinishedStrokeState() = default;
 
-PdfInkModule::LoadedV2ShapeState::LoadedV2ShapeState(ink::ModeledShape shape,
+PdfInkModule::LoadedV2ShapeState::LoadedV2ShapeState(ink::PartitionedMesh shape,
                                                      InkModeledShapeId id)
     : shape(std::move(shape)), id(id) {}
 
diff --git a/pdf/pdf_ink_module.h b/pdf/pdf_ink_module.h
index 57cfbff..ab853c8 100644
--- a/pdf/pdf_ink_module.h
+++ b/pdf/pdf_ink_module.h
@@ -21,7 +21,7 @@
 #include "pdf/pdf_ink_ids.h"
 #include "pdf/pdf_ink_undo_redo_model.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/strokes/in_progress_stroke.h"
 #include "third_party/ink/src/ink/strokes/input/stroke_input.h"
 #include "third_party/ink/src/ink/strokes/input/stroke_input_batch.h"
@@ -183,7 +183,7 @@
   // A shape that was loaded from a "V2" path from the PDF itself, its ID, and
   // whether it should be drawn or not.
   struct LoadedV2ShapeState {
-    LoadedV2ShapeState(ink::ModeledShape shape, InkModeledShapeId id);
+    LoadedV2ShapeState(ink::PartitionedMesh shape, InkModeledShapeId id);
     LoadedV2ShapeState(const LoadedV2ShapeState&) = delete;
     LoadedV2ShapeState& operator=(const LoadedV2ShapeState&) = delete;
     LoadedV2ShapeState(LoadedV2ShapeState&&) noexcept;
@@ -192,7 +192,7 @@
 
     // Coordinates for each shape are stored in a canonical format specified in
     // pdf_ink_transform.h.
-    ink::ModeledShape shape;
+    ink::PartitionedMesh shape;
 
     // A unique ID to identify this shape.
     InkModeledShapeId id;
diff --git a/pdf/pdf_ink_module_client.h b/pdf/pdf_ink_module_client.h
index 38e6dbe..5404625 100644
--- a/pdf/pdf_ink_module_client.h
+++ b/pdf/pdf_ink_module_client.h
@@ -10,7 +10,7 @@
 #include "pdf/buildflags.h"
 #include "pdf/page_orientation.h"
 #include "pdf/pdf_ink_ids.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
@@ -31,7 +31,8 @@
  public:
   // Key: ID to identify a shape.
   // Value: The Ink shape.
-  using PageV2InkPathShapesMap = std::map<InkModeledShapeId, ink::ModeledShape>;
+  using PageV2InkPathShapesMap =
+      std::map<InkModeledShapeId, ink::PartitionedMesh>;
 
   // Key: 0-based page index.
   // Value: Map of shapes on the page.
diff --git a/pdf/pdf_ink_module_unittest.cc b/pdf/pdf_ink_module_unittest.cc
index 55fbaf73..87b97d3c 100644
--- a/pdf/pdf_ink_module_unittest.cc
+++ b/pdf/pdf_ink_module_unittest.cc
@@ -159,6 +159,21 @@
   return arg.GetBrush().GetSize() == expected_size;
 }
 
+// Matcher for ink::Stroke objects against an expected drawing brush type.
+// A pen is opaque while a highlighter has transparency, so a drawing
+// brush type can be deduced from the ink::Stroke's brush coat.
+MATCHER_P(InkStrokeDrawingBrushTypeEq, expected_type, "") {
+  const ink::Brush& ink_brush = arg.GetBrush();
+  const ink::BrushCoat& coat = ink_brush.GetCoats()[0];
+  float opacity = coat.tips[0].opacity_multiplier;
+  if (expected_type == PdfInkBrush::Type::kPen) {
+    return opacity == 1.0f;
+  }
+
+  CHECK(expected_type == PdfInkBrush::Type::kHighlighter);
+  return opacity == 0.4f;
+}
+
 // Matcher for bitmap against expected dimensions.
 MATCHER_P(BitmapImageSizeEq, dimensions, "") {
   return arg.dimensions() == dimensions;
@@ -578,11 +593,11 @@
       .WillOnce(Return(PdfInkModuleClient::DocumentV2InkPathShapesMap{
           {0,
            PdfInkModuleClient::PageV2InkPathShapesMap{
-               {InkModeledShapeId(0), ink::ModeledShape()},
-               {InkModeledShapeId(1), ink::ModeledShape()}}},
+               {InkModeledShapeId(0), ink::PartitionedMesh()},
+               {InkModeledShapeId(1), ink::PartitionedMesh()}}},
           {3,
            PdfInkModuleClient::PageV2InkPathShapesMap{
-               {InkModeledShapeId(2), ink::ModeledShape()}}},
+               {InkModeledShapeId(2), ink::PartitionedMesh()}}},
       }));
 
   const auto kShapeMapMatcher = ElementsAre(
@@ -1880,6 +1895,75 @@
   EXPECT_TRUE(ink_module().HandleInputEvent(mouse_up_event));
 }
 
+TEST_F(PdfInkModuleStrokeTest, ChangeDrawingBrushTypeDuringDrawing) {
+  EnableAnnotationMode();
+  InitializeSimpleSinglePageBasicLayout();
+
+  // Start drawing a stroke with a black pen.  The stroke will not finish
+  // until the mouse-up event.  The cursor image will be updated immediately
+  // each time the brush tool is changed, regardless of whether a stroke is
+  // in progress.
+  EXPECT_CALL(client(), StrokeAdded(_, _, _)).Times(0);
+  {
+    InSequence seq;
+    EXPECT_CALL(client(),
+                UpdateInkCursorImage(BitmapImageSizeEq(SkISize(6, 6))));
+    EXPECT_CALL(client(),
+                UpdateInkCursorImage(BitmapImageSizeEq(SkISize(10, 10))));
+  }
+  TestAnnotationBrushMessageParams pen_message_params{/*color_r=*/0,
+                                                      /*color_g=*/0,
+                                                      /*color_b=*/0};
+  SelectBrushTool(PdfInkBrush::Type::kPen, 2.0f, pen_message_params);
+
+  blink::WebMouseEvent mouse_down_event =
+      MouseEventBuilder()
+          .CreateLeftClickAtPosition(kLeftVerticalStrokePoint1)
+          .Build();
+  EXPECT_TRUE(ink_module().HandleInputEvent(mouse_down_event));
+
+  // While the stroke is still in progress, change the input tool type to a
+  // highlighter.  The entire stroke changes to this new type.
+  TestAnnotationBrushMessageParams highlighter_message_params{/*color_r=*/221,
+                                                              /*color_g=*/243,
+                                                              /*color_b=*/0};
+  SelectBrushTool(PdfInkBrush::Type::kHighlighter, 8.0f,
+                  highlighter_message_params);
+  VerifyAndClearExpectations();
+
+  // Continue with mouse movement and then mouse up at a new location.  Notice
+  // that the events are handled and the new stroke is added.
+  // TODO(crbug.com/381908888): The in-progress stroke and cursor image are
+  // affected by the brush type change.  Update the expectation to show the
+  // in-progress stroke is still a pen once the brush management in
+  // PdfInkModule protects against such changes.
+  static constexpr int kPageIndex = 0;
+  EXPECT_CALL(client(), StrokeAdded(kPageIndex, InkStrokeId(0),
+                                    InkStrokeDrawingBrushTypeEq(
+                                        PdfInkBrush::Type::kHighlighter)));
+  blink::WebMouseEvent mouse_move_event =
+      MouseEventBuilder()
+          .SetType(blink::WebInputEvent::Type::kMouseMove)
+          .SetPosition(kLeftVerticalStrokePoint2)
+          .SetButton(blink::WebPointerProperties::Button::kLeft)
+          .Build();
+  EXPECT_TRUE(ink_module().HandleInputEvent(mouse_move_event));
+  blink::WebMouseEvent mouse_up_event =
+      MouseEventBuilder()
+          .CreateLeftMouseUpAtPosition(kLeftVerticalStrokePoint2)
+          .Build();
+  EXPECT_TRUE(ink_module().HandleInputEvent(mouse_up_event));
+  VerifyAndClearExpectations();
+
+  // Do another stroke.  Notice that the changed input tool type has taken
+  // effect for the new stroke that is added.
+  EXPECT_CALL(client(), StrokeAdded(kPageIndex, InkStrokeId(1),
+                                    InkStrokeDrawingBrushTypeEq(
+                                        PdfInkBrush::Type::kHighlighter)));
+  EXPECT_TRUE(ink_module().HandleInputEvent(mouse_down_event));
+  EXPECT_TRUE(ink_module().HandleInputEvent(mouse_up_event));
+}
+
 class PdfInkModuleUndoRedoTest : public PdfInkModuleStrokeTest {
  protected:
   void PerformUndo() {
@@ -2253,7 +2337,7 @@
       CreateInkMeshFromPolylineForTesting(ink_points);
   ASSERT_TRUE(mesh0.has_value());
   auto shape0 =
-      ink::ModeledShape::FromMeshes(base::span_from_ref(mesh0.value()));
+      ink::PartitionedMesh::FromMeshes(base::span_from_ref(mesh0.value()));
   ASSERT_TRUE(shape0.ok());
 
   constexpr ink::Point kCornerPoints[] = {
@@ -2265,7 +2349,7 @@
       CreateInkMeshFromPolylineForTesting(kCornerPoints);
   ASSERT_TRUE(mesh1.has_value());
   auto shape1 =
-      ink::ModeledShape::FromMeshes(base::span_from_ref(mesh1.value()));
+      ink::PartitionedMesh::FromMeshes(base::span_from_ref(mesh1.value()));
   ASSERT_TRUE(shape1.ok());
 
   EXPECT_CALL(client(), LoadV2InkPathsFromPdf())
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc
index 83908f2e..ef951ace 100644
--- a/pdf/pdf_view_web_plugin_unittest.cc
+++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -2619,18 +2619,18 @@
 }
 
 TEST_F(PdfViewWebPluginInkTest, LoadV2InkPathsForPageAndUpdateShapeActive) {
-  const std::map<InkModeledShapeId, ink::ModeledShape> kEmptyMap;
-  const std::map<InkModeledShapeId, ink::ModeledShape> kMap0{
-      {InkModeledShapeId(0), ink::ModeledShape()},
+  const std::map<InkModeledShapeId, ink::PartitionedMesh> kEmptyMap;
+  const std::map<InkModeledShapeId, ink::PartitionedMesh> kMap0{
+      {InkModeledShapeId(0), ink::PartitionedMesh()},
   };
-  const std::map<InkModeledShapeId, ink::ModeledShape> kMap1{
-      {InkModeledShapeId(1), ink::ModeledShape()},
-      {InkModeledShapeId(2), ink::ModeledShape()},
+  const std::map<InkModeledShapeId, ink::PartitionedMesh> kMap1{
+      {InkModeledShapeId(1), ink::PartitionedMesh()},
+      {InkModeledShapeId(2), ink::PartitionedMesh()},
   };
-  const std::map<InkModeledShapeId, ink::ModeledShape> kMap2{
-      {InkModeledShapeId(3), ink::ModeledShape()},
-      {InkModeledShapeId(4), ink::ModeledShape()},
-      {InkModeledShapeId(5), ink::ModeledShape()},
+  const std::map<InkModeledShapeId, ink::PartitionedMesh> kMap2{
+      {InkModeledShapeId(3), ink::PartitionedMesh()},
+      {InkModeledShapeId(4), ink::PartitionedMesh()},
+      {InkModeledShapeId(5), ink::PartitionedMesh()},
   };
 
   EXPECT_CALL(*engine_ptr_, LoadV2InkPathsForPage(testing::Lt(12)))
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index c3c6b18..80ea005 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4449,7 +4449,7 @@
   ink_stroke_objects_map_.erase(it);
 }
 
-std::map<InkModeledShapeId, ink::ModeledShape>
+std::map<InkModeledShapeId, ink::PartitionedMesh>
 PDFiumEngine::LoadV2InkPathsForPage(int page_index) {
   CHECK(PageIndexInBounds(page_index));
 
@@ -4459,7 +4459,7 @@
   CHECK(inserted);
 #endif  // DCHECK_IS_ON()
 
-  std::map<InkModeledShapeId, ink::ModeledShape> page_shape_map;
+  std::map<InkModeledShapeId, ink::PartitionedMesh> page_shape_map;
 
   std::vector<ReadV2InkPathResult> read_results =
       ReadV2InkPathsFromPageAsModeledShapes(pages_[page_index]->GetPage());
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index d6b3f62..5452ff7 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -62,7 +62,7 @@
 
 #if BUILDFLAG(ENABLE_PDF_INK2)
 #include "pdf/pdf_ink_ids.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #endif
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
@@ -408,8 +408,8 @@
   // PDFium page object.
   //
   // Virtual to support testing.
-  virtual std::map<InkModeledShapeId, ink::ModeledShape> LoadV2InkPathsForPage(
-      int page_index);
+  virtual std::map<InkModeledShapeId, ink::PartitionedMesh>
+  LoadV2InkPathsForPage(int page_index);
 
   // Modifies an existing shape identified by `id` on the page at `page_index`
   // to become either active or inactive. The caller must pass the same
diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc
index 26d7b96..d589b23f 100644
--- a/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/pdf/pdfium/pdfium_engine_unittest.cc
@@ -2054,7 +2054,7 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
   EXPECT_TRUE(engine->ink_modeled_shape_map_for_testing().empty());
 
-  std::map<InkModeledShapeId, ink::ModeledShape> ink_shapes =
+  std::map<InkModeledShapeId, ink::PartitionedMesh> ink_shapes =
       engine->LoadV2InkPathsForPage(/*page_index=*/0);
   ASSERT_EQ(1u, ink_shapes.size());
   const auto ink_shapes_it = ink_shapes.begin();
@@ -2275,7 +2275,7 @@
             1);
 
   // Check the LoadV2InkPathsForPage() call does not change the rendering.
-  std::map<InkModeledShapeId, ink::ModeledShape> ink_shapes =
+  std::map<InkModeledShapeId, ink::PartitionedMesh> ink_shapes =
       engine->LoadV2InkPathsForPage(kPageIndex);
   ASSERT_EQ(1u, ink_shapes.size());
   CheckPdfRendering(page.GetPage(), kPageSizeInPoints, kInkV2PngPath);
diff --git a/pdf/pdfium/pdfium_ink_reader.cc b/pdf/pdfium/pdfium_ink_reader.cc
index b82e3428..c0eb10b 100644
--- a/pdf/pdfium/pdfium_ink_reader.cc
+++ b/pdf/pdfium/pdfium_ink_reader.cc
@@ -18,7 +18,7 @@
 #include "pdf/pdfium/pdfium_api_wrappers.h"
 #include "printing/units.h"
 #include "third_party/ink/src/ink/geometry/mesh.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/point.h"
 #include "third_party/ink/src/ink/geometry/tessellator.h"
 #include "third_party/pdfium/public/fpdf_edit.h"
@@ -89,7 +89,7 @@
   return *mesh;
 }
 
-std::optional<ink::ModeledShape> ReadV2InkModeledShapeFromPath(
+std::optional<ink::PartitionedMesh> ReadV2InkModeledShapeFromPath(
     FPDF_PAGEOBJECT path,
     const gfx::AxisTransform2d& transform) {
   CHECK_EQ(FPDFPageObj_GetType(path), FPDF_PAGEOBJ_PATH);
@@ -138,8 +138,9 @@
 
   // Note that `shape` only has enough data for use with ink::Intersects(). It
   // has no outline.
-  auto shape = ink::ModeledShape::FromMeshes(base::span_from_ref(mesh.value()),
-                                             /*outlines=*/{});
+  auto shape =
+      ink::PartitionedMesh::FromMeshes(base::span_from_ref(mesh.value()),
+                                       /*outlines=*/{});
   if (!shape.ok()) {
     return std::nullopt;
   }
@@ -167,7 +168,7 @@
       continue;
     }
 
-    std::optional<ink::ModeledShape> shape =
+    std::optional<ink::PartitionedMesh> shape =
         ReadV2InkModeledShapeFromPath(page_object, transform);
     if (!shape.has_value()) {
       continue;
diff --git a/pdf/pdfium/pdfium_ink_reader.h b/pdf/pdfium/pdfium_ink_reader.h
index f75a963..0cb070a9 100644
--- a/pdf/pdfium/pdfium_ink_reader.h
+++ b/pdf/pdfium/pdfium_ink_reader.h
@@ -11,7 +11,7 @@
 #include "base/containers/span.h"
 #include "pdf/buildflags.h"
 #include "third_party/ink/src/ink/geometry/mesh.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/point.h"
 #include "third_party/pdfium/public/fpdfview.h"
 
@@ -21,11 +21,11 @@
 
 struct ReadV2InkPathResult {
   FPDF_PAGEOBJECT page_object;
-  ink::ModeledShape shape;
+  ink::PartitionedMesh shape;
 };
 
 // For the given `page`, iterate through all page objects and import "V2" paths
-// created by Ink as ink::ModeledShapes. For each shape, also return its
+// created by Ink as ink::PartitionedMeshs. For each shape, also return its
 // associated page object. The shapes do not have outlines and are only suitable
 // for use with ink::Intersects().
 //
diff --git a/pdf/pdfium/pdfium_ink_reader_unittest.cc b/pdf/pdfium/pdfium_ink_reader_unittest.cc
index 801b57df..00ae074 100644
--- a/pdf/pdfium/pdfium_ink_reader_unittest.cc
+++ b/pdf/pdfium/pdfium_ink_reader_unittest.cc
@@ -16,7 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/ink/src/ink/geometry/affine_transform.h"
 #include "third_party/ink/src/ink/geometry/intersects.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/point.h"
 
 namespace chrome_pdf {
diff --git a/pdf/pdfium/pdfium_ink_writer.cc b/pdf/pdfium/pdfium_ink_writer.cc
index 55872d0..6b47c9ca 100644
--- a/pdf/pdfium/pdfium_ink_writer.cc
+++ b/pdf/pdfium/pdfium_ink_writer.cc
@@ -17,7 +17,7 @@
 #include "third_party/ink/src/ink/brush/brush_coat.h"
 #include "third_party/ink/src/ink/brush/brush_tip.h"
 #include "third_party/ink/src/ink/geometry/mesh.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/point.h"
 #include "third_party/ink/src/ink/strokes/stroke.h"
 #include "third_party/pdfium/public/cpp/fpdf_scopers.h"
@@ -29,7 +29,7 @@
 
 namespace {
 
-// Wrapper around an `ink::ModeledShape` to iterate through all the outlines
+// Wrapper around an `ink::PartitionedMesh` to iterate through all the outlines
 // that make up the shape.
 class ModeledShapeOutlinesIterator {
  public:
@@ -37,11 +37,11 @@
     uint32_t group_index;
     // Guaranteeded to be non-empty.
     // TODO(367764863) Rewrite to base::raw_span.
-    RAW_PTR_EXCLUSION base::span<const ink::ModeledShape::VertexIndexPair>
+    RAW_PTR_EXCLUSION base::span<const ink::PartitionedMesh::VertexIndexPair>
         outline;
   };
 
-  explicit ModeledShapeOutlinesIterator(const ink::ModeledShape& shape)
+  explicit ModeledShapeOutlinesIterator(const ink::PartitionedMesh& shape)
       : shape_(shape) {}
 
   std::optional<OutlineData> GetAndAdvance() {
@@ -62,14 +62,14 @@
   }
 
  private:
-  const raw_ref<const ink::ModeledShape> shape_;
+  const raw_ref<const ink::PartitionedMesh> shape_;
   uint32_t group_index_ = 0;
   uint32_t outline_index_ = 0;
 };
 
 gfx::PointF GetVertexPosition(
     base::span<const ink::Mesh> meshes,
-    const ink::ModeledShape::VertexIndexPair& vertex_index_pair) {
+    const ink::PartitionedMesh::VertexIndexPair& vertex_index_pair) {
   ink::Point vertex_position =
       meshes[vertex_index_pair.mesh_index].VertexPosition(
           vertex_index_pair.vertex_index);
@@ -83,7 +83,7 @@
 // The returned page object is always a `FPDF_PAGEOBJ_PATH` and never null.
 ScopedFPDFPageObject CreatePathFromOutlineData(
     FPDF_PAGE page,
-    const ink::ModeledShape& shape,
+    const ink::PartitionedMesh& shape,
     const ModeledShapeOutlinesIterator::OutlineData& outline_data,
     const gfx::AxisTransform2d& transform) {
   CHECK(page);
@@ -119,7 +119,7 @@
 }
 
 std::vector<ScopedFPDFPageObject> WriteShapeToNewPathsOnPage(
-    const ink::ModeledShape& shape,
+    const ink::PartitionedMesh& shape,
     FPDF_PAGE page) {
   CHECK(page);
 
diff --git a/pdf/pdfium/pdfium_ink_writer_unittest.cc b/pdf/pdfium/pdfium_ink_writer_unittest.cc
index 3a045fe..8424e3a 100644
--- a/pdf/pdfium/pdfium_ink_writer_unittest.cc
+++ b/pdf/pdfium/pdfium_ink_writer_unittest.cc
@@ -23,7 +23,7 @@
 #include "pdf/test/test_helpers.h"
 #include "third_party/ink/src/ink/geometry/affine_transform.h"
 #include "third_party/ink/src/ink/geometry/intersects.h"
-#include "third_party/ink/src/ink/geometry/modeled_shape.h"
+#include "third_party/ink/src/ink/geometry/partitioned_mesh.h"
 #include "third_party/ink/src/ink/geometry/point.h"
 #include "third_party/ink/src/ink/strokes/input/stroke_input.h"
 #include "third_party/ink/src/ink/strokes/input/stroke_input_batch.h"
@@ -124,8 +124,9 @@
   ASSERT_TRUE(saved_page);
 
   // Complete the round trip and read the written PDF data back into memory as
-  // an ink::ModeledShape. ReadV2InkPathsFromPageAsModeledShapes() is known to
-  // be good because its unit tests reads from a real, known to be good Ink PDF.
+  // an ink::PartitionedMesh. ReadV2InkPathsFromPageAsModeledShapes() is known
+  // to be good because its unit tests reads from a real, known to be good Ink
+  // PDF.
   std::vector<ReadV2InkPathResult> saved_results =
       ReadV2InkPathsFromPageAsModeledShapes(saved_page);
   ASSERT_EQ(saved_results.size(), 1u);
diff --git a/pdf/test/test_pdfium_engine.h b/pdf/test/test_pdfium_engine.h
index b16aa98..094697d 100644
--- a/pdf/test/test_pdfium_engine.h
+++ b/pdf/test/test_pdfium_engine.h
@@ -109,7 +109,7 @@
 
   MOCK_METHOD(void, DiscardStroke, (int, InkStrokeId), (override));
 
-  MOCK_METHOD((std::map<InkModeledShapeId, ink::ModeledShape>),
+  MOCK_METHOD((std::map<InkModeledShapeId, ink::PartitionedMesh>),
               LoadV2InkPathsForPage,
               (int),
               (override));
diff --git a/remoting/base/crash/crashpad_linux.cc b/remoting/base/crash/crashpad_linux.cc
index a9b2c7c1..cbddcecb 100644
--- a/remoting/base/crash/crashpad_linux.cc
+++ b/remoting/base/crash/crashpad_linux.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
+#include "base/time/time.h"
 #include "remoting/base/file_path_util_linux.h"
 #include "remoting/base/logging.h"
 #include "remoting/base/version.h"
@@ -21,6 +22,8 @@
 
 namespace {
 
+using crashpad::CrashReportDatabase;
+
 constexpr char kChromotingCrashpadHandler[] = "crashpad-handler";
 constexpr char kDefaultCrashpadUploadUrl[] =
     "https://clients2.google.com/cr/report";
@@ -43,9 +46,10 @@
  private:
   bool GetCrashpadHandlerPath(base::FilePath* handler_path);
   base::FilePath GetCrashpadDatabasePath();
+  void LogCrashReportInfo(const CrashReportDatabase::Report& report);
   bool InitializeCrashpadDatabase(base::FilePath database_path);
 
-  std::unique_ptr<crashpad::CrashReportDatabase> database_;
+  std::unique_ptr<CrashReportDatabase> database_;
 };
 
 CrashpadLinux::CrashpadLinux() = default;
@@ -64,18 +68,53 @@
   return database_path.Append(kChromotingCrashpadDatabasePath);
 }
 
+void CrashpadLinux::LogCrashReportInfo(
+    const CrashReportDatabase::Report& report) {
+  HOST_LOG << "  Crash id: " << report.id;
+  HOST_LOG << "    path: " << report.file_path;
+  HOST_LOG << "    uuid: " << report.uuid.ToString();
+  HOST_LOG << "    created: " << base::Time::FromTimeT(report.creation_time);
+  HOST_LOG << "    uploaded: " << (report.uploaded ? "yes" : "no")
+           << " (attempts: " << report.upload_attempts << ")";
+}
+
 bool CrashpadLinux::InitializeCrashpadDatabase(base::FilePath database_path) {
   base::File::Error error;
   if (!base::CreateDirectoryAndGetError(database_path, &error)) {
     LOG(ERROR) << "Unable to create crashpad database directory: " << error;
     return false;
   }
-  database_ = crashpad::CrashReportDatabase::Initialize(database_path);
+  database_ = CrashReportDatabase::Initialize(database_path);
   if (!database_) {
     LOG(ERROR) << "Failed to initialize database for Crashpad at "
                << database_path.value();
     return false;
   }
+
+  // Log the crash report ids.
+  CrashReportDatabase::OperationStatus status;
+  std::vector<CrashReportDatabase::Report> completed_reports;
+  status = database_->GetCompletedReports(&completed_reports);
+  if (status == CrashReportDatabase::OperationStatus::kNoError) {
+    HOST_LOG << "Completed crash reports: " << completed_reports.size();
+    for (const auto& report : completed_reports) {
+      LogCrashReportInfo(report);
+    }
+  } else {
+    LOG(ERROR) << "Unable to read completed crash reports: " << status;
+  }
+
+  std::vector<CrashReportDatabase::Report> pending_reports;
+  status = database_->GetPendingReports(&pending_reports);
+  if (status == CrashReportDatabase::OperationStatus::kNoError) {
+    HOST_LOG << "Pending crash reports: " << pending_reports.size();
+    for (const auto& report : pending_reports) {
+      LogCrashReportInfo(report);
+    }
+  } else {
+    LOG(ERROR) << "Unable to read pending crash reports: " << status;
+  }
+
   return true;
 }
 
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn b/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
index 820928b..c1a5250 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/BUILD.gn
@@ -17,8 +17,6 @@
     "tracing_observer.h",
     "tracing_observer_proto.cc",
     "tracing_observer_proto.h",
-    "tracing_observer_traced_value.cc",
-    "tracing_observer_traced_value.h",
   ]
 
   if (is_apple) {
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.cc
deleted file mode 100644
index a3b183a..0000000
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.cc
+++ /dev/null
@@ -1,167 +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.
-
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h"
-
-#include "base/files/file_path.h"
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/traced_value.h"
-#include "build/build_config.h"
-
-namespace memory_instrumentation {
-
-using base::trace_event::ProcessMemoryDump;
-using base::trace_event::TracedValue;
-
-namespace {
-
-void OsDumpAsValueInto(TracedValue* value, const mojom::OSMemDump& os_dump) {
-  value->SetString(
-      "private_footprint_bytes",
-      base::StringPrintf(
-          "%" PRIx64,
-          static_cast<uint64_t>(os_dump.private_footprint_kb) * 1024));
-  value->SetString(
-      "peak_resident_set_size",
-      base::StringPrintf(
-          "%" PRIx64,
-          static_cast<uint64_t>(os_dump.peak_resident_set_kb) * 1024));
-  value->SetBoolean("is_peak_rss_resettable", os_dump.is_peak_rss_resettable);
-}
-
-}  // namespace
-
-TracingObserverTracedValue::TracingObserverTracedValue(
-    base::trace_event::TraceLog* trace_log,
-    base::trace_event::MemoryDumpManager* memory_dump_manager) {}
-
-TracingObserverTracedValue::~TracingObserverTracedValue() = default;
-
-// static
-void TracingObserverTracedValue::AddToTrace(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::ProcessId pid,
-    std::unique_ptr<TracedValue> traced_value) {
-  CHECK_NE(base::trace_event::MemoryDumpType::kSummaryOnly, args.dump_type);
-
-  traced_value->SetString(
-      "level_of_detail",
-      base::trace_event::MemoryDumpLevelOfDetailToString(args.level_of_detail));
-  const uint64_t dump_guid = args.dump_guid;
-  const char* const event_name =
-      base::trace_event::MemoryDumpTypeToString(args.dump_type);
-  base::trace_event::TraceArguments trace_args("dumps",
-                                               std::move(traced_value));
-  TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
-      TRACE_EVENT_PHASE_MEMORY_DUMP,
-      base::trace_event::TraceLog::GetCategoryGroupEnabled(
-          base::trace_event::MemoryDumpManager::kTraceCategory),
-      event_name, trace_event_internal::kGlobalScope, dump_guid, pid,
-      &trace_args, TRACE_EVENT_FLAG_HAS_ID);
-}
-
-bool TracingObserverTracedValue::AddChromeDumpToTraceIfEnabled(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::ProcessId pid,
-    const ProcessMemoryDump* process_memory_dump,
-    const base::TimeTicks& timastamp) {
-  if (!ShouldAddToTrace(args))
-    return false;
-
-  std::unique_ptr<TracedValue> traced_value = std::make_unique<TracedValue>();
-  process_memory_dump->SerializeAllocatorDumpsInto(traced_value.get());
-
-  AddToTrace(args, pid, std::move(traced_value));
-
-  return true;
-}
-
-bool TracingObserverTracedValue::AddOsDumpToTraceIfEnabled(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::ProcessId pid,
-    const mojom::OSMemDump& os_dump,
-    const std::vector<mojom::VmRegionPtr>& memory_maps,
-    const base::TimeTicks& timestamp) {
-  if (!ShouldAddToTrace(args))
-    return false;
-
-  std::unique_ptr<TracedValue> traced_value = std::make_unique<TracedValue>();
-
-  traced_value->BeginDictionary("process_totals");
-  OsDumpAsValueInto(traced_value.get(), os_dump);
-  traced_value->EndDictionary();
-
-  if (memory_maps.size()) {
-    traced_value->BeginDictionary("process_mmaps");
-    MemoryMapsAsValueInto(memory_maps, traced_value.get(), false);
-    traced_value->EndDictionary();
-  }
-
-  AddToTrace(args, pid, std::move(traced_value));
-  return true;
-}
-
-// static
-void TracingObserverTracedValue::MemoryMapsAsValueInto(
-    const std::vector<mojom::VmRegionPtr>& memory_maps,
-    TracedValue* value,
-    bool is_argument_filtering_enabled) {
-  static const char kHexFmt[] = "%" PRIx64;
-
-  // Refer to the design doc goo.gl/sxfFY8 for the semantics of these fields.
-  value->BeginArray("vm_regions");
-  for (const auto& region : memory_maps) {
-    value->BeginDictionary();
-
-    value->SetString("sa", base::StringPrintf(kHexFmt, region->start_address));
-    value->SetString("sz", base::StringPrintf(kHexFmt, region->size_in_bytes));
-    if (region->module_timestamp)
-      value->SetString("ts",
-                       base::StringPrintf(kHexFmt, region->module_timestamp));
-    if (!region->module_debugid.empty())
-      value->SetString("id", region->module_debugid);
-    if (!region->module_debug_path.empty()) {
-      value->SetString("df", ApplyPathFiltering(region->module_debug_path,
-                                                is_argument_filtering_enabled));
-    }
-    value->SetInteger("pf", region->protection_flags);
-
-    // The module path will be the basename when argument filtering is
-    // activated. The whitelisting implemented for filtering string values
-    // doesn't allow rewriting. Therefore, a different path is produced here
-    // when argument filtering is activated.
-    value->SetString("mf", ApplyPathFiltering(region->mapped_file,
-                                              is_argument_filtering_enabled));
-
-// The following stats are only well defined on Linux-derived OSes.
-#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
-    value->BeginDictionary("bs");  // byte stats
-    value->SetString(
-        "pss",
-        base::StringPrintf(kHexFmt, region->byte_stats_proportional_resident));
-    value->SetString(
-        "pd",
-        base::StringPrintf(kHexFmt, region->byte_stats_private_dirty_resident));
-    value->SetString(
-        "pc",
-        base::StringPrintf(kHexFmt, region->byte_stats_private_clean_resident));
-    value->SetString(
-        "sd",
-        base::StringPrintf(kHexFmt, region->byte_stats_shared_dirty_resident));
-    value->SetString(
-        "sc",
-        base::StringPrintf(kHexFmt, region->byte_stats_shared_clean_resident));
-    value->SetString("sw",
-                     base::StringPrintf(kHexFmt, region->byte_stats_swapped));
-    value->EndDictionary();
-#endif
-
-    value->EndDictionary();
-  }
-  value->EndArray();
-}
-
-}  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h
deleted file mode 100644
index 7da8009..0000000
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h
+++ /dev/null
@@ -1,53 +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.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_TRACING_OBSERVER_TRACED_VALUE_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_TRACING_OBSERVER_TRACED_VALUE_H_
-
-#include "base/component_export.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/trace_event.h"
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h"
-#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
-
-namespace memory_instrumentation {
-
-// Version of TracingObserver that serialized the dump into a TracedValue
-class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION)
-    TracingObserverTracedValue : public TracingObserver {
- public:
-  TracingObserverTracedValue(base::trace_event::TraceLog*,
-                             base::trace_event::MemoryDumpManager*);
-
-  TracingObserverTracedValue(const TracingObserverTracedValue&) = delete;
-  TracingObserverTracedValue& operator=(const TracingObserverTracedValue&) =
-      delete;
-
-  ~TracingObserverTracedValue() override;
-
-  bool AddChromeDumpToTraceIfEnabled(
-      const base::trace_event::MemoryDumpRequestArgs&,
-      const base::ProcessId pid,
-      const base::trace_event::ProcessMemoryDump*,
-      const base::TimeTicks& timestamp) override;
-  bool AddOsDumpToTraceIfEnabled(
-      const base::trace_event::MemoryDumpRequestArgs&,
-      const base::ProcessId,
-      const mojom::OSMemDump&,
-      const std::vector<mojom::VmRegionPtr>&,
-      const base::TimeTicks& timastamp) override;
-
-  static void MemoryMapsAsValueInto(
-      const std::vector<mojom::VmRegionPtr>& memory_maps,
-      base::trace_event::TracedValue* value,
-      bool is_argument_filtering_enabled);
-
-  static void AddToTrace(const base::trace_event::MemoryDumpRequestArgs&,
-                         const base::ProcessId,
-                         std::unique_ptr<base::trace_event::TracedValue>);
-};
-
-}  // namespace memory_instrumentation
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_TRACING_OBSERVER_TRACED_VALUE_H_
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc
index 2c8a6c30..b72515909 100644
--- a/services/webnn/coreml/graph_builder_coreml.cc
+++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -3347,7 +3347,7 @@
 
   static constexpr char kForwardDirection[] = "forward";
   static constexpr char kBackwardDirection[] = "reverse";
-  static constexpr char kBothDirection[] = "both";
+  static constexpr char kBiDirectional[] = "bidirectional";
 
   uint32_t num_of_directions =
       direction == mojom::RecurrentNetworkDirection::kBoth ? 2 : 1;
@@ -3439,7 +3439,7 @@
       direction_param_value = kBackwardDirection;
       break;
     case mojom::RecurrentNetworkDirection::kBoth:
-      direction_param_value = kBothDirection;
+      direction_param_value = kBiDirectional;
       break;
   }
 
@@ -3612,10 +3612,11 @@
   } else {
     // Else, the first output of CoreML lstm is the output of the last step with
     // shape [1, batchSize, hiddenSize].
-    ASSIGN_OR_RETURN(uint64_t unused_second_output,
-                     GenerateInternalOperandInfo(
-                         data_type, base::span<const uint32_t>(
-                                        {1, batch_size, hidden_size})));
+    ASSIGN_OR_RETURN(
+        uint64_t unused_second_output,
+        GenerateInternalOperandInfo(
+            data_type, base::span<const uint32_t>(
+                           {1, batch_size, num_of_directions * hidden_size})));
     PopulateNamedValueType(unused_second_output, *op->add_outputs());
   }
 
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index e51e061..dbb8561 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -1834,6 +1834,15 @@
       // TODO(crbug.com/328733319): Support other tensor data types.
       CHECK(context_properties_.data_type_limits.conv2d_input.Has(
           input_data_type));
+
+      // TFLite internally performs a truncating cast. See crbug.com/384999508.
+      if (!base::IsValueInRangeForNumericType<int16_t>(
+              conv2d.dilations->height) ||
+          !base::IsValueInRangeForNumericType<int16_t>(
+              conv2d.dilations->width)) {
+        return base::unexpected(
+            "Dilation width and height must fit within the int16 range");
+      }
       break;
     case mojom::Conv2d::Kind::kTransposed:
       // TODO(crbug.com/328733319): Support other tensor data types.
@@ -1849,6 +1858,13 @@
       break;
   }
 
+  // TFLite internally performs a truncating cast. See crbug.com/384999508
+  if (!base::IsValueInRangeForNumericType<int16_t>(conv2d.strides->height) ||
+      !base::IsValueInRangeForNumericType<int16_t>(conv2d.strides->width)) {
+    return base::unexpected(
+        "Stride width and height must fit within the int16 range");
+  }
+
   // Get tflite padding mode with the size2d of input, filter, dilation.
   const auto& input_shape = input_operand.descriptor.shape();
   CHECK_EQ(input_shape.size(), 4u);
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6813f16..fdd626fc 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3632,6 +3632,26 @@
             ]
         }
     ],
+    "CSSReadingFlow": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CSSReadingFlow"
+                    ]
+                }
+            ]
+        }
+    ],
     "CVDisplayLinkBeginFrameSource": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 2849e8f..81a41e4 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 2849e8f11e55ee14df94af8d471e9149448c8f4a
+Subproject commit 81a41e4f10f960a290d89147c7a152fcd48f09a4
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 6b907f8a..31945ea 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -907,10 +907,6 @@
              "FledgeEnforceKAnonymity",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kFledgePassRecencyToGenerateBid,
-             "FledgePassRecencyToGenerateBid",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kFledgeSampleDebugReports,
              "FledgeSampleDebugReports",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 1077049..d6410d48 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -509,8 +509,6 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFledgeConsiderKAnonymity);
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFledgeEnforceKAnonymity);
 
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFledgePassRecencyToGenerateBid);
-
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFledgeSampleDebugReports);
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFledgeSplitTrustedSignalsFetchingURL);
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index e3ad8643..c0015dd 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -1553,15 +1553,23 @@
     return false;
   };
 
+  Animation::NativePaintWorkletReasons properties_for_force_update = 0;
+
   for (auto& entry : element_animations->Animations()) {
     Animation& animation = *entry.key;
     if (snapshot(animation.effect())) {
       update.UpdateCompositorKeyframes(&animation);
-    } else if (NativePaintImageGenerator::
-                   NativePaintWorkletAnimationsEnabled()) {
-      element_animations->RecalcCompositedStatusForKeyframeChange(
-          element, animation.effect());
     }
+    if (force_update) {
+      properties_for_force_update |= animation.GetNativePaintWorkletReasons();
+    }
+  }
+
+  if (properties_for_force_update !=
+      Animation::NativePaintWorkletProperties::kNoPaintWorklet) {
+    CHECK(NativePaintImageGenerator::NativePaintWorkletAnimationsEnabled());
+    element_animations->RecalcCompositedStatusForKeyframeChange(
+        element, properties_for_force_update);
   }
 
   for (auto& entry : element_animations->GetWorkletAnimations()) {
diff --git a/third_party/blink/renderer/core/animation/element_animations.cc b/third_party/blink/renderer/core/animation/element_animations.cc
index b1f3b32..8bba57f 100644
--- a/third_party/blink/renderer/core/animation/element_animations.cc
+++ b/third_party/blink/renderer/core/animation/element_animations.cc
@@ -95,33 +95,28 @@
 
 void ElementAnimations::RecalcCompositedStatusForKeyframeChange(
     Element& element,
-    AnimationEffect* effect) {
-  if (KeyframeEffect* keyframe_effect = DynamicTo<KeyframeEffect>(effect)) {
-    if (RuntimeEnabledFeatures::CompositeBGColorAnimationEnabled()) {
-      if (CompositedBackgroundColorStatus() ==
-              ElementAnimations::CompositedPaintStatus::kComposited &&
-          keyframe_effect->Affects(
-              PropertyHandle(GetCSSPropertyBackgroundColor())) &&
-          element.GetLayoutObject()) {
-        SetCompositedBackgroundColorStatus(
-            ElementAnimations::CompositedPaintStatus::kNeedsRepaint);
-        element.GetLayoutObject()->SetShouldDoFullPaintInvalidation();
-      }
-    }
-
-    if (RuntimeEnabledFeatures::CompositeClipPathAnimationEnabled()) {
-      if (CompositedClipPathStatus() ==
-              ElementAnimations::CompositedPaintStatus::kComposited &&
-          keyframe_effect->Affects(PropertyHandle(GetCSSPropertyClipPath())) &&
-          element.GetLayoutObject()) {
-        SetCompositedClipPathStatus(
-            ElementAnimations::CompositedPaintStatus::kNeedsRepaint);
-        element.GetLayoutObject()->SetShouldDoFullPaintInvalidation();
-        // For clip paths, we also need to update the paint properties to switch
-        // from path based to mask based clip.
-        element.GetLayoutObject()->SetNeedsPaintPropertyUpdate();
-      }
-    }
+    Animation::NativePaintWorkletReasons properties) {
+  if (!element.GetLayoutObject()) {
+    return;
+  }
+  if ((CompositedBackgroundColorStatus() ==
+       ElementAnimations::CompositedPaintStatus::kComposited) &&
+      (properties &
+       Animation::NativePaintWorkletProperties::kBackgroundColorPaintWorklet)) {
+    SetCompositedBackgroundColorStatus(
+        ElementAnimations::CompositedPaintStatus::kNeedsRepaint);
+    element.GetLayoutObject()->SetShouldDoFullPaintInvalidation();
+  }
+  if ((CompositedClipPathStatus() ==
+       ElementAnimations::CompositedPaintStatus::kComposited) &&
+      (properties &
+       Animation::NativePaintWorkletProperties::kClipPathPaintWorklet)) {
+    SetCompositedClipPathStatus(
+        ElementAnimations::CompositedPaintStatus::kNeedsRepaint);
+    element.GetLayoutObject()->SetShouldDoFullPaintInvalidation();
+    // For clip paths, we also need to update the paint properties to switch
+    // from path based to mask based clip.
+    element.GetLayoutObject()->SetNeedsPaintPropertyUpdate();
   }
 }
 
@@ -177,16 +172,4 @@
   return false;
 }
 
-bool ElementAnimations::HasAnimationForProperty(const CSSProperty& property) {
-  for (auto& entry : Animations()) {
-    KeyframeEffect* effect = DynamicTo<KeyframeEffect>(entry.key->effect());
-    if (effect && effect->Affects(PropertyHandle(property)) &&
-        (entry.key->CalculateAnimationPlayState() !=
-         V8AnimationPlayState::Enum::kIdle)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/element_animations.h b/third_party/blink/renderer/core/animation/element_animations.h
index 3171061..97a3d2c 100644
--- a/third_party/blink/renderer/core/animation/element_animations.h
+++ b/third_party/blink/renderer/core/animation/element_animations.h
@@ -118,8 +118,9 @@
 
   bool HasCompositedPaintWorkletAnimation();
 
-  void RecalcCompositedStatusForKeyframeChange(Element& element,
-                                               AnimationEffect* effect);
+  void RecalcCompositedStatusForKeyframeChange(
+      Element& element,
+      Animation::NativePaintWorkletReasons properties);
   void RecalcCompositedStatus(Element* element);
 
   // TODO(crbug.com/1301961): Consider converting to an array or flat map of
@@ -140,8 +141,6 @@
   void Trace(Visitor*) const override;
 
  private:
-  bool HasAnimationForProperty(const CSSProperty& property);
-
   EffectStack effect_stack_;
   CSSAnimations css_animations_;
   AnimationCountedSet animations_;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index a59bf33..7e240f7 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -8843,6 +8843,24 @@
   if (pseudo_id == kPseudoIdFirstLetter && IsSVGElement()) {
     return false;
   }
+  if (pseudo_id == kPseudoIdCheckMark) {
+    // We want to avoid the performance cost of generating the checkmark for
+    // old-style selects.  While it is technically needed only when we have an
+    // appearance:base picker, we condition it on an appearance:base button
+    // instead, since we can do that without re-entering style recalc.
+    auto is_option_in_appearance_base_select = [](const Element* e) {
+      if (const auto* option = DynamicTo<HTMLOptionElement>(e)) {
+        if (const HTMLSelectElement* select = option->OwnerSelectElement()) {
+          return select->IsAppearanceBaseButton(
+              HTMLSelectElement::StyleUpdateBehavior::kDontUpdateStyle);
+        }
+      }
+      return false;
+    };
+    if (!is_option_in_appearance_base_select(this)) {
+      return false;
+    }
+  }
   if (const ComputedStyle* style = GetComputedStyle()) {
     return style->CanGeneratePseudoElement(pseudo_id);
   }
diff --git a/third_party/blink/renderer/core/dom/element_test.cc b/third_party/blink/renderer/core/dom/element_test.cc
index 696723f..14803a5 100644
--- a/third_party/blink/renderer/core/dom/element_test.cc
+++ b/third_party/blink/renderer/core/dom/element_test.cc
@@ -1241,18 +1241,34 @@
 TEST_F(ElementTest, TheCheckMarkPseudoElement) {
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
-      #a-div::checkmark {
+      .checked::checkmark {
         content: "*";
       }
 
-      #target::checkmark {
-        content: "*";
+      .base-button {
+        appearance: base-select;
+      }
+
+      .base-picker::picker(select) {
+        appearance: base-select;
       }
     </style>
 
-    <div id="a-div"></div>
+    <div class="checked" id="a-div"></div>
 
-    <select id="target">
+    <select class="checked">
+      <option id="not-base-option" value="the only option"></option>
+    </select>
+
+    <select class="checked base-button">
+      <option id="base-button-option" value="the only option"></option>
+    </select>
+
+    <select class="checked base-picker">
+      <option id="base-picker-option" value="the only option"></option>
+    </select>
+
+    <select class="checked base-picker base-button" id="target">
       <option id="target-option" value="the only option"></option>
     </select>
     )HTML");
@@ -1260,16 +1276,19 @@
   // GetPseudoElement() relies on style recalc.
   GetDocument().UpdateStyleAndLayoutTree();
 
-  Element* div = GetElementById("a-div");
-  EXPECT_EQ(nullptr, div->GetPseudoElement(kPseudoIdCheckMark));
-
-  Element* target = GetElementById("target");
-  EXPECT_EQ(nullptr, target->GetPseudoElement(kPseudoIdCheckMark));
+  auto checkmark_pseudo_for = [this](const char* id) -> PseudoElement* {
+    Element* e = GetElementById(id);
+    return e->GetPseudoElement(kPseudoIdCheckMark);
+  };
 
   // The `::checkmark` pseudo element should only be created for option
-  // elements.
-  Element* target_option = GetElementById("target-option");
-  EXPECT_NE(nullptr, target_option->GetPseudoElement(kPseudoIdCheckMark));
+  // elements in an appearance:base-select.
+  EXPECT_EQ(nullptr, checkmark_pseudo_for("a-div"));
+  EXPECT_EQ(nullptr, checkmark_pseudo_for("not-base-option"));
+  EXPECT_NE(nullptr, checkmark_pseudo_for("base-button-option"));
+  EXPECT_EQ(nullptr, checkmark_pseudo_for("base-picker-option"));
+  EXPECT_EQ(nullptr, checkmark_pseudo_for("target"));
+  EXPECT_NE(nullptr, checkmark_pseudo_for("target-option"));
 }
 
 TEST_F(ElementTest, ThePickerIconPseudoElement) {
diff --git a/third_party/blink/renderer/core/frame/browser_controls_test.cc b/third_party/blink/renderer/core/frame/browser_controls_test.cc
index 6e50a41..af9ab7f 100644
--- a/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -33,6 +33,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
+#include "third_party/blink/public/common/page/page_zoom.h"
 #include "third_party/blink/public/web/web_element.h"
 #include "third_party/blink/public/web/web_settings.h"
 #include "third_party/blink/renderer/core/css/css_variable_data.h"
@@ -428,6 +429,20 @@
   EXPECT_EQ("30px", ResolveSafeAreaInsetsBottom());
 }
 
+TEST_F(BrowserControlsTest, SafeAreaInsetAccountsForBrowserZoom) {
+  ScopedDynamicSafeAreaInsetsForTest dynamic_safe_area_insets(true);
+
+  WebViewImpl* web_view = Initialize();
+  web_view->GetSettings()->SetDynamicSafeAreaInsetsEnabled(true);
+  SetSafeAreaInsets(GetFrame(), gfx::Insets().set_bottom(30));
+
+  web_view->MainFrameViewWidget()->SetZoomLevel(ZoomFactorToZoomLevel(2.0));
+  web_view->ResizeWithBrowserControls(web_view->MainFrameViewWidget()->Size(),
+                                      0, 50.f, true);
+  CompositeForTest();
+  EXPECT_EQ("15px", ResolveSafeAreaInsetsBottom());
+}
+
 // Scrolling up should show browser controls.
 TEST_F(BrowserControlsTest, MAYBE(ShowOnScrollUp)) {
   WebViewImpl* web_view = Initialize();
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 33ed2e7d..0c061e1 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -960,12 +960,9 @@
   if (new_scaled_safe_area != applied_safe_area_insets_ || force_update) {
     applied_safe_area_insets_ = new_scaled_safe_area;
 
-    // TODO: Need to account for the browser zoom factor here. Convert the
-    // safe area to CSS pixels instead of DIPs for SetSafeAreaEnvVariables().
-    float dip_scale = chrome_client_->GetScreenInfo(*DeprecatedLocalMainFrame())
-                          .device_scale_factor;
+    float zoom_factor = DeprecatedLocalMainFrame()->LayoutZoomFactor();
     gfx::Insets new_safe_area =
-        ToRoundedInsets(ScaleInsets(new_scaled_safe_area, 1.0f / dip_scale));
+        ToRoundedInsets(ScaleInsets(new_scaled_safe_area, 1.0f / zoom_factor));
     SetSafeAreaEnvVariables(DeprecatedLocalMainFrame(), new_safe_area);
   }
 }
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
index 28b531b2..bb9b068 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/animation/document_timeline.h"
 #include "third_party/blink/renderer/core/animation/element_animations.h"
 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
+#include "third_party/blink/renderer/core/animation/pending_animations.h"
 #include "third_party/blink/renderer/core/animation/string_keyframe.h"
 #include "third_party/blink/renderer/core/animation/timing.h"
 #include "third_party/blink/renderer/core/css/clip_path_paint_image_generator.h"
@@ -15,6 +16,7 @@
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/page/page_animator.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -249,4 +251,120 @@
   EXPECT_FALSE(lo->FirstFragment().PaintProperties()->ClipPathMask());
 }
 
+TEST_F(ClipPathPaintDefinitionTest,
+       NoInvalidationsOnPseudoWithTransformAnimation) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #target:after{
+        content:"";
+      }
+    </style>
+    <span id="target"></span>
+  )HTML");
+
+  Timing timing;
+  timing.iteration_duration = ANIMATION_TIME_DELTA_FROM_SECONDS(30);
+
+  CSSPropertyID property_id_cp = CSSPropertyID::kClipPath;
+  Persistent<StringKeyframe> start_keyframe_cp =
+      MakeGarbageCollected<StringKeyframe>();
+  start_keyframe_cp->SetCSSPropertyValue(
+      property_id_cp, "circle(50% at 50% 50%)",
+      SecureContextMode::kInsecureContext, nullptr);
+  Persistent<StringKeyframe> mid_keyframe_cp =
+      MakeGarbageCollected<StringKeyframe>();
+  mid_keyframe_cp->SetCSSPropertyValue(property_id_cp, "circle(50% at 50% 50%)",
+                                       SecureContextMode::kInsecureContext,
+                                       nullptr);
+  Persistent<StringKeyframe> end_keyframe_cp =
+      MakeGarbageCollected<StringKeyframe>();
+  end_keyframe_cp->SetCSSPropertyValue(property_id_cp, "circle(30% at 30% 30%)",
+                                       SecureContextMode::kInsecureContext,
+                                       nullptr);
+
+  StringKeyframeVector keyframes_cp;
+  keyframes_cp.push_back(start_keyframe_cp);
+  keyframes_cp.push_back(mid_keyframe_cp);
+  keyframes_cp.push_back(end_keyframe_cp);
+
+  auto* model_cp =
+      MakeGarbageCollected<StringKeyframeEffectModel>(keyframes_cp);
+  model_cp->SetComposite(EffectModel::kCompositeReplace);
+
+  CSSPropertyID property_id_tf = CSSPropertyID::kTransform;
+  Persistent<StringKeyframe> start_keyframe_tf =
+      MakeGarbageCollected<StringKeyframe>();
+  start_keyframe_tf->SetCSSPropertyValue(property_id_tf, "rotate(10deg)",
+                                         SecureContextMode::kInsecureContext,
+                                         nullptr);
+  Persistent<StringKeyframe> end_keyframe_tf =
+      MakeGarbageCollected<StringKeyframe>();
+  end_keyframe_tf->SetCSSPropertyValue(property_id_tf, "rotate(360deg)",
+                                       SecureContextMode::kInsecureContext,
+                                       nullptr);
+
+  StringKeyframeVector keyframes_tf;
+  keyframes_tf.push_back(start_keyframe_tf);
+  keyframes_tf.push_back(end_keyframe_tf);
+
+  auto* model_tf =
+      MakeGarbageCollected<StringKeyframeEffectModel>(keyframes_tf);
+  model_tf->SetComposite(EffectModel::kCompositeReplace);
+
+  Element* element_main = GetElementById("target");
+  Element* element_pseudo = To<Element>(element_main->PseudoAwareFirstChild());
+
+  NonThrowableExceptionState exception_state;
+  DocumentTimeline* timeline =
+      MakeGarbageCollected<DocumentTimeline>(&GetDocument());
+
+  Animation* animation_tf = Animation::Create(
+      MakeGarbageCollected<KeyframeEffect>(element_main, model_tf, timing),
+      timeline, exception_state);
+  animation_tf->play();
+
+  Animation* animation_cp = Animation::Create(
+      MakeGarbageCollected<KeyframeEffect>(element_pseudo, model_cp, timing),
+      timeline, exception_state);
+  animation_cp->play();
+
+  UpdateAllLifecyclePhasesForTest();
+
+  // Set up animations for ticking.
+
+  GetDocument().Timeline().ResetForTesting();
+  GetDocument().GetAnimationClock().UpdateTime(base::TimeTicks() +
+                                               base::Milliseconds(0));
+  animation_tf->NotifyReady(ANIMATION_TIME_DELTA_FROM_MILLISECONDS(0));
+
+  // Check for correct state on the first frame. In all cases this should be
+  // correct (basic behavior for the feature)
+
+  LayoutObject* lo = element_pseudo->GetLayoutObject();
+  EXPECT_TRUE(lo->FirstFragment().PaintProperties()->ClipPathMask());
+  EXPECT_TRUE(element_pseudo->GetElementAnimations());
+  EXPECT_EQ(element_pseudo->GetElementAnimations()->CompositedClipPathStatus(),
+            CompositedPaintStatus::kComposited);
+
+  // Run lifecycle again, and advance the animation time so that style
+  // invalidation occurs. In this case, the correct behavior is that the
+  // animation should be in steady-state. The transform animation on the root
+  // element should NOT cause invalidations for the pseudo.
+
+  GetDocument().GetAnimationClock().UpdateTime(base::TimeTicks() +
+                                               base::Milliseconds(250));
+  animation_tf->Update(kTimingUpdateForAnimationFrame);
+  GetDocument().GetPendingAnimations().Update(
+      GetDocument().GetFrame()->View()->GetPaintArtifactCompositor(), false);
+
+  GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
+      DocumentUpdateReason::kTest);
+  EXPECT_FALSE(lo->ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(lo->NeedsPaintPropertyUpdate());
+  EXPECT_EQ(element_pseudo->GetElementAnimations()->CompositedClipPathStatus(),
+            CompositedPaintStatus::kComposited);
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_TRUE(lo->FirstFragment().PaintProperties()->ClipPathMask());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index 9666afac7..49b03e421 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -860,9 +860,8 @@
     // Issue a copyTextureForBrowser call with internal usage turned on.
     // There is a special step for srcAlphaMode == wgpu::AlphaMode::Opaque that
     // clears alpha channel to one.
-    SkImageInfo sk_dst_image_info = resource_provider->GetSkImageInfo();
     wgpu::AlphaMode dstAlphaMode;
-    switch (sk_dst_image_info.alphaType()) {
+    switch (resource_provider->GetAlphaType()) {
       case SkAlphaType::kPremul_SkAlphaType:
         dstAlphaMode = wgpu::AlphaMode::Premultiplied;
         break;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 9e65c68c..16af590 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1744,6 +1744,10 @@
                      : gfx::ColorSpace::CreateSRGB();
 }
 
+SkAlphaType CanvasResourceProvider::GetAlphaType() const {
+  return GetSkImageInfo().alphaType();
+}
+
 std::optional<cc::PaintRecord> CanvasResourceProvider::FlushCanvas(
     FlushReason reason) {
   if (!recorder_->HasReleasableDrawOps()) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 238a8b5..af3c321 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -185,6 +185,7 @@
   const SkImageInfo& GetSkImageInfo() const { return info_; }
   SkSurfaceProps GetSkSurfaceProps() const;
   gfx::ColorSpace GetColorSpace() const;
+  SkAlphaType GetAlphaType() const;
   gfx::Size Size() const;
   virtual bool IsValid() const = 0;
   virtual bool IsAccelerated() const = 0;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 5976612f..ffdb083b1 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2755,10 +2755,6 @@
 crbug.com/382953502 external/wpt/webrtc/simulcast/setParameters-maxFramerate.https.html [ Skip Timeout ]
 crbug.com/382552065 [ Mac13 ] external/wpt/css/css-writing-modes/abs-pos-replaced-vrl-001.html [ Failure ]
 crbug.com/382552065 [ Mac14 ] external/wpt/css/css-writing-modes/abs-pos-replaced-vrl-001.html [ Failure ]
-[ Linux ] wpt_internal/css/css-images/img-view-box-contents-opaque.html [ Failure ]
-[ Mac13 ] wpt_internal/css/css-images/img-view-box-contents-opaque.html [ Failure ]
-[ Mac14 ] wpt_internal/css/css-images/img-view-box-contents-opaque.html [ Failure ]
-[ Mac15 ] wpt_internal/css/css-images/img-view-box-contents-opaque.html [ Failure ]
 crbug.com/382547589 [ Mac13 ] external/wpt/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html?1-2 [ Crash ]
 crbug.com/382521329 [ Linux ] external/wpt/pointerlock/pointerlock_without_gesture.html [ Crash Failure ]
 crbug.com/382302593 [ Win10.20h2 ] external/wpt/mathml/presentation-markup/fractions/frac-created-dynamically-4.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestLists/headless_shell.filter b/third_party/blink/web_tests/TestLists/headless_shell.filter
index 41342cb3..a1d2e8f 100644
--- a/third_party/blink/web_tests/TestLists/headless_shell.filter
+++ b/third_party/blink/web_tests/TestLists/headless_shell.filter
@@ -51,8 +51,6 @@
 -external/wpt/accname/name/comp_label.html
 -external/wpt/accname/name/comp_name_from_content.html
 -external/wpt/accname/name/comp_text_node.html
--external/wpt/acid/acid2/reftest.html
--external/wpt/apng/animated-png-timeout.html
 -external/wpt/background-fetch/abort.https.window.html
 -external/wpt/background-fetch/fetch.https.window.html
 -external/wpt/background-fetch/fetch-uploads.https.window.html
@@ -60,14 +58,11 @@
 -external/wpt/background-fetch/update-ui.https.window.html
 -external/wpt/battery-status/page-visibility.https.html
 -external/wpt/bluetooth/*
--external/wpt/client-hints/critical-ch/redirect.critical.cross-origin.multiple.https.window.html
--external/wpt/client-hints/critical-ch/redirect.cross-origin.https.window.html
--external/wpt/client-hints/viewport-size/viewport-size-*
+-external/wpt/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html
 -external/wpt/clipboard-apis/async-navigator-clipboard-write-multiple.tentative.https.sub.html
 -external/wpt/compat/webkit-box-clamp-bottom-border.html
 -external/wpt/compat/webkit-box-horizontal-rtl-variants.html
 -external/wpt/compat/webkit-box-rtl-flex.html
--external/wpt/compute-pressure/compute_pressure_disconnect_idempotent.https.window.html*
 -external/wpt/console/console-log-large-array.any.html
 -external/wpt/content-security-policy/reporting-api/*
 -external/wpt/content-security-policy/report-hash/*
@@ -151,13 +146,15 @@
 -external/wpt/css/CSS2/text/text-transform-bicameral-022.xht
 -external/wpt/css/CSS2/text/white-space-008.xht
 -external/wpt/css/CSS2/text/white-space-collapsing-breaks-001.xht
--external/wpt/css/css-anchor-position/anchor-center-scroll.html
 -external/wpt/css/css-anchor-position/anchor-getComputedStyle-002.html
--external/wpt/css/css-anchor-position/anchor-position-inline-002.html
--external/wpt/css/css-anchor-position/anchor-position-top-layer-003.html
--external/wpt/css/css-anchor-position/anchor-scroll-*
+-external/wpt/css/css-anchor-position/anchor-scroll-004.html
+-external/wpt/css/css-anchor-position/anchor-scroll-position-try-014.html
 -external/wpt/css/css-anchor-position/position-try-switch-from-fixed-anchor.html
--external/wpt/css/css-anchor-position/position-visibility-*
+-external/wpt/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in.html
+-external/wpt/css/css-anchor-position/position-visibility-anchors-visible-chained-004.html
+-external/wpt/css/css-anchor-position/position-visibility-anchors-visible-change-anchor.html
+-external/wpt/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container.html
+-external/wpt/css/css-anchor-position/position-visibility-remove-anchors-visible.html
 -external/wpt/css/css-backgrounds/background-attachment-fixed-block-002.html
 -external/wpt/css/css-backgrounds/background-attachment-fixed-inline-002.html
 -external/wpt/css/css-backgrounds/background-attachment-local-inline-002.html
@@ -181,8 +178,6 @@
 -external/wpt/css/css-borders/border-radius-greater-than-width.html
 # Known to be very flaky: https://crbug.com/377818367
 -external/wpt/css/css-break/*
--external/wpt/css/css-cascade/revert-val-006.html
--external/wpt/css/css-cascade/scope-implicit-crash-print.html
 -external/wpt/css/css-color/color-mix-basic-001.html
 -external/wpt/css/css-color/composited-filters-under-opacity.html
 -external/wpt/css/css-color/deprecated-sameas-010.html
@@ -275,9 +270,6 @@
 -external/wpt/css/css-fonts/system-ui-mixed.html
 -external/wpt/css/css-fonts/variations/at-font-face-font-matching.html
 -external/wpt/css/css-fonts/variations/variable-box-font.html
--external/wpt/css/css-grid/alignment/grid-baseline-001.html
--external/wpt/css/css-grid/alignment/grid-item-aspect-ratio-stretch-*
--external/wpt/css/css-grid/grid-items/anonymous-grid-item-001.html
 -external/wpt/css/css-highlight-api/highlight-text-across-elements.html
 -external/wpt/css/css-highlight-api/highlight-text-decorations.html
 -external/wpt/css/css-highlight-api/highlight-text.html
@@ -293,17 +285,15 @@
 -external/wpt/css/css-highlight-api/painting/custom-highlight-painting-prioritization-003.html
 -external/wpt/css/css-highlight-api/painting/custom-highlight-painting-text-decoration-001.html
 -external/wpt/css/css-highlight-api/painting/custom-highlight-painting-vertical-writing-mode-001.html
--external/wpt/css/css-images/cross-fade-*
--external/wpt/css/css-images/image-orientation/image-orientation-background-properties-border-radius.html
--external/wpt/css/css-images/object-fit-contain-png-001c.html
--external/wpt/css/css-images/object-fit-cover-svg-006e.html
--external/wpt/css/css-images/object-fit-fill-*
--external/wpt/css/css-images/object-view-box-fit-*
 -external/wpt/css/css-inline/baseline-source/baseline-source-first-textarea-002.tentative.html
 -external/wpt/css/css-inline/baseline-source/baseline-source-last-textarea-002.tentative.html
--external/wpt/css/css-inline/initial-letter/*
--external/wpt/css/css-inline/text-box-trim/text-box-trim-initial-letter-end-001.html
--external/wpt/css/css-inline/text-box-trim/text-box-trim-initial-letter-start-001.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-block-position-drop-over-ruby-tall.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-block-position-drop-under-ruby.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-block-position-margins-rtl.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-block-position-margins-vlr.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-block-position-margins-vrl.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-breaking-srl.html
+-external/wpt/css/css-inline/initial-letter/initial-letter-short-para-initial-letter-clears.html
 -external/wpt/css/css-layout-api/baseline/orthogonal-baseline.https.html
 -external/wpt/css/css-layout-api/fallback-intrinsic-sizes/constructor-error.https.html
 -external/wpt/css/css-layout-api/fallback-layout/constructor-error.https.html
@@ -315,20 +305,12 @@
 -external/wpt/css/css-lists/li-insert-child.html
 -external/wpt/css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001.html
 -external/wpt/css/css-lists/list-style-type-string-005b.html
--external/wpt/css/css-masking/clip-path/clip-path-*
--external/wpt/css/css-masking/mask-image/mask-image-3c.html
+-external/wpt/css/css-masking/clip-path/clip-path-inline-003.html
+-external/wpt/css/css-masking/clip-path/clip-path-inline-010.html
 -external/wpt/css/css-masking/mask-image/mask-opacity-1e.html
--external/wpt/css/css-masking/mask-svg-content/mask-with-rotation.svg
--external/wpt/css/css-multicol/auto-fill-auto-size-002-print.html
--external/wpt/css/css-multicol/baseline-000.html
--external/wpt/css/css-multicol/baseline-003.html
--external/wpt/css/css-multicol/baseline-004.html
--external/wpt/css/css-multicol/baseline-005.html
--external/wpt/css/css-multicol/baseline-006.html
--external/wpt/css/css-multicol/getclientrects-*
--external/wpt/css/css-multicol/multicol-height-002-print.xht
+-external/wpt/css/css-multicol/getclientrects-000.html
+-external/wpt/css/css-multicol/getclientrects-001.html
 -external/wpt/css/css-multicol/multicol-fill-auto-block-children-002.xht
--external/wpt/css/css-multicol/multicol-span-all-children-height-011.html
 -external/wpt/css/css-multicol/multicol-under-vertical-rl-scroll.html
 -external/wpt/css/css-multicol/multicol-width-ch-001.xht
 -external/wpt/css/css-multicol/table/table-cell-as-multicol.html
@@ -347,21 +329,51 @@
 -external/wpt/css/css-overflow/scrollable-overflow-input-002.html
 -external/wpt/css/css-overflow/scrollbar-gutter-*
 -external/wpt/css/css-overscroll-behavior/overscroll-behavior-root.html
--external/wpt/css/css-page/*
--external/wpt/css/css-paint-api/paint2d-composite.https.html
--external/wpt/css/css-paint-api/paint2d-filter.https.html
--external/wpt/css/css-paint-api/paint2d-transform.https.html
--external/wpt/css/css-paint-api/parse-input-arguments-*
--external/wpt/css/css-paint-api/registered-property-*
--external/wpt/css/css-paint-api/top-level-await.https.html
+-external/wpt/css/css-page/background-image-only-for-print.html
+-external/wpt/css/css-page/basic-pagination-003-print.html
+-external/wpt/css/css-page/body-background-slr-print.html
+-external/wpt/css/css-page/body-background-srl-print.html
+-external/wpt/css/css-page/body-background-vlr-print.html
+-external/wpt/css/css-page/body-background-vrl-print.html
+-external/wpt/css/css-page/margin-boxes/alignment-001-print.html
+-external/wpt/css/css-page/margin-boxes/background-001-print.html
+-external/wpt/css/css-page/margin-boxes/content-003-print.html
+-external/wpt/css/css-page/margin-boxes/content-004-print.html
+-external/wpt/css/css-page/margin-boxes/content-005-print.html
+-external/wpt/css/css-page/margin-boxes/content-006-print.html
+-external/wpt/css/css-page/margin-boxes/content-007-print.html
+-external/wpt/css/css-page/margin-boxes/content-008-print.html
+-external/wpt/css/css-page/margin-boxes/content-009-print.html
+-external/wpt/css/css-page/margin-boxes/content-010-print.html
+-external/wpt/css/css-page/margin-boxes/content-011-print.html
+-external/wpt/css/css-page/margin-boxes/content-012-print.html
+-external/wpt/css/css-page/margin-boxes/content-013-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-004-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-005-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-006-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-007-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-008-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-013-print.html
+-external/wpt/css/css-page/margin-boxes/dimensions-014-print.html
+-external/wpt/css/css-page/margin-boxes/inapplicable-properties-print.html
+-external/wpt/css/css-page/margin-boxes/paint-order-001-print.html
+-external/wpt/css/css-page/margin-boxes/paint-order-002-print.html
+-external/wpt/css/css-page/monolithic-overflow-024-print.html
+-external/wpt/css/css-page/monolithic-overflow-025-print.html
+-external/wpt/css/css-page/page-background-003-print.html
+-external/wpt/css/css-page/page-background-005-print.html
+-external/wpt/css/css-page/page-background-image-print.html
+-external/wpt/css/css-page/page-box-004-print.html
+-external/wpt/css/css-page/page-box-005-print.html
+-external/wpt/css/css-page/page-margin-001-print.html
+-external/wpt/css/css-page/page-margin-002-print.html
+-external/wpt/css/css-page/page-margin-003-print.html
+-external/wpt/css/css-page/page-margin-auto-print.html
+-external/wpt/css/css-paint-api/parse-input-arguments-018.https.html
 -external/wpt/css/css-position/hypothetical-box-scroll-parent.html
--external/wpt/css/css-position/overlay/overlay-transition-backdrop.html
--external/wpt/css/css-position/position-absolute-crash-chrome-001.html
 -external/wpt/css/css-position/position-absolute-iframe-print-001.sub.html
 -external/wpt/css/css-position/position-absolute-iframe-print-002.sub.html
--external/wpt/css/css-position/position-fixed-scroll-*
--external/wpt/css/css-position/sticky/*
--external/wpt/css/css-properties-values-api/animation/*
+-external/wpt/css/css-position/position-fixed-scroll-overlap.html
 -external/wpt/css/css-pseudo/active-selection-014.html
 -external/wpt/css/css-pseudo/before-after-dynamic-custom-property-001.html
 -external/wpt/css/css-pseudo/first-letter-001.html
@@ -395,8 +407,6 @@
 -external/wpt/css/css-pseudo/target-text-shadow-vertical.html
 -external/wpt/css/css-ruby/block-ruby-003.html
 -external/wpt/css/css-ruby/ruby-inlinize-recursive-simple.html
--external/wpt/css/css-ruby/ruby-reflow-001-transparentruby.html
--external/wpt/css/css-ruby/ruby-text-combine-upright-*
 -external/wpt/css/css-scoping/css-scoping-shadow-host-rule.html
 -external/wpt/css/css-scoping/css-scoping-shadow-root-hides-children.html
 -external/wpt/css/css-scoping/css-scoping-shadow-slotted-nested.html
@@ -1007,7 +1017,6 @@
 -external/wpt/webcodecs/videoFrame-construction.any.html
 -external/wpt/webcodecs/videoFrame-texImage.any.html
 -external/wpt/webcodecs/videoFrame-texImage.any.worker.html
--external/wpt/webgl/*
 -external/wpt/webrtc*
 -external/wpt/websockets/binary/004.html?wpt_flags=h2
 -external/wpt/websockets/Close-1000.any.html?wpt_flags=h2
@@ -1045,7 +1054,9 @@
 -external/wpt/webvtt/rendering/cues-with-video/processing-model/audio_has_no_subtitles.html
 -external/wpt/webvtt/rendering/cues-with-video/processing-model/embedded_style_media_queries_resized.html
 -external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/inherit_values_from_media_element.html
--external/wpt/webxr/*
+-external/wpt/webxr/dom-overlay/nested_fullscreen.https.html
+-external/wpt/webxr/xrSession_requestReferenceSpace_features.https.html
+-external/wpt/webxr/xr_viewport_scale.https.html
 -external/wpt/workers/baseurl/alpha/sharedworker-in-worker.html
 -external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.worker.html
 -external/wpt/workers/postMessage_block.https.html
@@ -1070,7 +1081,9 @@
 -virtual/dialog-close-when-open-removed-disabled/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-canceling.html
 -virtual/dialog-close-when-open-removed-disabled/external/wpt/html/semantics/interactive-elements/the-dialog-element/top-layer-stacking.tentative.html
 -virtual/dialog-light-dismiss-disabled/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-canceling.html
--virtual/direct-sockets/*
+-virtual/direct-sockets/external/wpt/direct-sockets/disabled-by-permissions-policy.https.sub.html
+-virtual/direct-sockets/external/wpt/direct-sockets/tcp_socket.https.html
+-virtual/direct-sockets/external/wpt/direct-sockets/udp_socket.https.html
 -virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-024.html
 -virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-025.html
 -virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-036.html
@@ -1098,7 +1111,6 @@
 -virtual/fenced-frame-mparch/external/wpt/fenced-frame/prerender.https.html
 -virtual/fenced-frame-mparch/external/wpt/fenced-frame/resize-lock*
 -virtual/fenced-frame-mparch/external/wpt/fenced-frame/window-outer-dimensions.https.html
--virtual/force-eager/*
 -virtual/fractional-scroll-offsets/external/wpt/css/css-position/sticky/position-sticky-hyperlink.html
 -virtual/fractional-scroll-offsets/external/wpt/css/css-position/sticky/position-sticky-inline.html
 -virtual/fractional-scroll-offsets/external/wpt/css/css-position/sticky/position-sticky-large-top*
@@ -1122,7 +1134,13 @@
 -virtual/keepalive-in-browser-migration/external/wpt/fetch/stale-while-revalidate/stale-*
 -virtual/main-thread-clip-path-animation/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-custom-timing-function.html
 -virtual/main-thread-clip-path-animation/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-fixed-position-rounding-error.html
--virtual/media-foundation-for-clear-dcomp/*
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/last-frame-dimensions.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/mediasource-config-change-mp4-v-bitrate.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/mediasource-config-change-mp4-v-framerate.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/mediasource-correct-frames-after-reappend.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/mediasource-correct-frames.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/mediasource-getvideoplaybackquality.html
+-virtual/media-foundation-for-clear-dcomp/external/wpt/media-source/SourceBuffer-short-frame-endOfStream.html
 -virtual/no-auto-wpt-origin-isolation/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-location-replace-set-src.html
 -virtual/no-auto-wpt-origin-isolation/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-form-submit.html
 -virtual/no-auto-wpt-origin-isolation/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-meta-refresh.optional.html
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 7516e24..8cc1088f 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1476,7 +1476,7 @@
       "external/wpt/fledge/tentative/server-response.https.window.js"
     ],
     "args": [
-      "--enable-features=EnableBandATriggeredUpdates,FledgeBiddingAndAuctionServer:FledgeBiddingAndAuctionKeyConfig/{\"https%3A%2F%2Fpublickeyservice.gcp.privacysandboxservices.com%22%3A%22https%3A%2F%2Fweb-platform.test%3A8444%2Ffledge%2Ftentative%2Fresources%2Fba-public-keys\"}"
+      "--enable-features=EnableBandATriggeredUpdates,FledgeBiddingAndAuctionServer:FledgeBiddingAndAuctionKeyConfig/{\"https%3A%2F%2Fweb-platform.test%22%3A%22https%3A%2F%2Fweb-platform.test%3A8444%2Ffledge%2Ftentative%2Fresources%2Fba-public-keys\"}"
     ],
     "expires": "Jan 14, 2025"
   },
@@ -1496,7 +1496,7 @@
       "external/wpt/fledge/tentative/server-response.https.window.js"
     ],
     "args": [
-      "--enable-features=FledgeConsiderKAnonymity,FledgeEnforceKAnonymity,EnableBandAKAnonEnforcement,EnableBandADealSupport,EnableBandATriggeredUpdates,FledgeBiddingAndAuctionServer:FledgeBiddingAndAuctionKeyConfig/{\"https%3A%2F%2Fpublickeyservice.gcp.privacysandboxservices.com%22%3A%22https%3A%2F%2Fweb-platform.test%3A8444%2Ffledge%2Ftentative%2Fresources%2Fba-public-keys\"}",
+      "--enable-features=FledgeConsiderKAnonymity,FledgeEnforceKAnonymity,EnableBandAKAnonEnforcement,EnableBandADealSupport,EnableBandATriggeredUpdates,FledgeBiddingAndAuctionServer:FledgeBiddingAndAuctionKeyConfig/{\"https%3A%2F%2Fweb-platform.test%22%3A%22https%3A%2F%2Fweb-platform.test%3A8444%2Ffledge%2Ftentative%2Fresources%2Fba-public-keys\"}",
       "--disable-features=CookieDeprecationFacilitatedTesting"
     ],
     "expires": "Jan 14, 2025"
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window.js
index 4a46c44..205391d 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window.js
@@ -28,12 +28,18 @@
 }
 
 subsetTest(promise_test, async test => {
-  const result = await navigator.getInterestGroupAdAuctionData({ seller: window.location.origin });
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length === 0);
 }, 'getInterestGroupAdAuctionData() with no interest groups returns a zero length result.');
 
 async function testInvalidConfig(test, configObj, desc) {
+  if (!configObj.coordinatorOrigin) {
+    configObj.coordinatorOrigin = await BA.configureCoordinator();
+  }
   await promise_rejects_js(
       test, TypeError, navigator.getInterestGroupAdAuctionData(configObj),
       desc);
@@ -84,6 +90,7 @@
 
   // These two actually succeed.
   let result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
     seller: 'https://example.org',
     perBuyerConfig:
         {'https://a.com': {targetSize: 400}, 'https://b.com': {targetSize: 500}}
@@ -91,6 +98,7 @@
   assert_true(result.requestId !== null);
 
   result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
     seller: 'https://example.org',
     perBuyerConfig: {'https://a.com': {targetSize: 400}, 'https://b.com': {}},
     requestSize: 5000
@@ -102,7 +110,10 @@
   const uuid = generateUuid(test);
   await joinInterestGroup(test, uuid);
 
-  const result = await navigator.getInterestGroupAdAuctionData({ seller: window.location.origin });
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -128,8 +139,10 @@
     ]
   });
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -154,8 +167,10 @@
     ]
   });
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -178,8 +193,10 @@
       test, uuid,
       {auctionServerRequestFlags: ['include-full-ads'], ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -253,8 +270,10 @@
   igConfig.auctionServerRequestFlags = ['include-full-ads'];
   await joinInterestGroup(test, uuid, igConfig);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -304,8 +323,10 @@
   const igConfig = makeTemplateIgConfig(uuid);
   await joinInterestGroup(test, uuid, igConfig);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -330,8 +351,10 @@
   igConfig.auctionServerRequestFlags = ['omit-user-bidding-signals'];
   await joinInterestGroup(test, uuid, igConfig);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -364,8 +387,10 @@
   await waitForObservedRequests(
       uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -424,8 +449,10 @@
   await waitForObservedRequests(
       uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -480,8 +507,10 @@
   await joinInterestGroup(test, uuid, {...igTemplate, name: 'first'});
   await joinInterestGroup(test, uuid, {...igTemplate, name: 'second'});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -516,8 +545,10 @@
   await joinCrossOriginIG(test, uuid, OTHER_ORIGIN3, 'o3');
   await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -548,6 +579,7 @@
   await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
 
   let config = {
+    coordinatorOrigin: await BA.configureCoordinator(),
     seller: window.location.origin,
     perBuyerConfig: {},
     requestSize: 5000
@@ -574,8 +606,10 @@
   const uuid = generateUuid(test);
   await joinInterestGroup(test, uuid);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_1-4-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_1-4-expected.txt
index 9e965c7..a9dc09c2 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_1-4-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_1-4-expected.txt
@@ -1,7 +1,11 @@
 This is a testharness.js-based test.
+[FAIL] getInterestGroupAdAuctionData() with no interest groups returns a zero length result.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
+[FAIL] getInterestGroupAdAuctionData() config checks
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() with one interest group returns a valid result.
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds.
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_13-16-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_13-16-expected.txt
index b9b5a95..b8f0dfd 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_13-16-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_13-16-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] getInterestGroupAdAuctionData() with multiple buyers
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() uses perBuyerConfig to select buyers
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() requests k-anon.
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_5-8-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_5-8-expected.txt
index 32f7a7b..a071d97 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_5-8-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_5-8-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and omit-ads.
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and include-full-ads.
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() all IG data fields, with include-full-ads
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() all IG data fields, w/o include-full-ads
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_9-12-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_9-12-expected.txt
index 3c6ea6f..c009c80 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_9-12-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/get-interest-group-auction-data.https.window_9-12-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] getInterestGroupAdAuctionData() all IG data fields, with omit-user-bidding-signals
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() browserSignals
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() browserSignals with include-full-ads
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] getInterestGroupAdAuctionData() with multiple interest groups
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/ba-fledge-util.sub.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/ba-fledge-util.sub.js
index 3aef43d..e03a4056c 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/ba-fledge-util.sub.js
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/ba-fledge-util.sub.js
@@ -360,4 +360,9 @@
   await fetch(authorizeURL, {adAuctionHeaders: true});
 };
 
+BA.configureCoordinator = async function() {
+  // This is async in hope it can eventually use testdriver to configure this.
+  return 'https://{{hosts[][]}}';
+}
+
 })(BA);
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js
index fa9defa..2205500d 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window.js
@@ -34,8 +34,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -74,8 +76,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -128,8 +132,10 @@
     biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true})
   });
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+      coordinatorOrigin: await BA.configureCoordinator(),
+      seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -189,8 +195,10 @@
     biddingLogicURL: createBiddingScriptURL({allowComponentAuction: true})
   });
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -261,8 +269,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -315,8 +325,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -357,8 +369,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result =
-      await navigator.getInterestGroupAdAuctionData({seller: OTHER_ORIGIN1});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: OTHER_ORIGIN1
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -395,8 +409,10 @@
       [{renderURL: adA, adRenderId: 'a'}, {renderURL: adB, adRenderId: 'b'}];
   await joinInterestGroup(test, uuid, {ads: adsArray});
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -440,8 +456,10 @@
   }
   await joinInterestGroup(test, uuid, ig);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -788,8 +806,10 @@
   }
   await joinInterestGroup(test, uuid, interestGroup);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
@@ -1141,8 +1161,10 @@
 
   await joinInterestGroup(test, uuid, ig);
 
-  const result = await navigator.getInterestGroupAdAuctionData(
-      {seller: window.location.origin});
+  const result = await navigator.getInterestGroupAdAuctionData({
+    coordinatorOrigin: await BA.configureCoordinator(),
+    seller: window.location.origin
+  });
   assert_true(result.requestId !== null);
   assert_true(result.request.length > 0);
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_1-4-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_1-4-expected.txt
index 912cf51..ad6191d3 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_1-4-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_1-4-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction with reporting URLs
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction with reporting URLs
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_13-16-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_13-16-expected.txt
index b3a7b12f..2482e257 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_13-16-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_13-16-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - nonsense error field
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - response marked as error, with message
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - response marked as error, with bad message
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - response marked as chaff
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_17-20-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_17-20-expected.txt
index 08f9dab..d2e5d60 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_17-20-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_17-20-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - response marked as non-chaff
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - incorrectly includes topLevelSeller
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - http:// topLevelSeller is bad, too
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - positive bid is good
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_21-24-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_21-24-expected.txt
index 6726fd0..4f80086 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_21-24-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_21-24-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - negative bid is bad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - zero bid is bad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - winning group did not bid
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - negative bidding group index
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_25-28-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_25-28-expected.txt
index 08f28e7..39ffe35 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_25-28-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_25-28-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - too large bidding group index
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - wrong IG name
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - left IG in the middle
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - ad URL not in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_29-32-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_29-32-expected.txt
index 566a552..e6d22fb 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_29-32-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_29-32-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - buyerReportingId not in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - buyerReportingId in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - buyerReportingId in wrong ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - buyerAndSellerReportingId not in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_33-36-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_33-36-expected.txt
index afe1513e..14e009d 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_33-36-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_33-36-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - buyerAndSellerReportingId in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - buyerAndSellerReportingId in wrong ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - ad component URL not in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - ad component URL in ad
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_37-40-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_37-40-expected.txt
index eac833c2..66fec79 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_37-40-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_37-40-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - loading winning component ads
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction --- beacon reporting
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - invalid ad currency
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - valid ad currency
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_41-44-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_41-44-expected.txt
index f2eb1034..bb4e2ae 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_41-44-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_41-44-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Hybrid B&A auction --- missing top-level seller
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- wrong top-level seller
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- no bid
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- currency check --- nothing configured
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_45-48-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_45-48-expected.txt
index 833500f..fe892c918b 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_45-48-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_45-48-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Hybrid B&A auction --- sellerCurrency mismatch
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- sellerCurrency config, no bidCurrency
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- top perBuyerCurrencies mismatch
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- perBuyerCurrencies config, no bidCurrency
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_49-52-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_49-52-expected.txt
index 8213579..f582b26 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_49-52-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_49-52-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Hybrid B&A auction --- bid info passed to top-level scoreAd
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- bid info passed to top-level reporting
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Hybrid B&A auction --- beacon reporting
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - updateIfOlderThanMs - invalid index
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_5-8-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_5-8-expected.txt
index bc9bfe1..3aca2fb 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_5-8-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_5-8-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - fault inject at CBOR
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - fault inject at gzip
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - fault inject at framing
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - fault inject at encryption
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_53-56-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_53-56-expected.txt
index b3f2427..2f0a4622 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_53-56-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_53-56-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - updateIfOlderThanMs
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - winner with candidates
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - winner with bad render hash
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - winner with bad reporting hash
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_57-60-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_57-60-expected.txt
index 66cede8..48d2125d 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_57-60-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_57-60-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - invalid ghost winner
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - only ghost winner
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - multiple ghost winners
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - second ghost winner invalid
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_61-64-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_61-64-expected.txt
index 2527d8d..e50d5c7 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_61-64-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_61-64-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - winner with ghost winner
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - invalid GhostWinnerForTopLevelAuction
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - winner with full ghost winner
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_9-12-expected.txt b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_9-12-expected.txt
index 716e2be..57e73bc5 100644
--- a/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_9-12-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/server-response.https.window_9-12-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] Basic B&A auction - Wrong authorization
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - Wrong seller
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - Wrong request Id
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 [FAIL] Basic B&A auction - response marked as error
-  assert_true: valid key Id expected true got false
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'getInterestGroupAdAuctionData' on 'Navigator': Invalid Coordinator"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
index eef85b0..0223abc 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
@@ -50,7 +50,7 @@
 
 
 const getLstmPrecisionTolerance = (graphResources) => {
-  const toleranceValueDict = {float32: 1, float16: 1};
+  const toleranceValueDict = {float32: 3, float16: 3};
   const expectedDataType =
       graphResources
           .expectedOutputs[Object.keys(graphResources.expectedOutputs)[0]]
@@ -867,6 +867,90 @@
     }
   },
   {
+    'name': 'lstm float32 tensors steps=2 with bidirections',
+    'graph': {
+      'inputs': {
+        'lstmInput': {
+          'data': [1, 2, 2, 1, 3, 4, 1, 2],
+          'descriptor': {shape: [2, 2, 2], dataType: 'float32'}
+        },
+        'lstmWeight': {
+          'data': [
+            1, -1, 2, -2, 1, -1, 2, -2, 1, -1, 2, -2, 1, -1, 2, -2,
+            1, -1, 2, -2, 1, -1, 2, -2, 1, -1, 2, -2, 1, -1, 2, -2
+          ],
+          'descriptor': {shape: [2, 8, 2], dataType: 'float32'},
+          'constant': true
+        },
+        'lstmRecurrentWeight': {
+          'data': [
+            0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
+            0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
+            0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1
+          ],
+          'descriptor': {shape: [2, 8, 2], dataType: 'float32'},
+          'constant': true
+        },
+        'lstmBias': {
+          'data': [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2],
+          'descriptor': {shape: [2, 8], dataType: 'float32'},
+          'constant': true
+        },
+        'lstmRecurrentBias': {
+          'data': [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2],
+          'descriptor': {shape: [2, 8], dataType: 'float32'},
+          'constant': true
+        }
+      },
+      'operators': [{
+        'name': 'lstm',
+        'arguments': [
+          {'input': 'lstmInput'}, {'weight': 'lstmWeight'},
+          {'recurrentWeight': 'lstmRecurrentWeight'}, {'steps': 2},
+          {'hiddenSize': 2}, {
+            'options': {
+              'bias': 'lstmBias',
+              'recurrentBias': 'lstmRecurrentBias',
+              'returnSequence': true,
+              'direction': 'both',
+              'layout': 'iofg'
+            }
+          }
+        ],
+        'outputs': ['lstmOutput1', 'lstmOutput2', 'lstmOutput3']
+      }],
+      'expectedOutputs': {
+        'lstmOutput1': {
+          'data': [
+            0.5764073133468628, 0.8236227035522461, 0.6612355709075928,
+            0.8442635536193848, 0.5764073133468628, 0.8236227035522461,
+            0.8635294437408447, 0.9491351246833801
+          ],
+          'descriptor': {shape: [2, 2, 2], dataType: 'float32'}
+        },
+        'lstmOutput2': {
+          'data': [
+            1.0171456336975098, 1.6205494403839111, 1.3388464450836182,
+            1.7642604112625122, 1.0171456336975098, 1.6205494403839111,
+            1.4856269359588623, 1.8449554443359375
+          ],
+          'descriptor': {shape: [2, 2, 2], dataType: 'float32'}
+        },
+        'lstmOutput3': {
+          'data': [
+            0.3696063756942749, 0.6082833409309387, 0.7037754058837891,
+            0.7586681246757507, 0.5764073133468628, 0.8236227035522461,
+            0.8635294437408447, 0.9491351246833801, 0.5764073133468628,
+            0.8236227035522461, 0.6612355709075928, 0.8442635536193848,
+            0.3696063756942749, 0.6082833409309387, 0.3696063756942749,
+            0.6082833409309387
+          ],
+          'descriptor': {shape: [2, 2, 2, 2], dataType: 'float32'}
+        }
+      }
+    }
+  },
+  {
     'name':
         'lstm float16 tensors steps=1 with options.bias, options.recurrentBias',
     'graph': {
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt
index 03965bd..5db05e0 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-input-value-expected.txt
@@ -47,7 +47,7 @@
             childNodeIndexes : [
                 [0] : 4
                 [1] : 5
-                [2] : 44
+                [2] : 42
             ]
             layoutNodeIndex : 2
             nodeName : BODY
@@ -71,21 +71,21 @@
             childNodeIndexes : [
                 [0] : 6
                 [1] : 7
-                [2] : 24
-                [3] : 25
-                [4] : 28
-                [5] : 29
-                [6] : 31
-                [7] : 32
-                [8] : 33
-                [9] : 34
-                [10] : 35
-                [11] : 36
-                [12] : 37
-                [13] : 38
-                [14] : 39
-                [15] : 40
-                [16] : 43
+                [2] : 22
+                [3] : 23
+                [4] : 26
+                [5] : 27
+                [6] : 29
+                [7] : 30
+                [8] : 31
+                [9] : 32
+                [10] : 33
+                [11] : 34
+                [12] : 35
+                [13] : 36
+                [14] : 37
+                [15] : 38
+                [16] : 41
             ]
             layoutNodeIndex : 3
             nodeName : DIV
@@ -103,9 +103,9 @@
             childNodeIndexes : [
                 [0] : 8
                 [1] : 10
-                [2] : 19
-                [3] : 20
-                [4] : 22
+                [2] : 17
+                [3] : 18
+                [4] : 20
             ]
             layoutNodeIndex : 4
             nodeName : SELECT
@@ -147,7 +147,7 @@
             backendNodeId : <number>
             childNodeIndexes : [
                 [0] : 11
-                [1] : 15
+                [1] : 14
             ]
             nodeName : SLOT
             nodeType : 1
@@ -163,40 +163,30 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 13
+                [0] : 12
             ]
             nodeName : OPTION
             nodeType : 1
             nodeValue : 
             optionSelected : true
-            pseudoElementIndexes : [
-                [0] : 12
-            ]
         }
         [12] : {
             backendNodeId : <number>
-            nodeName : ::checkmark
-            nodeType : 1
-            nodeValue : 
-            pseudoType : checkmark
-        }
-        [13] : {
-            backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 14
+                [0] : 13
             ]
             nodeName : SLOT
             nodeType : 1
             nodeValue : 
             shadowRootType : user-agent
         }
-        [14] : {
+        [13] : {
             backendNodeId : <number>
             nodeName : #text
             nodeType : 3
             nodeValue : Option 1
         }
-        [15] : {
+        [14] : {
             attributes : [
                 [0] : {
                     name : id
@@ -205,40 +195,30 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 17
+                [0] : 15
             ]
             nodeName : OPTION
             nodeType : 1
             nodeValue : 
             optionSelected : false
-            pseudoElementIndexes : [
-                [0] : 16
-            ]
         }
-        [16] : {
-            backendNodeId : <number>
-            nodeName : ::checkmark
-            nodeType : 1
-            nodeValue : 
-            pseudoType : checkmark
-        }
-        [17] : {
+        [15] : {
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 18
+                [0] : 16
             ]
             nodeName : SLOT
             nodeType : 1
             nodeValue : 
             shadowRootType : user-agent
         }
-        [18] : {
+        [16] : {
             backendNodeId : <number>
             nodeName : #text
             nodeType : 3
             nodeValue : Option 2
         }
-        [19] : {
+        [17] : {
             attributes : [
                 [0] : {
                     name : id
@@ -251,7 +231,7 @@
             nodeValue : 
             shadowRootType : user-agent
         }
-        [20] : {
+        [18] : {
             attributes : [
                 [0] : {
                     name : pseudo
@@ -264,6 +244,39 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
+                [0] : 19
+            ]
+            nodeName : DIV
+            nodeType : 1
+            nodeValue : 
+            shadowRootType : user-agent
+        }
+        [19] : {
+            attributes : [
+                [0] : {
+                    name : id
+                    value : select-popover-options
+                }
+            ]
+            backendNodeId : <number>
+            nodeName : SLOT
+            nodeType : 1
+            nodeValue : 
+            shadowRootType : user-agent
+        }
+        [20] : {
+            attributes : [
+                [0] : {
+                    name : popover
+                    value : manual
+                }
+                [1] : {
+                    name : pseudo
+                    value : -internal-select-autofill-preview
+                }
+            ]
+            backendNodeId : <number>
+            childNodeIndexes : [
                 [0] : 21
             ]
             nodeName : DIV
@@ -274,39 +287,6 @@
         [21] : {
             attributes : [
                 [0] : {
-                    name : id
-                    value : select-popover-options
-                }
-            ]
-            backendNodeId : <number>
-            nodeName : SLOT
-            nodeType : 1
-            nodeValue : 
-            shadowRootType : user-agent
-        }
-        [22] : {
-            attributes : [
-                [0] : {
-                    name : popover
-                    value : manual
-                }
-                [1] : {
-                    name : pseudo
-                    value : -internal-select-autofill-preview
-                }
-            ]
-            backendNodeId : <number>
-            childNodeIndexes : [
-                [0] : 23
-            ]
-            nodeName : DIV
-            nodeType : 1
-            nodeValue : 
-            shadowRootType : user-agent
-        }
-        [23] : {
-            attributes : [
-                [0] : {
                     name : pseudo
                     value : -internal-select-autofill-preview-text
                 }
@@ -317,14 +297,14 @@
             nodeValue : 
             shadowRootType : user-agent
         }
-        [24] : {
+        [22] : {
             backendNodeId : <number>
             layoutNodeIndex : 7
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [25] : {
+        [23] : {
             attributes : [
                 [0] : {
                     name : id
@@ -337,7 +317,7 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 26
+                [0] : 24
             ]
             inputValue : InputValue
             isClickable : true
@@ -346,10 +326,10 @@
             nodeType : 1
             nodeValue : 
         }
-        [26] : {
+        [24] : {
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 27
+                [0] : 25
             ]
             isClickable : true
             layoutNodeIndex : 9
@@ -358,7 +338,7 @@
             nodeValue : 
             shadowRootType : user-agent
         }
-        [27] : {
+        [25] : {
             backendNodeId : <number>
             isClickable : true
             layoutNodeIndex : 10
@@ -367,14 +347,14 @@
             nodeValue : InputValue
             shadowRootType : user-agent
         }
-        [28] : {
+        [26] : {
             backendNodeId : <number>
             layoutNodeIndex : 11
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [29] : {
+        [27] : {
             attributes : [
                 [0] : {
                     name : id
@@ -391,7 +371,7 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 30
+                [0] : 28
             ]
             inputValue : ButtonValue
             isClickable : true
@@ -400,7 +380,7 @@
             nodeType : 1
             nodeValue : 
         }
-        [30] : {
+        [28] : {
             backendNodeId : <number>
             layoutNodeIndex : 13
             nodeName : #text
@@ -408,14 +388,14 @@
             nodeValue : ButtonValue
             shadowRootType : user-agent
         }
-        [31] : {
+        [29] : {
             backendNodeId : <number>
             layoutNodeIndex : 14
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [32] : {
+        [30] : {
             attributes : [
                 [0] : {
                     name : id
@@ -443,14 +423,14 @@
             nodeType : 1
             nodeValue : 
         }
-        [33] : {
+        [31] : {
             backendNodeId : <number>
             layoutNodeIndex : 16
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [34] : {
+        [32] : {
             attributes : [
                 [0] : {
                     name : id
@@ -470,14 +450,14 @@
             nodeType : 1
             nodeValue : 
         }
-        [35] : {
+        [33] : {
             backendNodeId : <number>
             layoutNodeIndex : 18
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [36] : {
+        [34] : {
             attributes : [
                 [0] : {
                     name : id
@@ -505,14 +485,14 @@
             nodeType : 1
             nodeValue : 
         }
-        [37] : {
+        [35] : {
             backendNodeId : <number>
             layoutNodeIndex : 20
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [38] : {
+        [36] : {
             attributes : [
                 [0] : {
                     name : id
@@ -536,14 +516,14 @@
             nodeType : 1
             nodeValue : 
         }
-        [39] : {
+        [37] : {
             backendNodeId : <number>
             layoutNodeIndex : 22
             nodeName : #text
             nodeType : 3
             nodeValue :    
         }
-        [40] : {
+        [38] : {
             attributes : [
                 [0] : {
                     name : id
@@ -552,7 +532,7 @@
             ]
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 41
+                [0] : 39
             ]
             layoutNodeIndex : 23
             nodeName : TEXTAREA
@@ -560,10 +540,10 @@
             nodeValue : 
             textValue : TextAreaValue
         }
-        [41] : {
+        [39] : {
             backendNodeId : <number>
             childNodeIndexes : [
-                [0] : 42
+                [0] : 40
             ]
             isClickable : true
             layoutNodeIndex : 24
@@ -572,7 +552,7 @@
             nodeValue : 
             shadowRootType : user-agent
         }
-        [42] : {
+        [40] : {
             backendNodeId : <number>
             isClickable : true
             layoutNodeIndex : 25
@@ -581,14 +561,14 @@
             nodeValue : TextAreaValue
             shadowRootType : user-agent
         }
-        [43] : {
+        [41] : {
             backendNodeId : <number>
             layoutNodeIndex : 26
             nodeName : #text
             nodeType : 3
             nodeValue :  
         }
-        [44] : {
+        [42] : {
             backendNodeId : <number>
             nodeName : #text
             nodeType : 3
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
similarity index 81%
rename from third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
rename to third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
similarity index 81%
copy from third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
copy to third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_gpu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
new file mode 100644
index 0000000..e53dd3b2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+[FAIL] lstm float32 tensors steps=2 with all options
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+[FAIL] lstm float32 tensors steps=2 with bidirections
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
new file mode 100644
index 0000000..e53dd3b2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+[FAIL] lstm float32 tensors steps=2 with all options
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+[FAIL] lstm float32 tensors steps=2 with bidirections
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
index 9e73a70..e53dd3b2 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_cpu-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+[FAIL] lstm float32 tensors steps=2 with bidirections
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
index 9e73a70..e53dd3b2 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+[FAIL] lstm float32 tensors steps=2 with bidirections
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
deleted file mode 100644
index 9e73a70..0000000
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_npu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any.worker_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
index 9e73a70..4f2fe75 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 1 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque-ref.html
index 2bc965e..383aded 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque-ref.html
@@ -1,7 +1,8 @@
-<!-- This is an autogen file. Run support/generate_object_view_box_tests.py to update -->
 <!DOCTYPE html>
+<html class="reftest-wait">
 <title>Image opaqueness with CSS object-view-box and object-position (ref)</title>
 <link rel="author" href="mailto:szager@chromium.org">
+<script src="/common/reftest-wait.js"></script>
 
 <body>
 <style>
@@ -77,5 +78,6 @@
   for (let i = 0; i < images.length; i++) {
     images[i].src = url;
   }
+  takeScreenshot();
 });
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque.html b/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque.html
index d14db5f..57d8356 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-images/img-view-box-contents-opaque.html
@@ -1,7 +1,9 @@
 <!DOCTYPE html>
+<html class="reftest-wait">
 <title>Image opaqueness with CSS object-view-box and object-position</title>
 <link rel="author" href="mailto:szager@chromium.org">
 <link rel="match" href="img-view-box-contents-opaque-ref.html">
+<script src="/common/reftest-wait.js"></script>
 
 <body>
 <style>
@@ -53,5 +55,6 @@
   for (let i = 0; i < images.length; i++) {
     images[i].src = url;
   }
+  takeScreenshot();
 });
 </script>
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index be21ef7..cf6dc5d 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit be21ef7012f0812bb1c0c8fc226979fa6c301e8d
+Subproject commit cf6dc5d38385e4ff6faf9bf0883a67c2f511076b
diff --git a/third_party/catapult b/third_party/catapult
index 415e0f1..9b526439 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 415e0f1c10d3de8ba78aff15ca6dfe71f0b04d9e
+Subproject commit 9b526439504cb5f2465696b807faa8c5459bdd63
diff --git a/third_party/ink/BUILD.gn b/third_party/ink/BUILD.gn
index 7df6ac4..9428acc 100644
--- a/third_party/ink/BUILD.gn
+++ b/third_party/ink/BUILD.gn
@@ -58,10 +58,10 @@
     "src/ink/geometry/mesh_format.cc",
     "src/ink/geometry/mesh_format.h",
     "src/ink/geometry/mesh_packing_types.h",
-    "src/ink/geometry/modeled_shape.cc",
-    "src/ink/geometry/modeled_shape.h",
     "src/ink/geometry/mutable_mesh.cc",
     "src/ink/geometry/mutable_mesh.h",
+    "src/ink/geometry/partitioned_mesh.cc",
+    "src/ink/geometry/partitioned_mesh.h",
     "src/ink/geometry/point.cc",
     "src/ink/geometry/point.h",
     "src/ink/geometry/quad.cc",
diff --git a/third_party/ink/README.chromium b/third_party/ink/README.chromium
index ad01d0c..540ca1e 100644
--- a/third_party/ink/README.chromium
+++ b/third_party/ink/README.chromium
@@ -1,7 +1,7 @@
 Name: Ink
 URL: https://github.com/google/ink.git
 Version: N/A
-Revision: 4300dc7402a257b85fc5bf2559137edacb050227
+Revision: e5673a4ff2d82f29b22f7bec114161cbc1ff8cf8
 License: Apache-2.0
 License File: LICENSE
 Shipped: yes
diff --git a/third_party/ink/src b/third_party/ink/src
index d21aa58..e5673a4 160000
--- a/third_party/ink/src
+++ b/third_party/ink/src
@@ -1 +1 @@
-Subproject commit d21aa587baa20f9db3dba2007e314f1c29351d10
+Subproject commit e5673a4ff2d82f29b22f7bec114161cbc1ff8cf8
diff --git a/third_party/libc++/src b/third_party/libc++/src
index 175bf00..ec4ac17 160000
--- a/third_party/libc++/src
+++ b/third_party/libc++/src
@@ -1 +1 @@
-Subproject commit 175bf00303d0747baa158072cf7a2755ab1fbe88
+Subproject commit ec4ac17a44a46b162c28d38f313f157f76236a6c
diff --git a/third_party/libwebp/BUILD.gn b/third_party/libwebp/BUILD.gn
index 58f7bf5..7a25c1a 100644
--- a/third_party/libwebp/BUILD.gn
+++ b/third_party/libwebp/BUILD.gn
@@ -187,6 +187,9 @@
     ":libwebp_utils",
     ":libwebp_webp",
   ]
+  if (use_dsp_neon) {
+    deps += [ ":libwebp_dsp_neon" ]
+  }
   public_deps = [ ":libwebp_dsp_headers" ]
   if (is_android) {
     deps += [ "//third_party/cpu_features:ndk_compat" ]
@@ -202,6 +205,9 @@
     ":libwebp_dsp_sse41",
     ":libwebp_utils",
   ]
+  if (use_dsp_neon) {
+    allow_circular_includes_from += [ ":libwebp_dsp_neon" ]
+  }
 }
 
 static_library("libwebp_dsp_sse41") {
@@ -288,7 +294,7 @@
 
     deps = [
       ":libwebp_dec",
-      ":libwebp_dsp",
+      ":libwebp_dsp_headers",
       ":libwebp_enc",
       ":libwebp_utils",
     ]
@@ -542,9 +548,6 @@
   ]
   public_deps = [ ":libwebp_webp" ]
   public_configs = [ ":libwebp_public_config" ]
-  if (use_dsp_neon) {
-    deps += [ ":libwebp_dsp_neon" ]
-  }
 }
 
 ###############################################################################
@@ -712,90 +715,114 @@
 ################################################################################
 # Fuzzers
 
-fuzzer_test("libwebp_simple_api_fuzzer") {
-  sources = [ "src/tests/fuzzer/simple_api_fuzzer.c" ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
+source_set("libwebp_fuzz_utils") {
+  public = [ "src/tests/fuzzer/fuzz_utils.h" ]
+  sources = [ "src/tests/fuzzer/fuzz_utils.cc" ]
+  testonly = true
+  configs += [ ":libwebp_config" ]
   deps = [
-    ":libwebp",
+    ":libwebp_dsp_headers",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
   ]
-  defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_advanced_api_fuzzer") {
-  sources = [ "src/tests/fuzzer/advanced_api_fuzzer.c" ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
+test("libwebp_simple_api_fuzzer") {
+  sources = [ "src/tests/fuzzer/simple_api_fuzzer.cc" ]
   deps = [
     ":libwebp",
+    ":libwebp_fuzz_utils",
+    ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
+  ]
+  defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
+  configs += [ ":libwebp_config" ]
+}
+
+test("libwebp_advanced_api_fuzzer") {
+  sources = [ "src/tests/fuzzer/advanced_api_fuzzer.cc" ]
+  deps = [
+    ":libwebp_dec",
+    ":libwebp_dsp",
+    ":libwebp_fuzz_utils",
     ":libwebp_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
   defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_animation_api_fuzzer") {
+test("libwebp_animation_api_fuzzer") {
   sources = [
     "src/src/demux/anim_decode.c",
-    "src/tests/fuzzer/animation_api_fuzzer.c",
+    "src/tests/fuzzer/animation_api_fuzzer.cc",
   ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
   deps = [
     ":libwebp",
+    ":libwebp_fuzz_utils",
     ":libwebp_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
   defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_mux_demux_api_fuzzer") {
-  sources = [ "src/tests/fuzzer/mux_demux_api_fuzzer.c" ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
+test("libwebp_mux_demux_api_fuzzer") {
+  sources = [ "src/tests/fuzzer/mux_demux_api_fuzzer.cc" ]
   deps = [
     ":libwebp",
+    ":libwebp_fuzz_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
   defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_animencoder_fuzzer") {
+test("libwebp_animencoder_fuzzer") {
   sources = [ "src/tests/fuzzer/animencoder_fuzzer.cc" ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
   deps = [
     ":libwebp",
+    ":libwebp_dsp_headers",
+    ":libwebp_fuzz_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
   defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_enc_dec_api_fuzzer") {
+test("libwebp_enc_dec_api_fuzzer") {
   sources = [ "src/tests/fuzzer/enc_dec_fuzzer.cc" ]
-  dict = "src/tests/fuzzer/fuzz.dict"
-  seed_corpus = "fuzzing/fuzz_seed_corpus"
   deps = [
     ":libwebp",
+    ":libwebp_dsp_headers",
+    ":libwebp_fuzz_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
   defines = [ "WEBP_MAX_IMAGE_SIZE=838860800" ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
 
-fuzzer_test("libwebp_huffman_fuzzer") {
-  sources = [ "src/tests/fuzzer/huffman_fuzzer.c" ]
+test("libwebp_huffman_fuzzer") {
+  sources = [ "src/tests/fuzzer/huffman_fuzzer.cc" ]
   deps = [
     ":libwebp",
     ":libwebp_dec",
+    ":libwebp_fuzz_utils",
     ":libwebp_utils",
     ":libwebp_webp",
+    "//third_party/fuzztest:fuzztest",
+    "//third_party/fuzztest:fuzztest_gtest_main",
   ]
-  additional_configs = [ ":libwebp_config" ]
+  configs += [ ":libwebp_config" ]
 }
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index b54da91..ceb6f97 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -2,8 +2,8 @@
 Short Name: libwebp
 URL: https://chromium.googlesource.com/webm/libwebp
 Version: N/A
-Revision: 845d5476a866141ba35ac133f856fa62f0b7445f
-CPEPrefix: cpe:/a:webmproject:libwebp:1.4.0
+Revision: 2af6c034ac871c967e04c8c9f8bf2dbc2e271b18
+CPEPrefix: cpe:/a:webmproject:libwebp:1.5.0
 License: BSD-3-Clause, Patent
 License File: src/COPYING, src/PATENTS
 Security Critical: Yes
diff --git a/third_party/libwebp/src b/third_party/libwebp/src
index 845d547..2af6c03 160000
--- a/third_party/libwebp/src
+++ b/third_party/libwebp/src
@@ -1 +1 @@
-Subproject commit 845d5476a866141ba35ac133f856fa62f0b7445f
+Subproject commit 2af6c034ac871c967e04c8c9f8bf2dbc2e271b18
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index ca233e8..2222607 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit ca233e8056f91e3f1b2cb3d17efa88b3ae6fb15d
+Subproject commit 2222607a3ea3d5f65338d3b36a4cc5fb563169ab
diff --git a/third_party/skia b/third_party/skia
index a15d02f..a38c4ae 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit a15d02f7757e95b700aea3f53e7ee8c3305bae1c
+Subproject commit a38c4ae0287a1d6d4a57db85b8b52c0d43965deb
diff --git a/tools/clang/scripts/upload_revision.py b/tools/clang/scripts/upload_revision.py
index 589bdd1a..2cf6bd3 100755
--- a/tools/clang/scripts/upload_revision.py
+++ b/tools/clang/scripts/upload_revision.py
@@ -81,7 +81,8 @@
 Cq-Include-Trybots: chrome/try:iphone-device,ipad-device
 Cq-Include-Trybots: chrome/try:linux-chromeos-chrome
 Cq-Include-Trybots: chrome/try:win-chrome,win64-chrome,linux-chrome,mac-chrome
-Cq-Include-Trybots: chrome/try:linux-pgo,mac-pgo,win32-pgo,win64-pgo'''
+Cq-Include-Trybots: chrome/try:linux-pgo,mac-pgo,win32-pgo,win64-pgo
+Cq-Include-Trybots: luci.chromium.try:linux-cast-x64-rel'''
 
 RUST_BOTS = \
 '''Cq-Include-Trybots: chromium/try:android-rust-arm32-rel
diff --git a/tools/metrics/histograms/metadata/accessibility/enums.xml b/tools/metrics/histograms/metadata/accessibility/enums.xml
index 931f9d7..e109fd789 100644
--- a/tools/metrics/histograms/metadata/accessibility/enums.xml
+++ b/tools/metrics/histograms/metadata/accessibility/enums.xml
@@ -177,6 +177,60 @@
 
 <!-- LINT.ThenChange(//components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomUma.java:AccessibilityPageZoomUsageType) -->
 
+<!-- LINT.IfChange(AccessibilityPredicateType)-->
+
+<enum name="AccessibilityPredicateType">
+  <summary>
+    Tracks the type of predicate used during next html element navigation on
+    Android.
+  </summary>
+  <int value="0" label="UNKNOWN"/>
+  <int value="1" label="DEFAULT"/>
+  <int value="2" label="Article"/>
+  <int value="3" label="BlockQuote"/>
+  <int value="4" label="Button"/>
+  <int value="5" label="Checkbox"/>
+  <int value="6" label="Combobox"/>
+  <int value="7" label="Control"/>
+  <int value="8" label="Focusable"/>
+  <int value="9" label="Frame"/>
+  <int value="10" label="Graphic"/>
+  <int value="11" label="H1"/>
+  <int value="12" label="H2"/>
+  <int value="13" label="H3"/>
+  <int value="14" label="H4"/>
+  <int value="15" label="H5"/>
+  <int value="16" label="H6"/>
+  <int value="17" label="Heading"/>
+  <int value="18" label="Heading Same"/>
+  <int value="19" label="Landmark"/>
+  <int value="20" label="Link"/>
+  <int value="21" label="List"/>
+  <int value="22" label="ListItem"/>
+  <int value="23" label="Live"/>
+  <int value="24" label="Main"/>
+  <int value="25" label="Media"/>
+  <int value="26" label="Paragraph"/>
+  <int value="27" label="Radio"/>
+  <int value="28" label="RadioGroup"/>
+  <int value="29" label="Section"/>
+  <int value="30" label="Table"/>
+  <int value="31" label="TextField"/>
+  <int value="32" label="Text Bold"/>
+  <int value="33" label="Text Italic"/>
+  <int value="34" label="Text Underline"/>
+  <int value="35" label="Tree"/>
+  <int value="36" label="Unvisited Link"/>
+  <int value="37" label="Visited Link"/>
+  <int value="38" label="Row"/>
+  <int value="39" label="Column"/>
+  <int value="40" label="Row Bounds"/>
+  <int value="41" label="Column Bounds"/>
+  <int value="42" label="Table Bounds"/>
+</enum>
+
+<!-- LINT.ThenChange(//content/browser/accessibility/web_contents_accessibility_android.cc:AccessibilityPredicateType) -->
+
 <!-- LINT.IfChange(AccessibilityTreeUnserializeError) -->
 
 <enum name="AccessibilityTreeUnserializeError">
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 348d8086..f7c41e7 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -146,6 +146,27 @@
   </summary>
 </histogram>
 
+<histogram name="Accessibility.Android.FindElementType.Usage.{RunningATs}"
+    enum="AccessibilityPredicateType" expires_after="2025-04-14">
+  <owner>mschillaci@google.com</owner>
+  <owner>lucasradaelli@google.com</owner>
+  <owner>chrome-a11y-core@chromium.org</owner>
+  <summary>
+    Tracks the type of element that a user navigates by in the web contents when
+    the Android Framework calls performAction with the ACTION_NEXT_HTML_ELEMENT
+    action. This is tracked during the tree search for the next/previous
+    element. This occured with: {RunningATs}
+  </summary>
+  <token key="RunningATs">
+    <variant name="NotTalkBackAT"
+        summary="AT(s) running that are not TalkBack."/>
+    <variant name="OnlyTalkBackRunning"
+        summary="TalkBack as the only running AT."/>
+    <variant name="TalkBackRunningWithOtherAT"
+        summary="TalkBack running along with another AT."/>
+  </token>
+</histogram>
+
 <histogram name="Accessibility.Android.InlineTextBoxes.Bundle.{CallLocation}"
     enum="AccessibilityModeBundleEnum" expires_after="2025-04-14">
   <owner>mschillaci@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 0f3abe62..57f2b64e 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -156,6 +156,7 @@
   <variant name="ToggleClipboardHistory"/>
   <variant name="ToggleDictation"/>
   <variant name="ToggleDockedMagnifier"/>
+  <variant name="ToggleDoNotDisturb"/>
   <variant name="ToggleFloating"/>
   <variant name="ToggleFullscreen"/>
   <variant name="ToggleFullscreenMagnifier"/>
diff --git a/tools/metrics/histograms/metadata/chromeos/enums.xml b/tools/metrics/histograms/metadata/chromeos/enums.xml
index eda4529..0d2593f 100644
--- a/tools/metrics/histograms/metadata/chromeos/enums.xml
+++ b/tools/metrics/histograms/metadata/chromeos/enums.xml
@@ -190,6 +190,7 @@
   <int value="136" label="ToggleMouseKeys"/>
   <int value="137" label="ResizePipWindow"/>
   <int value="138" label="ToggleGeminiApp"/>
+  <int value="139" label="ToggleDoNotDisturb"/>
   <int value="9000" label="DebugClearUseKMeansPref"/>
   <int value="9001" label="DebugKeyboardBacklightToggle"/>
   <int value="9002" label="DebugMicrophoneMuteToggle"/>
@@ -1229,6 +1230,7 @@
   <int value="22" label="Dictation"/>
   <int value="23" label="PrivacyScreenToggle"/>
   <int value="24" label="Accessibility"/>
+  <int value="25" label="DoNotDisturb"/>
 </enum>
 
 <enum name="KeyboardTopRowLayoutWithExtraSublayout">
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml
index dc6ed44f..dc4b66c 100644
--- a/tools/metrics/histograms/metadata/history/histograms.xml
+++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -2253,6 +2253,16 @@
   </summary>
 </histogram>
 
+<histogram name="History.Embeddings.Passages.TitleInserted" enum="Boolean"
+    expires_after="2025-07-31">
+  <owner>orinj@chromium.org</owner>
+  <owner>src/components/history_embeddings/OWNERS</owner>
+  <summary>
+    Whether a dedicated web contents title passage was inserted at the beginning
+    of the extracted passages vector. Logged each time passages are extracted.
+  </summary>
+</histogram>
+
 <histogram name="History.Embeddings.Passages.TotalTextSize" units="bytes"
     expires_after="2025-07-31">
   <owner>orinj@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/enums.xml b/tools/metrics/histograms/metadata/navigation/enums.xml
index 656ca991..6ef84e6 100644
--- a/tools/metrics/histograms/metadata/navigation/enums.xml
+++ b/tools/metrics/histograms/metadata/navigation/enums.xml
@@ -353,6 +353,13 @@
   <int value="1" label="Requires dedicated process"/>
 </enum>
 
+<enum name="NavigationStartAdjustmentType">
+  <int value="0" label="No adjustment made"/>
+  <int value="1" label="Legacy PostTask without BeforeUnload"/>
+  <int value="2" label="BeforeUnload handlers without dialog"/>
+  <int value="3" label="BeforeUnload dialog shown"/>
+</enum>
+
 <enum name="NavigationSuddenTerminationDisabler">
   <int value="0" label="Subframe-None"/>
   <int value="1" label="MainFrame-None"/>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index c900729..8d52088 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -2057,6 +2057,81 @@
   <token key="FrameType" variants="FrameTypes"/>
 </histogram>
 
+<histogram name="Navigation.StartAdjustment"
+    enum="NavigationStartAdjustmentType" expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records whether an adjustment was made to the navigation start time, and
+    what the reason was if so. This metric is recorded each time a navigation
+    finishes.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.BeforeUnloadDialog" units="ms"
+    expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records how many milliseconds the navigation start time was delayed, in
+    cases where it was adjusted to after a beforeunload dialog was displayed.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.BeforeUnloadDialog.Percentage"
+    units="%" expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records the percentage of navigation time that was ignored, in cases where
+    the start time was adjusted to after a beforeunload dialog was displayed.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.BeforeUnloadHandlers" units="ms"
+    expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records how many milliseconds the navigation start time was delayed, in
+    cases where it was adjusted to after beforeunload handlers ran, when no
+    dialog was displayed.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.BeforeUnloadHandlers.Percentage"
+    units="%" expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records the percentage of navigation time that was ignored, in cases where
+    the start time was adjusted to after beforeunload handlers ran, when no
+    dialog was displayed.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.LegacyPostTask" units="ms"
+    expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records how many milliseconds the navigation start time was delayed, in
+    cases where it was adjusted to after a legacy PostTask was run, when no
+    beforeunload handlers were registered.
+  </summary>
+</histogram>
+
+<histogram name="Navigation.StartAdjustment.LegacyPostTask.Percentage"
+    units="%" expires_after="2025-12-20">
+  <owner>creis@chromium.org</owner>
+  <owner>alexmos@chromium.org</owner>
+  <summary>
+    Records the percentage of navigation time that was ignored, in cases where
+    the start time was adjusted to after a legacy PostTask was run, when no
+    beforeunload handlers were registered.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.StartToCommit" units="ms"
     expires_after="2025-06-01">
   <owner>nasko@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 0fd5dfea..b5de9e1 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "perfetto-luci-artifacts/5bf4e2a65d76d5a603ff175222d1513f71d28a0b/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "672028f024121da789a1eeb995347fc5eb39a64e",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/f4aab84374ce3a5a90ee72f9dbd54572cf758682/trace_processor_shell.exe"
+            "hash": "fd3e40af5ed15794b4ce050d6ec096527f245753",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/1e7633eb8271449051555e5b8f6488c6e0189dd0/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "e250187786aa190a66288bc9443a5e1f5888f8d7",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "0a0eaa928585335d4dd653c07ced18595eb0b7c3",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d0fbd4a2d0e1b565bf4c5a4e11d53113457bc293/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/1e7633eb8271449051555e5b8f6488c6e0189dd0/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/android/java/src/org/chromium/ui/accessibility/AccessibilityState.java b/ui/accessibility/android/java/src/org/chromium/ui/accessibility/AccessibilityState.java
index 3728f29..c70fac0e 100644
--- a/ui/accessibility/android/java/src/org/chromium/ui/accessibility/AccessibilityState.java
+++ b/ui/accessibility/android/java/src/org/chromium/ui/accessibility/AccessibilityState.java
@@ -25,6 +25,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.util.Pair;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.autofill.AutofillManager;
@@ -801,15 +802,24 @@
     }
 
     /**
-     * Returns true when one of the running services is TalkBack based on list of service ids. This
-     * should not be used commonly, and is meant for identifying state while tracking metrics for
-     * performance improvements.
+     * Checks the current enabled state of TalkBack. TalkBack can either be disabled, enabled with
+     * other services running, or be the only enabled service.
+     *
+     * @return A {@link Pair} where the first boolean indicates whether or not TalkBack is enabled
+     *     at all, and the second boolean indicates whether or not TalkBack is the only running
+     *     accessibility service.
      */
-    public static boolean isTalkBackEnabled() {
+    public static Pair<Boolean, Boolean> getTalkBackEnabledState() {
         if (!sInitialized) updateAccessibilityServices();
-        return sServiceIds != null
-                && !sServiceIds.isEmpty()
-                && sServiceIds.contains(TALKBACK_SERVICE_ID);
+        if (sServiceIds == null || sServiceIds.isEmpty()) {
+            return new Pair<Boolean, Boolean>(false, false);
+        }
+
+        boolean isTalkBackEnabled = sServiceIds.contains(TALKBACK_SERVICE_ID);
+        boolean isOnlyOneServiceEnabled = sServiceIds.size() == 1;
+
+        return new Pair<Boolean, Boolean>(
+                isTalkBackEnabled, isTalkBackEnabled && isOnlyOneServiceEnabled);
     }
 
     /**
diff --git a/ui/base/accelerators/accelerator_manager_unittest.cc b/ui/base/accelerators/accelerator_manager_unittest.cc
index 1ef0b45..0ed99c1c 100644
--- a/ui/base/accelerators/accelerator_manager_unittest.cc
+++ b/ui/base/accelerators/accelerator_manager_unittest.cc
@@ -4,13 +4,9 @@
 
 #include "ui/base/accelerators/accelerator_manager.h"
 
-#include <array>
-
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/accelerators/test_accelerator_target.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -175,10 +171,6 @@
 #if BUILDFLAG(IS_CHROMEOS)
 
 TEST_F(AcceleratorManagerTest, PositionalShortcuts_AllEqual) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kImprovedKeyboardShortcuts);
-
   // Use a local instance so that the feature is enabled during construction.
   AcceleratorManager manager;
   manager.SetUsePositionalLookup(true);
@@ -197,10 +189,6 @@
 }
 
 TEST_F(AcceleratorManagerTest, PositionalShortcuts_MatchingDomCode) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kImprovedKeyboardShortcuts);
-
   // Use a local instance so that the feature is enabled during construction.
   AcceleratorManager manager;
   manager.SetUsePositionalLookup(true);
@@ -220,10 +208,6 @@
 }
 
 TEST_F(AcceleratorManagerTest, PositionalShortcuts_NotMatchingDomCode) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kImprovedKeyboardShortcuts);
-
   // Use a local instance so that the feature is enabled during construction.
   AcceleratorManager manager;
   manager.SetUsePositionalLookup(true);
@@ -244,10 +228,6 @@
 }
 
 TEST_F(AcceleratorManagerTest, PositionalShortcuts_NonPositionalMatch) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kImprovedKeyboardShortcuts);
-
   // Use a local instance so that the feature is enabled during construction.
   AcceleratorManager manager;
   manager.SetUsePositionalLookup(true);
@@ -268,10 +248,6 @@
 }
 
 TEST_F(AcceleratorManagerTest, PositionalShortcuts_NonPositionalNonMatch) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kImprovedKeyboardShortcuts);
-
   // Use a local instance so that the feature is enabled during construction.
   AcceleratorManager manager;
   manager.SetUsePositionalLookup(true);
diff --git a/ui/base/accelerators/accelerator_unittest.cc b/ui/base/accelerators/accelerator_unittest.cc
index bc08a75b..2d4d0c2 100644
--- a/ui/base/accelerators/accelerator_unittest.cc
+++ b/ui/base/accelerators/accelerator_unittest.cc
@@ -7,10 +7,8 @@
 #include <string>
 
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/event.h"
 #include "ui/events/types/event_type.h"
 
@@ -139,10 +137,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 TEST(AcceleratorTest, ConversionFromKeyEvent_Ash) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      ::features::kImprovedKeyboardShortcuts);
-
   ui::KeyEvent key_event(ui::EventType::kKeyPressed, ui::VKEY_F,
                          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN);
   Accelerator accelerator(key_event);
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index f80e2096..5e7dc1b 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -82,14 +82,6 @@
   return base::FeatureList::IsEnabled(kNotificationsIgnoreRequireInteraction);
 }
 
-BASE_FEATURE(kShortcutCustomization,
-             "ShortcutCustomization",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-bool IsShortcutCustomizationEnabled() {
-  return base::FeatureList::IsEnabled(kShortcutCustomization);
-}
-
 // Enables settings that allow users to remap the F11 and F12 keys in the
 // "Customize keyboard keys" page.
 BASE_FEATURE(kSupportF11AndF12KeyShortcuts,
@@ -252,13 +244,7 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 #if BUILDFLAG(IS_CHROMEOS)
-// This feature supersedes kNewShortcutMapping.
-BASE_FEATURE(kImprovedKeyboardShortcuts,
-             "ImprovedKeyboardShortcuts",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 bool IsImprovedKeyboardShortcutsEnabled() {
-#if BUILDFLAG(IS_CHROMEOS)
   // TODO(crbug.com/40203434): Remove this once kDeviceI18nShortcutsEnabled
   // policy is deprecated.
   if (::ui::ShortcutMappingPrefDelegate::IsInitialized()) {
@@ -268,9 +254,7 @@
       return instance->IsI18nShortcutPrefEnabled();
     }
   }
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-  return base::FeatureList::IsEnabled(kImprovedKeyboardShortcuts);
+  return true;
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index 90c73ab..cbfe3d2 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -61,8 +61,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 COMPONENT_EXPORT(UI_BASE_FEATURES)
-BASE_DECLARE_FEATURE(kImprovedKeyboardShortcuts);
-COMPONENT_EXPORT(UI_BASE_FEATURES)
 bool IsImprovedKeyboardShortcutsEnabled();
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
@@ -104,12 +102,6 @@
 bool IsNotificationsIgnoreRequireInteractionEnabled();
 
 COMPONENT_EXPORT(UI_BASE_FEATURES)
-BASE_DECLARE_FEATURE(kShortcutCustomization);
-
-COMPONENT_EXPORT(UI_BASE_FEATURES)
-bool IsShortcutCustomizationEnabled();
-
-COMPONENT_EXPORT(UI_BASE_FEATURES)
 BASE_DECLARE_FEATURE(kSupportF11AndF12KeyShortcuts);
 
 COMPONENT_EXPORT(UI_BASE_FEATURES) bool AreF11AndF12ShortcutsEnabled();
diff --git a/ui/events/ash/keyboard_capability.cc b/ui/events/ash/keyboard_capability.cc
index 9ec5d843..4c6836ea 100644
--- a/ui/events/ash/keyboard_capability.cc
+++ b/ui/events/ash/keyboard_capability.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 "ui/events/ash/top_row_action_keys.h"
 #ifdef UNSAFE_BUFFERS_BUILD
 // TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
 #pragma allow_unsafe_buffers
@@ -126,6 +127,7 @@
         {VKEY_DICTATE, TopRowActionKey::kDictation},
         {VKEY_PRIVACY_SCREEN_TOGGLE, TopRowActionKey::kPrivacyScreenToggle},
         {VKEY_ACCESSIBILITY, TopRowActionKey::kAccessibility},
+        {VKEY_DO_NOT_DISTURB, TopRowActionKey::kDoNotDisturb},
     });
 
 // Some ChromeOS compatible keyboards have a capslock key.
diff --git a/ui/events/ash/keyboard_capability_unittest.cc b/ui/events/ash/keyboard_capability_unittest.cc
index 4933b9c1..3bdd69e 100644
--- a/ui/events/ash/keyboard_capability_unittest.cc
+++ b/ui/events/ash/keyboard_capability_unittest.cc
@@ -24,6 +24,7 @@
 #include "ui/events/ash/mojom/meta_key.mojom-shared.h"
 #include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
 #include "ui/events/ash/mojom/modifier_key.mojom.h"
+#include "ui/events/ash/top_row_action_keys.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/device_data_manager_test_api.h"
 #include "ui/events/devices/input_device.h"
@@ -1288,6 +1289,7 @@
       case TopRowActionKey::kAllApplications:
       case TopRowActionKey::kEmojiPicker:
       case TopRowActionKey::kDictation:
+      case TopRowActionKey::kDoNotDisturb:
       case TopRowActionKey::kUnknown:
       case TopRowActionKey::kNone:
         return 0;
diff --git a/ui/events/ash/top_row_action_keys.h b/ui/events/ash/top_row_action_keys.h
index 0450324..31bdb654 100644
--- a/ui/events/ash/top_row_action_keys.h
+++ b/ui/events/ash/top_row_action_keys.h
@@ -35,7 +35,8 @@
   TOP_ROW_ACTION_KEYS_ENTRY(EmojiPicker)             \
   TOP_ROW_ACTION_KEYS_ENTRY(Dictation)               \
   TOP_ROW_ACTION_KEYS_ENTRY(PrivacyScreenToggle)     \
-  TOP_ROW_ACTION_KEYS_LAST_ENTRY(Accessibility)
+  TOP_ROW_ACTION_KEYS_ENTRY(Accessibility)           \
+  TOP_ROW_ACTION_KEYS_LAST_ENTRY(DoNotDisturb)
 
 enum class TopRowActionKey {
 #define TOP_ROW_ACTION_KEYS_ENTRY(top_row_key) k##top_row_key,
diff --git a/ui/events/keycodes/dom/dom_code_data.inc b/ui/events/keycodes/dom/dom_code_data.inc
index c2ae80e..0b76559a 100644
--- a/ui/events/keycodes/dom/dom_code_data.inc
+++ b/ui/events/keycodes/dom/dom_code_data.inc
@@ -110,6 +110,8 @@
   DOM_CODE(0x010082, 0x008e, 0x0096, 0xe05f, 0xffff, "Sleep", SLEEP), // SystemSleep
   DOM_CODE(0x010083, 0x008f, 0x0097, 0xe063, 0xffff, "WakeUp", WAKE_UP),
   DOM_CODE(0x010097, 0x01d0, 0x01d8, 0x0000, 0xffff, "Fn", FN),
+  DOM_CODE(0x01009b, 0x024f, 0x0257, 0x0000, 0xffff, NULL,
+             DO_NOT_DISTURB), // System Do Not Disturb
   DOM_CODE(0x0100a9, 0x00f8, 0x0100, 0x0000, 0xffff, NULL,
              MICROPHONE_MUTE_TOGGLE),  // Microphone Mute Toggle
   DOM_CODE(0x0100aa, 0x024e, 0x0256, 0x0000, 0xffff, NULL,
diff --git a/ui/events/keycodes/dom/keycode_converter_unittest.cc b/ui/events/keycodes/dom/keycode_converter_unittest.cc
index d16724f..0123c0a 100644
--- a/ui/events/keycodes/dom/keycode_converter_unittest.cc
+++ b/ui/events/keycodes/dom/keycode_converter_unittest.cc
@@ -30,8 +30,8 @@
 // These are in the same order as the columns in dom_code_data.inc
 // as reflected in the DOM_CODE() macro below.
 const auto expected_mapped_key_count = std::to_array<size_t>({
-    223,  // evdev
-    223,  // xkb
+    224,  // evdev
+    224,  // xkb
     157,  // windows
     119,  // mac
 });
diff --git a/ui/events/keycodes/dom_us_layout_data.h b/ui/events/keycodes/dom_us_layout_data.h
index 5147dff..7a421769 100644
--- a/ui/events/keycodes/dom_us_layout_data.h
+++ b/ui/events/keycodes/dom_us_layout_data.h
@@ -423,10 +423,14 @@
     // DomCode::WAKE_UP                            0x010083 WakeUp
 #if BUILDFLAG(IS_CHROMEOS)
     {DomCode::FN, VKEY_FUNCTION},  // 0x010097 Fn
+    {DomCode::DO_NOT_DISTURB,
+     VKEY_DO_NOT_DISTURB},  // 0x01009B System Do Not Disturb
 #endif
 #if BUILDFLAG(IS_POSIX)
     {DomCode::MICROPHONE_MUTE_TOGGLE,
      VKEY_MICROPHONE_MUTE_TOGGLE},  // 0x0100A9 MicrophoneMuteToggle
+#endif
+#if BUILDFLAG(IS_CHROMEOS)
     {DomCode::ACCESSIBILITY,
      VKEY_ACCESSIBILITY},  // 0x0100AA System Accessibility Binding
 #endif
diff --git a/ui/events/keycodes/keyboard_codes_posix.h b/ui/events/keycodes/keyboard_codes_posix.h
index 1074c5f58..0c42c95 100644
--- a/ui/events/keycodes/keyboard_codes_posix.h
+++ b/ui/events/keycodes/keyboard_codes_posix.h
@@ -259,12 +259,13 @@
 #if BUILDFLAG(IS_CHROMEOS)
   VKEY_FUNCTION = 0xFF,
   VKEY_QUICK_INSERT = 0x100,
-#endif
 
   // System Accessibility Binding.
   VKEY_ACCESSIBILITY = 0x101,
 
-#if BUILDFLAG(IS_CHROMEOS)
+  // System Do Not Disturb Toggle.
+  VKEY_DO_NOT_DISTURB = 0x102,
+
   // The following values are used to be able to recognize button events within
   // ChromeOS. They have no functionality by default.
   VKEY_BUTTON_0 = 0xFF00,
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
index 1c8dfe8..8a52d8bf 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
@@ -836,7 +836,6 @@
       {{DomCode::EMOJI_PICKER, EF_NONE}, VKEY_EMOJI_PICKER},
       {{DomCode::DICTATE, EF_NONE}, VKEY_DICTATE},
       {{DomCode::ALL_APPLICATIONS, EF_NONE}, VKEY_ALL_APPLICATIONS},
-      {{DomCode::ACCESSIBILITY, EF_NONE}, VKEY_ACCESSIBILITY},
       // Verify the AC Application keys.
       {{DomCode::NEW, EF_NONE}, VKEY_NEW},
       {{DomCode::CLOSE, EF_NONE}, VKEY_CLOSE},
@@ -847,6 +846,8 @@
       {{DomCode::US_W, EF_ALTGR_DOWN, XKB_KEY_BackSpace, 8}, VKEY_BACK},
       {{DomCode::US_V, EF_ALTGR_DOWN, XKB_KEY_Return, 13}, VKEY_RETURN},
 #if BUILDFLAG(IS_CHROMEOS)
+      {{DomCode::ACCESSIBILITY, EF_NONE}, VKEY_ACCESSIBILITY},
+      {{DomCode::DO_NOT_DISTURB, EF_NONE}, VKEY_DO_NOT_DISTURB},
       // Verify on ChromeOS PRINT maps to VKEY_PRINT not VKEY_SNAPSHOT.
       {{DomCode::PRINT, EF_NONE, XKB_KEY_Print}, VKEY_PRINT},
       // On ChromeOS XKB_KEY_3270_PrintScreen is used for PRINT_SCREEN.
diff --git a/ui/gfx/range/range.h b/ui/gfx/range/range.h
index c4b561d..ee84d560 100644
--- a/ui/gfx/range/range.h
+++ b/ui/gfx/range/range.h
@@ -95,12 +95,8 @@
     return start() > end() ? start() : end();
   }
 
-  constexpr bool operator==(const Range& other) const {
-    return start() == other.start() && end() == other.end();
-  }
-  constexpr bool operator!=(const Range& other) const {
-    return !(*this == other);
-  }
+  constexpr bool operator==(const Range& other) const = default;
+  constexpr auto operator<=>(const Range& other) const = default;
   constexpr bool EqualsIgnoringDirection(const Range& other) const {
     return GetMin() == other.GetMin() && GetMax() == other.GetMax();
   }
diff --git a/ui/gfx/range/range_f.h b/ui/gfx/range/range_f.h
index 8960dae9..489a563 100644
--- a/ui/gfx/range/range_f.h
+++ b/ui/gfx/range/range_f.h
@@ -63,12 +63,8 @@
   constexpr float GetMin() const { return start() < end() ? start() : end(); }
   constexpr float GetMax() const { return start() > end() ? start() : end(); }
 
-  constexpr bool operator==(const RangeF& other) const {
-    return start() == other.start() && end() == other.end();
-  }
-  constexpr bool operator!=(const RangeF& other) const {
-    return !(*this == other);
-  }
+  constexpr bool operator==(const RangeF& other) const = default;
+  constexpr auto operator<=>(const RangeF& other) const = default;
   constexpr bool EqualsIgnoringDirection(const RangeF& other) const {
     return GetMin() == other.GetMin() && GetMax() == other.GetMax();
   }
diff --git a/ui/views/animation/animation_builder.cc b/ui/views/animation/animation_builder.cc
index b4620a45..4a22f47 100644
--- a/ui/views/animation/animation_builder.cc
+++ b/ui/views/animation/animation_builder.cc
@@ -174,14 +174,14 @@
   base::TimeDelta original_duration;
   std::unique_ptr<ui::LayerAnimationElement> element;
 
-  bool operator<(const Value& key) const {
+  auto operator<=>(const Value& key) const {
     // Animations with zero duration need to be ordered before animations with
     // nonzero of the same start time to prevent the DCHECK from happening in
     // TerminateSequence(). These animations don't count as overlapping
     // properties.
     auto element_properties = element->properties();
     auto key_element_properties = key.element->properties();
-    return std::tie(start, original_duration, element_properties) <
+    return std::tie(start, original_duration, element_properties) <=>
            std::tie(key.start, key.original_duration, key_element_properties);
   }
 };
diff --git a/ui/views/animation/animation_key.h b/ui/views/animation/animation_key.h
index 90ca5f09..b55a03e 100644
--- a/ui/views/animation/animation_key.h
+++ b/ui/views/animation/animation_key.h
@@ -20,9 +20,7 @@
   raw_ptr<ui::Layer> target;
   ui::LayerAnimationElement::AnimatableProperty property;
 
-  bool operator<(const AnimationKey& key) const {
-    return std::tie(target, property) < std::tie(key.target, key.property);
-  }
+  auto operator<=>(const AnimationKey& key) const = default;
 };
 
 }  // namespace views
diff --git a/ui/views/border_unittest.cc b/ui/views/border_unittest.cc
index 3c83051..49fa999 100644
--- a/ui/views/border_unittest.cc
+++ b/ui/views/border_unittest.cc
@@ -33,8 +33,8 @@
     DrawRectCall(const SkRect& rect, const SkPaint& paint)
         : rect(rect), paint(paint) {}
 
-    bool operator<(const DrawRectCall& other) const {
-      return std::tie(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom) <
+    auto operator<=>(const DrawRectCall& other) const {
+      return std::tie(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom) <=>
              std::tie(other.rect.fLeft, other.rect.fTop, other.rect.fRight,
                       other.rect.fBottom);
     }
@@ -47,7 +47,7 @@
     DrawRRectCall(const SkRRect& rrect, const SkPaint& paint)
         : rrect(rrect), paint(paint) {}
 
-    bool operator<(const DrawRRectCall& other) const {
+    auto operator<=>(const DrawRRectCall& other) const {
       SkRect rect = rrect.rect();
       SkRect other_rect = other.rrect.rect();
       return std::tie(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom) <
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc
index 352da80..99835f95 100644
--- a/ui/views/controls/button/button.cc
+++ b/ui/views/controls/button/button.cc
@@ -800,13 +800,6 @@
   UpdateAccessibleDefaultActionVerb();
 }
 
-void Button::ReleaseAnchorHighlight() {
-  if (0 == --anchor_count_) {
-    SetHighlighted(false);
-  }
-  anchor_count_changed_callbacks_.Notify(anchor_count_);
-}
-
 void Button::UpdateAccessibleCheckedState() {
   switch (state_) {
     case STATE_PRESSED:
@@ -818,6 +811,13 @@
   }
 }
 
+void Button::ReleaseAnchorHighlight() {
+  if (0 == --anchor_count_) {
+    SetHighlighted(false);
+  }
+  anchor_count_changed_callbacks_.Notify(anchor_count_);
+}
+
 void Button::SetDefaultActionVerb(ax::mojom::DefaultActionVerb verb) {
   default_action_verb_ = verb;
 }
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h
index 1964a24..51b5fa0 100644
--- a/ui/views/controls/button/button.h
+++ b/ui/views/controls/button/button.h
@@ -349,6 +349,8 @@
 
   virtual void OnEnabledChanged();
 
+  virtual void UpdateAccessibleCheckedState();
+
   // Sets the |default_action_verb_| for accessibility. Subclasses may
   // call this method to set their specific default action verb.
   void SetDefaultActionVerb(ax::mojom::DefaultActionVerb verb);
@@ -361,7 +363,6 @@
   FRIEND_TEST_ALL_PREFIXES(BlueButtonTest, Border);
 
   void ReleaseAnchorHighlight();
-  void UpdateAccessibleCheckedState();
 
   // The button's listener. Notified when clicked.
   PressedCallback callback_;
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc
index 22da94ea..0617b178 100644
--- a/ui/views/controls/button/checkbox.cc
+++ b/ui/views/controls/button/checkbox.cc
@@ -216,6 +216,12 @@
   return std::make_unique<CheckboxActionViewInterface>(this);
 }
 
+void Checkbox::UpdateAccessibleCheckedState() {
+  GetViewAccessibility().SetCheckedState(GetChecked()
+                                             ? ax::mojom::CheckedState::kTrue
+                                             : ax::mojom::CheckedState::kFalse);
+}
+
 void Checkbox::OnThemeChanged() {
   LabelButton::OnThemeChanged();
 }
@@ -272,12 +278,6 @@
   LabelButton::NotifyClick(event);
 }
 
-void Checkbox::UpdateAccessibleCheckedState() {
-  GetViewAccessibility().SetCheckedState(GetChecked()
-                                             ? ax::mojom::CheckedState::kTrue
-                                             : ax::mojom::CheckedState::kFalse);
-}
-
 ui::NativeTheme::Part Checkbox::GetThemePart() const {
   return ui::NativeTheme::kCheckbox;
 }
diff --git a/ui/views/controls/button/checkbox.h b/ui/views/controls/button/checkbox.h
index 21736094..c0c6b98 100644
--- a/ui/views/controls/button/checkbox.h
+++ b/ui/views/controls/button/checkbox.h
@@ -56,6 +56,9 @@
   // Bitmask constants for GetIconImageColor.
   enum IconState { CHECKED = 0b1, ENABLED = 0b10 };
 
+  // Button:
+  void UpdateAccessibleCheckedState() override;
+
   // LabelButton:
   void OnThemeChanged() override;
 
@@ -79,7 +82,6 @@
 
   // Button:
   void NotifyClick(const ui::Event& event) override;
-  void UpdateAccessibleCheckedState();
 
   ui::NativeTheme::Part GetThemePart() const override;
   void GetExtraParams(ui::NativeTheme::ExtraParams* params) const override;
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index 4bd3bbf4..84516bd 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -47,6 +47,19 @@
 
 ImageButton::~ImageButton() = default;
 
+void ToggleImageButton::UpdateAccessibleCheckedState() {
+  // Use the visual pressed image as a cue for making this control into an
+  // accessible toggle button.
+  if ((toggled_ && !images_[ButtonState::STATE_NORMAL].IsEmpty()) ||
+      (!toggled_ && !alternate_images_[ButtonState::STATE_NORMAL].IsEmpty())) {
+    GetViewAccessibility().SetCheckedState(
+        toggled_ ? ax::mojom::CheckedState::kTrue
+                 : ax::mojom::CheckedState::kFalse);
+  } else {
+    GetViewAccessibility().RemoveCheckedState();
+  }
+}
+
 gfx::ImageSkia ImageButton::GetImage(ButtonState state) const {
   return images_[state].Rasterize(GetColorProvider());
 }
@@ -307,19 +320,6 @@
   return toggled_;
 }
 
-void ToggleImageButton::UpdateAccessibleCheckedState() {
-  // Use the visual pressed image as a cue for making this control into an
-  // accessible toggle button.
-  if ((toggled_ && !images_[ButtonState::STATE_NORMAL].IsEmpty()) ||
-      (!toggled_ && !alternate_images_[ButtonState::STATE_NORMAL].IsEmpty())) {
-    GetViewAccessibility().SetCheckedState(
-        toggled_ ? ax::mojom::CheckedState::kTrue
-                 : ax::mojom::CheckedState::kFalse);
-  } else {
-    GetViewAccessibility().RemoveCheckedState();
-  }
-}
-
 void ToggleImageButton::SetToggled(bool toggled) {
   if (toggled == toggled_)
     return;
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index fd84dfb..f5aa7670 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -149,7 +149,6 @@
   // Change the toggled state.
   bool GetToggled() const;
   void SetToggled(bool toggled);
-  void UpdateAccessibleCheckedState();
 
   // Like ImageButton::SetImage(), but to set the graphics used for the
   // "has been toggled" state.  Must be called for each button state
@@ -171,6 +170,9 @@
   std::u16string GetToggledAccessibleName() const;
   void SetToggledAccessibleName(const std::u16string& name);
 
+  // Overridden from Button:
+  void UpdateAccessibleCheckedState() override;
+
   // Overridden from ImageButton:
   gfx::ImageSkia GetImage(ButtonState state) const override;
   void SetImageModel(ButtonState state,
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc
index 82a8c47..e4ae0347 100644
--- a/ui/views/controls/button/toggle_button.cc
+++ b/ui/views/controls/button/toggle_button.cc
@@ -496,6 +496,12 @@
   }
 }
 
+void ToggleButton::UpdateAccessibleCheckedState() {
+  GetViewAccessibility().SetCheckedState(GetIsOn()
+                                             ? ax::mojom::CheckedState::kTrue
+                                             : ax::mojom::CheckedState::kFalse);
+}
+
 SkPath ToggleButton::GetFocusRingPath() const {
   SkPath path;
   gfx::RectF bounds(GetTrackBounds());
diff --git a/ui/views/controls/button/toggle_button.h b/ui/views/controls/button/toggle_button.h
index 5c465d0..fdf7f3f 100644
--- a/ui/views/controls/button/toggle_button.h
+++ b/ui/views/controls/button/toggle_button.h
@@ -71,6 +71,7 @@
   // views::Button:
   void NotifyClick(const ui::Event& event) override;
   void StateChanged(ButtonState old_state) override;
+  void UpdateAccessibleCheckedState() override;
 
   // Returns the path to draw the focus ring around for this ToggleButton.
   virtual SkPath GetFocusRingPath() const;
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index c8e5fbf1..3a40d2e4 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -1246,10 +1246,7 @@
     // The first child is taking over, just use its accessible name instead of
     // |title_|.
     View* child = children().front();
-    ui::AXNodeData child_node_data;
-    child->GetViewAccessibility().GetAccessibleNodeData(&child_node_data);
-    item_text =
-        child_node_data.GetString16Attribute(ax::mojom::StringAttribute::kName);
+    item_text = child->GetViewAccessibility().GetCachedName();
   } else {
     item_text = title_;
   }
diff --git a/ui/views/controls/native/native_view_host_aura_unittest.cc b/ui/views/controls/native/native_view_host_aura_unittest.cc
index 4936220..b59615a8 100644
--- a/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -58,10 +58,7 @@
     EventType type;
     int window_id;
     gfx::Rect bounds;
-    bool operator!=(const EventDetails& rhs) {
-      return type != rhs.type || window_id != rhs.window_id ||
-             bounds != rhs.bounds;
-    }
+    bool operator==(const EventDetails& rhs) const = default;
   };
 
   NativeViewHostWindowObserver() = default;
diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
index 3f0dad0..c08e7e8 100644
--- a/ui/views/controls/styled_label.cc
+++ b/ui/views/controls/styled_label.cc
@@ -69,9 +69,9 @@
     const LayoutSizeInfo&) = default;
 StyledLabel::LayoutSizeInfo::~LayoutSizeInfo() = default;
 
-bool StyledLabel::StyleRange::operator<(
+auto StyledLabel::StyleRange::operator<=>(
     const StyledLabel::StyleRange& other) const {
-  return range.start() < other.range.start();
+  return range <=> other.range;
 }
 
 struct StyledLabel::LayoutViews {
diff --git a/ui/views/controls/styled_label.h b/ui/views/controls/styled_label.h
index a200565..761b33d5 100644
--- a/ui/views/controls/styled_label.h
+++ b/ui/views/controls/styled_label.h
@@ -208,7 +208,7 @@
         : range(range), style_info(style_info) {}
     ~StyleRange() = default;
 
-    bool operator<(const StyleRange& other) const;
+    auto operator<=>(const StyleRange& other) const;
 
     gfx::Range range;
     RangeStyleInfo style_info;
diff --git a/ui/views/test/ax_event_counter.cc b/ui/views/test/ax_event_counter.cc
index 1d6a13f..f3c2b3e4 100644
--- a/ui/views/test/ax_event_counter.cc
+++ b/ui/views/test/ax_event_counter.cc
@@ -31,9 +31,8 @@
   // We should either fix those errors or stop firing the events. For now,
   // require the presence of a Widget to count events by role.
   if (view->GetWidget()) {
-    ui::AXNodeData node_data;
-    view->GetViewAccessibility().GetAccessibleNodeData(&node_data);
-    ++event_counts_for_role_[std::make_pair(event_type, node_data.role)];
+    ++event_counts_for_role_[std::make_pair(
+        event_type, view->GetViewAccessibility().GetCachedRole())];
   }
 
   if (run_loop_ && event_type == wait_for_event_type_) {
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn
index 45328d1f..082f4b1 100644
--- a/ui/webui/resources/cr_components/app_management/BUILD.gn
+++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -70,10 +70,10 @@
   grd_prefix = "cr_components_app_management"
 
   non_web_component_files = [
+    "browser_proxy.ts",
     "constants.ts",
     "permission_constants.ts",
     "permission_util.ts",
-    "browser_proxy.ts",
     "util.ts",
   ]
 
diff --git a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
index 454cb3c..be64513 100644
--- a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
+++ b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
@@ -58,13 +58,13 @@
       "local_certs_section_v2.ts",
     ]
     non_web_component_files += [
-      "certificates_v2_browser_proxy.ts",
       "certificate_confirmation_dialog.html.ts",
       "certificate_confirmation_dialog.ts",
       "certificate_info_dialog.html.ts",
       "certificate_info_dialog.ts",
       "certificate_password_dialog.html.ts",
       "certificate_password_dialog.ts",
+      "certificates_v2_browser_proxy.ts",
       "navigation_v2.ts",
     ]
 
diff --git a/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn b/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn
index 19ca9d5..180984ab 100644
--- a/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn
+++ b/ui/webui/resources/cr_components/customize_color_scheme_mode/BUILD.gn
@@ -33,9 +33,9 @@
     "customize_color_scheme_mode.html.ts",
     "customize_color_scheme_mode.ts",
     "segmented_button.html.ts",
+    "segmented_button.ts",
     "segmented_button_option.html.ts",
     "segmented_button_option.ts",
-    "segmented_button.ts",
   ]
   css_files = [
     "customize_color_scheme_mode.css",
diff --git a/ui/webui/resources/cr_components/help_bubble/BUILD.gn b/ui/webui/resources/cr_components/help_bubble/BUILD.gn
index 58e430de..b336461 100644
--- a/ui/webui/resources/cr_components/help_bubble/BUILD.gn
+++ b/ui/webui/resources/cr_components/help_bubble/BUILD.gn
@@ -22,14 +22,14 @@
   grd_prefix = "cr_components_help_bubble"
 
   non_web_component_files = [
-    "help_bubble.ts",
     "help_bubble.html.ts",
+    "help_bubble.ts",
+    "help_bubble_controller.ts",
     "help_bubble_mixin.ts",
     "help_bubble_mixin_lit.ts",
     "help_bubble_proxy.ts",
-    "help_bubble_controller.ts",
-    "new_badge.ts",
     "new_badge.html.ts",
+    "new_badge.ts",
   ]
 
   css_files = [
diff --git a/ui/webui/resources/cr_components/history_clusters/BUILD.gn b/ui/webui/resources/cr_components/history_clusters/BUILD.gn
index be1219c..7458fb1b 100644
--- a/ui/webui/resources/cr_components/history_clusters/BUILD.gn
+++ b/ui/webui/resources/cr_components/history_clusters/BUILD.gn
@@ -24,28 +24,28 @@
 
   non_web_component_files = [
     "browser_proxy.ts",
-    "cluster.ts",
     "cluster.html.ts",
-    "clusters.ts",
-    "clusters.html.ts",
-    "cluster_menu.ts",
+    "cluster.ts",
     "cluster_menu.html.ts",
-    "horizontal_carousel.ts",
+    "cluster_menu.ts",
+    "clusters.html.ts",
+    "clusters.ts",
     "horizontal_carousel.html.ts",
-    "page_favicon.ts",
-    "page_favicon.html.ts",
-    "search_query.ts",
-    "search_query.html.ts",
-    "url_visit.ts",
-    "url_visit.html.ts",
+    "horizontal_carousel.ts",
     "metrics_proxy.ts",
+    "page_favicon.html.ts",
+    "page_favicon.ts",
+    "search_query.html.ts",
+    "search_query.ts",
+    "url_visit.html.ts",
+    "url_visit.ts",
     "utils.ts",
   ]
 
   css_files = [
     "cluster.css",
-    "clusters.css",
     "cluster_menu.css",
+    "clusters.css",
     "history_clusters_shared_style.css",
     "horizontal_carousel.css",
     "page_favicon.css",
diff --git a/ui/webui/resources/cr_components/managed_dialog/BUILD.gn b/ui/webui/resources/cr_components/managed_dialog/BUILD.gn
index 5a82006a..aca3bb9 100644
--- a/ui/webui/resources/cr_components/managed_dialog/BUILD.gn
+++ b/ui/webui/resources/cr_components/managed_dialog/BUILD.gn
@@ -10,8 +10,8 @@
   grd_prefix = "cr_components_managed_dialog"
 
   non_web_component_files = [
-    "managed_dialog.ts",
     "managed_dialog.html.ts",
+    "managed_dialog.ts",
   ]
   css_files = [ "managed_dialog.css" ]
 
diff --git a/ui/webui/resources/cr_components/managed_footnote/BUILD.gn b/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
index e0bda03d..184576b 100644
--- a/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
+++ b/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
@@ -10,8 +10,8 @@
   grd_prefix = "cr_components_managed_footnote"
 
   non_web_component_files = [
-    "managed_footnote.ts",
     "managed_footnote.html.ts",
+    "managed_footnote.ts",
   ]
   css_files = [ "managed_footnote.css" ]
 
diff --git a/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn b/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn
index d3f98de7..700998b 100644
--- a/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn
+++ b/ui/webui/resources/cr_components/theme_color_picker/BUILD.gn
@@ -35,9 +35,9 @@
     "check_mark_wrapper.ts",
     "color_utils.ts",
     "theme_color.html.ts",
+    "theme_color.ts",
     "theme_color_picker.html.ts",
     "theme_color_picker.ts",
-    "theme_color.ts",
     "theme_hue_slider_dialog.html.ts",
     "theme_hue_slider_dialog.ts",
   ]
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index 3861e92..f03dfe55 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -100,14 +100,14 @@
       "cr_lazy_list/cr_lazy_list.ts",
       "cr_lazy_render/cr_lazy_render.ts",
       "cr_lazy_render/cr_lazy_render_lit.ts",
-      "cr_link_row/cr_link_row.ts",
       "cr_link_row/cr_link_row.html.ts",
-      "cr_loading_gradient/cr_loading_gradient.ts",
+      "cr_link_row/cr_link_row.ts",
       "cr_loading_gradient/cr_loading_gradient.html.ts",
-      "cr_menu_selector/cr_menu_selector.ts",
+      "cr_loading_gradient/cr_loading_gradient.ts",
       "cr_menu_selector/cr_menu_selector.html.ts",
-      "cr_page_selector/cr_page_selector.ts",
+      "cr_menu_selector/cr_menu_selector.ts",
       "cr_page_selector/cr_page_selector.html.ts",
+      "cr_page_selector/cr_page_selector.ts",
       "cr_profile_avatar_selector/cr_profile_avatar_selector.html.ts",
       "cr_profile_avatar_selector/cr_profile_avatar_selector.ts",
       "cr_progress/cr_progress.html.ts",
@@ -126,17 +126,17 @@
       "cr_textarea/cr_textarea.html.ts",
       "cr_textarea/cr_textarea.ts",
       "cr_toast/cr_toast.html.ts",
+      "cr_toast/cr_toast.ts",
       "cr_toast/cr_toast_manager.html.ts",
       "cr_toast/cr_toast_manager.ts",
-      "cr_toast/cr_toast.ts",
       "cr_toggle/cr_toggle.html.ts",
       "cr_toggle/cr_toggle.ts",
       "cr_toolbar/cr_toolbar.html.ts",
+      "cr_toolbar/cr_toolbar.ts",
       "cr_toolbar/cr_toolbar_search_field.html.ts",
       "cr_toolbar/cr_toolbar_search_field.ts",
       "cr_toolbar/cr_toolbar_selection_overlay.html.ts",
       "cr_toolbar/cr_toolbar_selection_overlay.ts",
-      "cr_toolbar/cr_toolbar.ts",
       "cr_tooltip/cr_tooltip.html.ts",
       "cr_tooltip/cr_tooltip.ts",
       "cr_url_list_item/cr_url_list_item.html.ts",
@@ -152,34 +152,9 @@
     css_files += [
       "action_link.css",
       "action_link_lit.css",
+      "cr_action_menu/cr_action_menu.css",
       "cr_actionable_row_style.css",
       "cr_actionable_row_style_lit.css",
-      "cr_hidden_style.css",
-      "cr_icons.css",
-      "cr_icons_lit.css",
-      "cr_nav_menu_item_style.css",
-      "cr_nav_menu_item_style_lit.css",
-      "cr_page_host_style.css",
-      "cr_page_host_style_lit.css",
-      "cr_lazy_list/cr_lazy_list.css",
-      "cr_radio_button/cr_radio_button.css",
-      "cr_radio_button/cr_card_radio_button.css",
-      "cr_radio_button/cr_radio_button_style.css",
-      "cr_radio_button/cr_radio_button_style_lit.css",
-      "cr_radio_group/cr_radio_group.css",
-      "cr_shared_style.css",
-      "cr_shared_style_lit.css",
-      "cr_spinner_style.css",
-      "cr_spinner_style_lit.css",
-      "md_select.css",
-      "md_select_lit.css",
-      "mwb_element_shared_style.css",
-      "mwb_element_shared_style_lit.css",
-      "mwb_shared_style.css",
-      "mwb_shared_style_lit.css",
-      "mwb_shared_vars.css",
-      "search_highlight_style.css",
-      "cr_action_menu/cr_action_menu.css",
       "cr_checkbox/cr_checkbox.css",
       "cr_chip/cr_chip.css",
       "cr_collapse/cr_collapse.css",
@@ -188,20 +163,37 @@
       "cr_expand_button/cr_expand_button.css",
       "cr_feedback_buttons/cr_feedback_buttons.css",
       "cr_grid/cr_grid.css",
+      "cr_hidden_style.css",
       "cr_icon/cr_icon.css",
       "cr_icon/cr_iconset.css",
       "cr_icon_button/cr_icon_button.css",
+      "cr_icons.css",
+      "cr_icons_lit.css",
       "cr_infinite_list/cr_infinite_list.css",
       "cr_input/cr_input.css",
       "cr_input/cr_input_style.css",
       "cr_input/cr_input_style_lit.css",
+      "cr_lazy_list/cr_lazy_list.css",
       "cr_link_row/cr_link_row.css",
       "cr_loading_gradient/cr_loading_gradient.css",
+      "cr_nav_menu_item_style.css",
+      "cr_nav_menu_item_style_lit.css",
+      "cr_page_host_style.css",
+      "cr_page_host_style_lit.css",
       "cr_page_selector/cr_page_selector.css",
       "cr_profile_avatar_selector/cr_profile_avatar_selector.css",
       "cr_progress/cr_progress.css",
+      "cr_radio_button/cr_card_radio_button.css",
+      "cr_radio_button/cr_radio_button.css",
+      "cr_radio_button/cr_radio_button_style.css",
+      "cr_radio_button/cr_radio_button_style_lit.css",
+      "cr_radio_group/cr_radio_group.css",
       "cr_search_field/cr_search_field.css",
+      "cr_shared_style.css",
+      "cr_shared_style_lit.css",
       "cr_slider/cr_slider.css",
+      "cr_spinner_style.css",
+      "cr_spinner_style_lit.css",
       "cr_textarea/cr_textarea.css",
       "cr_toast/cr_toast.css",
       "cr_toast/cr_toast_manager.css",
@@ -212,8 +204,16 @@
       "cr_tooltip/cr_tooltip.css",
       "cr_url_list_item/cr_url_list_item.css",
       "cr_view_manager/cr_view_manager.css",
+      "md_select.css",
+      "md_select_lit.css",
+      "mwb_element_shared_style.css",
+      "mwb_element_shared_style_lit.css",
+      "mwb_shared_style.css",
+      "mwb_shared_style_lit.css",
+      "mwb_shared_vars.css",
       "policy/cr_policy_indicator.css",
       "policy/cr_tooltip_icon.css",
+      "search_highlight_style.css",
     ]
   }
 
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn
index 4f79d99..f96408f 100644
--- a/ui/webui/resources/js/BUILD.gn
+++ b/ui/webui/resources/js/BUILD.gn
@@ -23,8 +23,8 @@
     "focus_row.ts",
     "icon.ts",
     "keyboard_shortcut_list.ts",
-    "load_time_data_deprecated.js",
     "load_time_data.ts",
+    "load_time_data_deprecated.js",
     "metrics_reporter/browser_proxy.ts",
     "metrics_reporter/metrics_reporter.ts",
     "mojo_type_util.ts",
@@ -55,8 +55,8 @@
 
   if (include_polymer) {
     non_web_component_files += [
-      "focus_without_ink.ts",
       "browser_command/browser_command_proxy.ts",
+      "focus_without_ink.ts",
     ]
   }