diff --git a/AUTHORS b/AUTHORS
index 5206baf..9ae03a5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -437,6 +437,7 @@
 Hari Singh <hari.singh1@samsung.com>
 Harpreet Singh Khurana <harpreet.sk@samsung.com>
 Harshikesh Kumar <harshikeshnobug@gmail.com>
+Harshit Pal <harshitp12345@gmail.com>
 Hassan Salehe Matar <hassansalehe@gmail.com>
 Hautio Kari <khautio@gmail.com>
 Heejin R. Chung <heejin.r.chung@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn
index 02596c90..23ea3bc 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -179,7 +179,7 @@
 
   if (!is_ios) {
     deps += [
-      ":chromedriver",
+      ":chromedriver_group",
       "//cc:cc_unittests",
       "//components:components_browsertests",
       "//components/policy:policy_templates",
@@ -1068,7 +1068,7 @@
 }
 
 if (!is_ios) {
-  group("chromedriver") {
+  group("chromedriver_group") {
     testonly = true
 
     if (is_fuchsia || is_android) {
@@ -1091,6 +1091,12 @@
     }
   }
 
+  # TODO(chromium:1382224): Remove this target as soon as all the builders have switched to :chromedriver_group
+  group("chromedriver") {
+    testonly = true
+    deps = [ ":chromedriver_group" ]
+  }
+
   # This group includes all of the targets needed to build and test Blink,
   # including running web tests (see below). This target is defined here because
   # previously //third_party/WebKit, now //third_party/blink, couldn't depend on
diff --git a/DEPS b/DEPS
index 1c1e6f0a..3095d9c0 100644
--- a/DEPS
+++ b/DEPS
@@ -306,7 +306,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '9d56e506b4df8a75b559aa9d25ecdb7db88ca8a0',
+  'skia_revision': '8e2ed1e3d1b9dd47f668535bd5ad98f3a11795b1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -314,7 +314,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': '386ef2eefe63af50162ef61ce2f5c00e6bde7b66',
+  'angle_revision': 'ec42459200373e4fed77933f67b098ba45290f47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -385,7 +385,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'c73fe21a0ec8ff28fd24c584fcb001571a2ca025',
+  'devtools_frontend_revision': 'fecd73d233db03c980e6c1b3af7dc4d28f6cd8b9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -421,7 +421,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '9f2829f4718e3b7742aa6795df78491e20f7ffab',
+  'dawn_revision': 'aedda6a50076c7747e66954a1b55bc0776615d17',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -816,7 +816,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    'c07fc321ae7f5f3a285f568fb1f0b2d6a4db99ff',
+    'f1c755b7ba172daac62f1f1266fae32aff2c22d1',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
@@ -1249,7 +1249,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '85429b8992a921c63c2bae4de22c81737d12ad3a',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'b899c39111bf4837c800da8c81c2d2f2ef95c1be',
     'condition': 'checkout_src_internal',
   },
 
@@ -1664,7 +1664,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6f7678ba37a925e02df652a13c50be9daaeb484e',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6c5c80b3c694219abfaa0a1fe814522e70c0dc65',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1849,7 +1849,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'fa3aad630e1a992808c28986bb6b24cadd6d1c15',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '408f0be5c23024a4b88f80b7707f570cd53ca6a6',
+    Var('webrtc_git') + '/src.git' + '@' + '76793c300fdd87fa8fd8be3dd2e5faf8c1916e96',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1919,7 +1919,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a17c545b26c0974baa4603d45a63377f0530b53d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@11b1d9bac3891adcdbbcf2e479dc2a47c546b6e6',
     'condition': 'checkout_src_internal',
   },
 
@@ -1971,7 +1971,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': '1W6l_EV9c96k_haPLjYQYFoEuoLiwiYqGdKCU9D4-BsC',
+        'version': '4xnC6TU1wpoJID-muq1szP_W5mRqh6iPyQIXxkQ2D1cC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts b/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
index 7ba1f31..2c1e864 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
@@ -479,9 +479,12 @@
 
   async startCapture(): Promise<[Promise<void>]> {
     this.setCameraAvailable(false);
-    const captureDone = await this.scheduler.startCapture();
-    this.setCameraAvailable(true);
-    return assertExists(captureDone);
+    try {
+      const captureDone = await this.scheduler.startCapture();
+      return assertExists(captureDone);
+    } finally {
+      this.setCameraAvailable(true);
+    }
   }
 
   stopCapture(): void {
diff --git a/ash/wm/window_cycle/window_cycle_controller_unittest.cc b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
index a63a7cb..23e5427b 100644
--- a/ash/wm/window_cycle/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
@@ -75,6 +75,7 @@
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/views/accessibility/accessibility_paint_checks.h"
 
 namespace ash {
 
@@ -179,6 +180,12 @@
     return cycle_view()->mirror_container_->children();
   }
 
+  const views::View* GetTabSliderActiveButtonSelector() const {
+    if (auto* tab_slider_container = cycle_view()->tab_slider_container_)
+      return tab_slider_container->active_button_selector_;
+    return nullptr;
+  }
+
   const views::View::Views& GetTabSliderButtons() const {
     auto* tab_slider_container = cycle_view()->tab_slider_container_;
     if (!tab_slider_container) {
@@ -236,6 +243,11 @@
     return WindowCycleListTestApi(GetCycleList()).GetTabSliderButtons();
   }
 
+  const views::View* GetWindowCycleTabSliderActiveButtonSelector() const {
+    return WindowCycleListTestApi(GetCycleList())
+        .GetTabSliderActiveButtonSelector();
+  }
+
   const views::Label* GetWindowCycleNoRecentItemsLabel() const {
     return WindowCycleListTestApi(GetCycleList()).no_recent_items_label();
   }
@@ -3101,6 +3113,42 @@
   EXPECT_TRUE(cycle_controller->IsCycling());
 }
 
+// Runs the accessibility paint checks on the active button selector.
+// There should be no DCHECK failures.
+TEST_F(ModeSelectionWindowCycleControllerTest,
+       AccessibilityPaintChecksOnActiveButtonSelector) {
+  WindowCycleController* cycle_controller =
+      Shell::Get()->window_cycle_controller();
+
+  // Create a second desk.
+  auto* desks_controller = DesksController::Get();
+  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
+  ASSERT_EQ(2u, desks_controller->desks().size());
+
+  // Put one window on each desk.
+  auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
+  ActivateDesk(desks_controller->desks()[1].get());
+  auto win1 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
+
+  // Start cycle. Verify the slider buttons are present.
+  cycle_controller->StartCycling();
+  auto tab_slider_buttons = GetWindowCycleTabSliderButtons();
+  EXPECT_EQ(2u, tab_slider_buttons.size());
+
+  // Run the accessibility paint checks on the active button selector.
+  // There should be no DCHECK failures. Failures in the past occurred due to
+  // the active button selector having `FocusBehavior::ALWAYS`. That change,
+  // done to improve ChromeVox's presentation, appears to no longer be needed.
+  // Therefore the default focus behavior (`FocusBehavior::NEVER`) is once again
+  // in place.
+  auto* active_button_selector = GetWindowCycleTabSliderActiveButtonSelector();
+  EXPECT_EQ(active_button_selector->GetFocusBehavior(),
+            views::View::FocusBehavior::NEVER);
+  RunAccessibilityPaintChecks(const_cast<views::View*>(active_button_selector));
+
+  CompleteCycling(cycle_controller);
+}
+
 namespace {
 
 constexpr char kUser1Email[] = "user1@alttab";
@@ -3235,6 +3283,11 @@
     return WindowCycleListTestApi(GetCycleList()).GetWindowCycleItemViews();
   }
 
+  const views::View* GetWindowCycleTabSliderActiveButtonSelector() const {
+    return WindowCycleListTestApi(GetCycleList())
+        .GetTabSliderActiveButtonSelector();
+  }
+
   const views::View::Views& GetWindowCycleTabSliderButtons() const {
     return WindowCycleListTestApi(GetCycleList()).GetTabSliderButtons();
   }
diff --git a/ash/wm/window_cycle/window_cycle_tab_slider.cc b/ash/wm/window_cycle/window_cycle_tab_slider.cc
index 55a7204f..c927a990 100644
--- a/ash/wm/window_cycle/window_cycle_tab_slider.cc
+++ b/ash/wm/window_cycle/window_cycle_tab_slider.cc
@@ -10,12 +10,13 @@
 #include "ash/wm/window_cycle/window_cycle_controller.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/transform_util.h"
-#include "ui/views/accessibility/accessibility_paint_checks.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/animation/animation_builder.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/highlight_path_generator.h"
@@ -105,13 +106,6 @@
       Shell::Get()->window_cycle_controller()->IsAltTabPerActiveDesk();
   all_desks_tab_slider_button_->SetToggled(!per_desk);
   current_desk_tab_slider_button_->SetToggled(per_desk);
-
-  // TODO(crbug.com/1218186): Remove this, this is in place temporarily to be
-  // able to submit accessibility checks. This crashes if fetching a11y node
-  // data during paint because `active_button_selector_` is null.
-  active_button_selector_->SetProperty(views::kSkipAccessibilityPaintChecks,
-                                       true);
-  active_button_selector_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
 }
 
 void WindowCycleTabSlider::SetFocus(bool focus) {
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 438d539..812b8c2 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-10.20221117.1.1
+10.20221118.0.1
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index 4fe4ce9..fe9a487 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -89,7 +89,6 @@
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCustomTabTestRule.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java",
-    "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandlerTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacadeTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java",
@@ -120,7 +119,6 @@
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUpdateClientSettingsIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetOnboardingCoordinatorTest.java",
-    "javatests/src/org/chromium/chrome/browser/autofill_assistant/DirectActionsIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromGsaTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/InCctTriggeringFromNonGsaTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/JsFlowIntegrationTest.java",
@@ -129,7 +127,6 @@
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureTest.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/PasswordChangeFixtureTestUtils.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/ProtoTestUtil.java",
-    "javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java",
     "javatests/src/org/chromium/chrome/browser/autofill_assistant/TriggerContextTest.java",
   ]
 
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandlerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandlerTest.java
deleted file mode 100644
index 312fe53..0000000
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandlerTest.java
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill_assistant;
-
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
-
-import android.os.Bundle;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.Callback;
-import org.chromium.base.supplier.Supplier;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.DisabledTest;
-import org.chromium.chrome.browser.app.ChromeActivity;
-import org.chromium.chrome.browser.directactions.DirectActionHandler;
-import org.chromium.chrome.browser.directactions.DirectActionReporter;
-import org.chromium.chrome.browser.directactions.DirectActionReporter.Type;
-import org.chromium.chrome.browser.directactions.FakeDirectActionReporter;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.preferences.Pref;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.components.autofill_assistant.R;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.prefs.PrefService;
-import org.chromium.components.user_prefs.UserPrefs;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-/** Tests the direct actions exposed by AA. */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@Batch(Batch.PER_CLASS)
-@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
-public class AutofillAssistantDirectActionHandlerTest {
-    @Rule
-    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
-
-    private ChromeActivity mActivity;
-    private BottomSheetController mBottomSheetController;
-    private DirectActionHandler mHandler;
-    private TestingAutofillAssistantModuleEntryProvider mModuleEntryProvider;
-
-    @Before
-    public void setUp() throws Exception {
-        mActivityTestRule.startMainActivityOnBlankPage();
-        mActivity = mActivityTestRule.getActivity();
-
-        mBottomSheetController = TestThreadUtils.runOnUiThreadBlocking(
-                () -> AutofillAssistantUiTestUtil.getBottomSheetController(mActivity));
-        mModuleEntryProvider = new TestingAutofillAssistantModuleEntryProvider();
-        mModuleEntryProvider.setCannotInstall();
-
-        Supplier<WebContents> webContentsSupplier =
-                () -> mActivity.getActivityTabProvider().get().getWebContents();
-
-        mHandler = new AutofillAssistantDirectActionHandler(mActivity, mBottomSheetController,
-                mActivity.getBrowserControlsManager(),
-                mActivity.getCompositorViewHolderForTesting(), mActivity.getActivityTabProvider(),
-                webContentsSupplier, mModuleEntryProvider);
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_CONSENT);
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_ENABLED);
-        });
-    }
-
-    @After
-    public void tearDown() {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_CONSENT);
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_ENABLED);
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testReportOnboardingOnlyIfNotAccepted() throws Exception {
-        mModuleEntryProvider.setInstalled();
-
-        FakeDirectActionReporter reporter = new FakeDirectActionReporter();
-        reportAvailableDirectActions(mHandler, reporter);
-
-        Assert.assertThat(reporter.getDirectActions(),
-                containsInAnyOrder("onboarding", "onboarding_and_start"));
-
-        FakeDirectActionReporter.FakeDefinition onboarding =
-                reporter.mActions.get(reporter.getDirectActions().indexOf("onboarding"));
-        assertEquals("onboarding", onboarding.mId);
-        assertEquals(2, onboarding.mParameters.size());
-        assertEquals("name", onboarding.mParameters.get(0).mName);
-        assertEquals(Type.STRING, onboarding.mParameters.get(0).mType);
-        assertEquals("experiment_ids", onboarding.mParameters.get(1).mName);
-        assertEquals(Type.STRING, onboarding.mParameters.get(1).mType);
-        assertEquals(1, onboarding.mResults.size());
-        assertEquals("success", onboarding.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, onboarding.mResults.get(0).mType);
-    }
-
-    @Test
-    @MediumTest
-    @DisabledTest(message = "https://crbug.com/1296764")
-    public void testReportAvailableDirectActions() throws Exception {
-        mModuleEntryProvider.setInstalled();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.setBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT, true);
-            prefService.setBoolean(Pref.AUTOFILL_ASSISTANT_ENABLED, true);
-        });
-
-        // Start the autofill assistant stack.
-
-        FakeDirectActionReporter reporter = new FakeDirectActionReporter();
-        reportAvailableDirectActions(mHandler, reporter);
-
-        assertEquals(1, reporter.mActions.size());
-
-        FakeDirectActionReporter.FakeDefinition fetch = reporter.mActions.get(0);
-        assertEquals("fetch_website_actions", fetch.mId);
-        assertEquals(2, fetch.mParameters.size());
-        assertEquals("user_name", fetch.mParameters.get(0).mName);
-        assertEquals(Type.STRING, fetch.mParameters.get(0).mType);
-        assertEquals(false, fetch.mParameters.get(0).mRequired);
-        assertEquals("experiment_ids", fetch.mParameters.get(1).mName);
-        assertEquals(Type.STRING, fetch.mParameters.get(1).mType);
-        assertEquals(false, fetch.mParameters.get(1).mRequired);
-        assertEquals(1, fetch.mResults.size());
-        assertEquals("success", fetch.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, fetch.mResults.get(0).mType);
-
-        // Start the autofill assistant stack.
-        fetchWebsiteActions();
-        // Reset the reported actions.
-        reporter = new FakeDirectActionReporter();
-        reportAvailableDirectActions(mHandler, reporter);
-
-        // Now that the AA stack is up, the fetdch_website_actions should no longer show up.
-        assertEquals(3, reporter.mActions.size());
-
-        // Now we expect 3 dyamic actions "search", "action2" and "action2_alias".
-        FakeDirectActionReporter.FakeDefinition search = reporter.mActions.get(0);
-        assertEquals("search", search.mId);
-        assertEquals(3, search.mParameters.size());
-        assertEquals("experiment_ids", search.mParameters.get(0).mName);
-        assertEquals(Type.STRING, search.mParameters.get(0).mType);
-        assertEquals("SEARCH_QUERY", search.mParameters.get(1).mName);
-        assertEquals(Type.STRING, search.mParameters.get(1).mType);
-        assertEquals("arg2", search.mParameters.get(2).mName);
-        assertEquals(Type.STRING, search.mParameters.get(2).mType);
-        assertEquals(1, search.mResults.size());
-        assertEquals("success", search.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, search.mResults.get(0).mType);
-
-        FakeDirectActionReporter.FakeDefinition action2 = reporter.mActions.get(1);
-        assertEquals("action2", action2.mId);
-        assertEquals(3, action2.mParameters.size());
-        assertEquals("experiment_ids", action2.mParameters.get(0).mName);
-        assertEquals(Type.STRING, action2.mParameters.get(0).mType);
-        assertEquals("SEARCH_QUERY", action2.mParameters.get(1).mName);
-        assertEquals(Type.STRING, action2.mParameters.get(1).mType);
-        assertEquals("arg2", action2.mParameters.get(2).mName);
-        assertEquals(Type.STRING, action2.mParameters.get(2).mType);
-        assertEquals(1, action2.mResults.size());
-        assertEquals("success", action2.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, action2.mResults.get(0).mType);
-
-        FakeDirectActionReporter.FakeDefinition action2Alias = reporter.mActions.get(2);
-        assertEquals("action2_alias", action2Alias.mId);
-        assertEquals(3, action2Alias.mParameters.size());
-        assertEquals("experiment_ids", action2Alias.mParameters.get(0).mName);
-        assertEquals(Type.STRING, action2Alias.mParameters.get(0).mType);
-        assertEquals("SEARCH_QUERY", action2Alias.mParameters.get(1).mName);
-        assertEquals(Type.STRING, action2Alias.mParameters.get(1).mType);
-        assertEquals("arg2", action2Alias.mParameters.get(2).mName);
-        assertEquals(Type.STRING, action2Alias.mParameters.get(2).mType);
-        assertEquals(1, action2Alias.mResults.size());
-        assertEquals("success", action2Alias.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, action2Alias.mResults.get(0).mType);
-    }
-
-    @Test
-    @MediumTest
-    public void testReportAvailableAutofillAssistantActions() throws Exception {
-        mModuleEntryProvider.setInstalled();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.setBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT, true);
-            prefService.setBoolean(Pref.AUTOFILL_ASSISTANT_ENABLED, true);
-        });
-
-        FakeDirectActionReporter reporter = new FakeDirectActionReporter();
-        reportAvailableDirectActions(mHandler, reporter);
-
-        assertEquals(1, reporter.mActions.size());
-
-        FakeDirectActionReporter.FakeDefinition fetch = reporter.mActions.get(0);
-        assertEquals("fetch_website_actions", fetch.mId);
-        assertEquals(2, fetch.mParameters.size());
-        assertEquals("user_name", fetch.mParameters.get(0).mName);
-        assertEquals(Type.STRING, fetch.mParameters.get(0).mType);
-        assertEquals(false, fetch.mParameters.get(0).mRequired);
-        assertEquals("experiment_ids", fetch.mParameters.get(1).mName);
-        assertEquals(Type.STRING, fetch.mParameters.get(1).mType);
-        assertEquals(false, fetch.mParameters.get(1).mRequired);
-
-        assertEquals(1, fetch.mResults.size());
-        assertEquals("success", fetch.mResults.get(0).mName);
-        assertEquals(Type.BOOLEAN, fetch.mResults.get(0).mType);
-    }
-
-    @Test
-    @MediumTest
-    @DisableIf.Build(sdk_is_greater_than = 22) // TODO(crbug/990118): re-enable
-    public void testOnboarding() throws Exception {
-        mModuleEntryProvider.setInstalled();
-
-        assertThat(isActionReported("onboarding"), is(true));
-        acceptOnboarding();
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            assertTrue(prefService.getBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT));
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testModuleNotAvailable() throws Exception {
-        mModuleEntryProvider.setCannotInstall();
-
-        assertThat(isActionReported("onboarding"), is(true));
-        assertFalse(performAction("onboarding", Bundle.EMPTY));
-    }
-
-    @Test
-    @MediumTest
-    @DisableIf.Build(sdk_is_greater_than = 22) // TODO(crbug/990118): re-enable
-    public void testInstallModuleOnDemand() throws Exception {
-        mModuleEntryProvider.setNotInstalled();
-
-        assertThat(isActionReported("onboarding"), is(true));
-        acceptOnboarding();
-    }
-
-    private void acceptOnboarding() throws Exception {
-        WaitingCallback<Boolean> onboardingCallback =
-                performActionAsync("onboarding", Bundle.EMPTY);
-
-        waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
-
-        assertFalse(onboardingCallback.hasResult());
-        onView(withId(R.id.button_init_ok)).perform(click());
-        assertEquals(Boolean.TRUE, onboardingCallback.waitForResult("accept onboarding"));
-    }
-
-    private boolean isActionReported(String actionId) throws Exception {
-        FakeDirectActionReporter reporter = new FakeDirectActionReporter();
-        reportAvailableDirectActions(mHandler, reporter);
-
-        for (FakeDirectActionReporter.FakeDefinition definition : reporter.mActions) {
-            if (definition.mId.equals(actionId)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // TODO(b/134741524): Add tests that list and execute direct actions coming from scripts, once
-    // we have a way to fake RPCs and can create a bottom sheet controller on demand.
-
-    /** Calls fetch_website_actions and returns whether that succeeded or not. */
-    private boolean fetchWebsiteActions() throws Exception {
-        WaitingCallback<Bundle> callback = new WaitingCallback<Bundle>();
-        assertTrue(TestThreadUtils.runOnUiThreadBlocking(
-                ()
-                        -> mHandler.performDirectAction(
-                                "fetch_website_actions", Bundle.EMPTY, callback)));
-        return callback.waitForResult("fetch_website_actions").getBoolean("success", false);
-    }
-
-    /**
-     * When reporting direct actions involves web_contents in the controller, it needs to run on the
-     * UI thread.
-     */
-    private void reportAvailableDirectActions(
-            DirectActionHandler handler, DirectActionReporter reporter) throws Exception {
-        assertTrue(TestThreadUtils.runOnUiThreadBlocking(() -> {
-            handler.reportAvailableDirectActions(reporter);
-            return true;
-        }));
-    }
-
-    /** Performs direct action |name| and returns the result. */
-    private Boolean performAction(String name, Bundle arguments) throws Exception {
-        return performActionAsync(name, arguments).waitForResult("success");
-    }
-
-    /**
-     * Performs direct action |name| and returns a {@link WaitingCallback} that'll eventually
-     * contain the result.
-     */
-    private WaitingCallback<Boolean> performActionAsync(String name, Bundle arguments)
-            throws Exception {
-        WaitingCallback<Boolean> callback = new WaitingCallback<Boolean>();
-        Bundle allArguments = new Bundle(arguments);
-        TestThreadUtils.runOnUiThreadBlocking(
-                ()
-                        -> mHandler.performDirectAction(name, allArguments,
-                                (bundle) -> callback.onResult(bundle.getBoolean("success"))));
-        return callback;
-    }
-
-    /**
-     * A callback that allows waiting for the result to be available, then retrieving it.
-     */
-    private static class WaitingCallback<T> implements Callback<T> {
-        private final CallbackHelper mHelper = new CallbackHelper();
-        private boolean mHasResult;
-        private T mResult;
-
-        @Override
-        public synchronized void onResult(T result) {
-            mResult = result;
-            mHasResult = true;
-            mHelper.notifyCalled();
-        }
-
-        synchronized T waitForResult(String msg) throws Exception {
-            if (!mHasResult) mHelper.waitForFirst(msg);
-            assertTrue(mHasResult);
-            return mResult;
-        }
-
-        synchronized boolean hasResult() {
-            return mHasResult;
-        }
-
-        synchronized T getResult() {
-            return mResult;
-        }
-    }
-}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/DirectActionsIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/DirectActionsIntegrationTest.java
deleted file mode 100644
index 94fd95b..0000000
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/DirectActionsIntegrationTest.java
+++ /dev/null
@@ -1,475 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill_assistant;
-
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.not;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.verify;
-
-import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.checkElementExists;
-import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil;
-import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
-import static org.chromium.chrome.browser.autofill_assistant.MiniActionTestUtil.addTapSteps;
-import static org.chromium.chrome.browser.autofill_assistant.ProtoTestUtil.toCssSelector;
-
-import android.os.Bundle;
-
-import androidx.test.espresso.matcher.ViewMatchers.Visibility;
-import androidx.test.filters.MediumTest;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import org.chromium.base.Callback;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.CriteriaNotSatisfiedException;
-import org.chromium.base.test.util.DisabledTest;
-import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.DirectActionProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.InfoBoxProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.ShowInfoBoxProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.StopProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto;
-import org.chromium.chrome.browser.autofill_assistant.proto.TellProto;
-import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
-import org.chromium.chrome.browser.directactions.DirectActionHandler;
-import org.chromium.chrome.browser.directactions.FakeDirectActionReporter;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.preferences.Pref;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-import org.chromium.components.autofill_assistant.AssistantDependencies;
-import org.chromium.components.autofill_assistant.AssistantFeatures;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntry;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntryProvider;
-import org.chromium.components.autofill_assistant.R;
-import org.chromium.components.prefs.PrefService;
-import org.chromium.components.user_prefs.UserPrefs;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Tests Autofill Assistant direct actions.
- */
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Batch(Batch.PER_CLASS)
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class DirectActionsIntegrationTest {
-    public DirectActionsIntegrationTest() {}
-
-    private final CustomTabActivityTestRule mTestRule = new CustomTabActivityTestRule();
-
-    @Rule
-    public final TestRule mRulesChain =
-            RuleChain.outerRule(mTestRule).around(new AutofillAssistantCustomTabTestRule(
-                    mTestRule, "autofill_assistant_target_website.html"));
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    @Mock
-    Callback<Bundle> mDirectActionResultCallback;
-
-    private AutofillAssistantModuleEntry mModuleEntry;
-    private DirectActionHandler mDirectActionHandler;
-    private FakeDirectActionReporter mDirectActionReporter;
-
-    @Before
-    public void setUp() {
-        mDirectActionReporter = new FakeDirectActionReporter();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mModuleEntry =
-                    AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntryIfInstalled();
-            assert mModuleEntry != null;
-            AssistantDependencies dependencies =
-                    new AssistantStaticDependenciesChrome().createDependencies(
-                            mTestRule.getActivity());
-            mDirectActionHandler = AutofillAssistantFacade.createDirectActionHandler(
-                    mTestRule.getActivity(), dependencies.getBottomSheetController(),
-                    mTestRule.getActivity().getBrowserControlsManager(), dependencies.getRootView(),
-                    mTestRule.getActivity().getActivityTabProvider());
-        });
-    }
-
-    @After
-    public void tearDown() {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_CONSENT);
-            prefService.clearPref(Pref.AUTOFILL_ASSISTANT_ENABLED);
-        });
-    }
-
-    /** Sets the value of @param preference to @param value. */
-    private void setBooleanPref(String preference, boolean value) {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
-            prefService.setBoolean(preference, value);
-        });
-    }
-
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    public void
-    testOnboardingAndStart() {
-        setBooleanPref(Pref.AUTOFILL_ASSISTANT_CONSENT, false);
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("onboarding", "onboarding_and_start"));
-        });
-
-        ArrayList<ActionProto> list = new ArrayList<>();
-        // Tapping touch_area_one will make it disappear.
-        addTapSteps(toCssSelector("#touch_area_one"), list);
-
-        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
-                SupportedScriptProto.newBuilder()
-                        .setPath("autofill_assistant_target_website.html")
-                        .setPresentation(PresentationProto.newBuilder().setDirectAction(
-                                DirectActionProto.newBuilder()
-                                        .addNames("some_direct_action")
-                                        .build()))
-                        .build(),
-                list);
-
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.singletonList(script));
-        testService.scheduleForInjection();
-
-        Bundle arguments = new Bundle();
-        arguments.putString("name", "some_direct_action");
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.performDirectAction(
-                    "onboarding_and_start", arguments, mDirectActionResultCallback);
-        });
-
-        waitUntilViewMatchesCondition(withText("I agree"), isDisplayed());
-        onView(withText("I agree")).perform(click());
-
-        waitUntil(() -> !checkElementExists(mTestRule.getWebContents(), "touch_area_one"));
-        verify(mDirectActionResultCallback)
-                .onResult(argThat(bundle -> bundle.getBoolean("success")));
-    }
-
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    public void
-    testOnboardingAndStartShowsErrorMessageIfRequested() {
-        setBooleanPref(Pref.AUTOFILL_ASSISTANT_CONSENT, false);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("onboarding", "onboarding_and_start"));
-        });
-
-        // No scripts available.
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.emptyList());
-        testService.scheduleForInjection();
-
-        Bundle arguments = new Bundle();
-        arguments.putString("name", "some_direct_action");
-        arguments.putBoolean("show_error_on_failure", true);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.performDirectAction(
-                    "onboarding_and_start", arguments, mDirectActionResultCallback);
-        });
-
-        waitUntilViewMatchesCondition(withText("I agree"), isDisplayed());
-        onView(withText("I agree")).perform(click());
-
-        waitUntilViewMatchesCondition(withText("Something went wrong"), isDisplayed());
-        verify(mDirectActionResultCallback)
-                .onResult(argThat(bundle -> !bundle.getBoolean("success")));
-    }
-
-    /**
-     * Regression test for b/200916720.
-     */
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    public void
-    testOnboardingTwice() {
-        setBooleanPref(Pref.AUTOFILL_ASSISTANT_CONSENT, false);
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("onboarding", "onboarding_and_start"));
-        });
-
-        ArrayList<ActionProto> list = new ArrayList<>();
-        // Tapping touch_area_one will make it disappear.
-        addTapSteps(toCssSelector("#touch_area_one"), list);
-
-        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
-                SupportedScriptProto.newBuilder()
-                        .setPath("autofill_assistant_target_website.html")
-                        .setPresentation(PresentationProto.newBuilder().setDirectAction(
-                                DirectActionProto.newBuilder()
-                                        .addNames("some_direct_action")
-                                        .build()))
-                        .build(),
-                list);
-
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.singletonList(script));
-        testService.scheduleForInjection();
-
-        Bundle arguments = new Bundle();
-        arguments.putString("name", "some_direct_action");
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.performDirectAction(
-                    "onboarding_and_start", arguments, mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("I agree"), isDisplayed());
-
-        // Don't agree to the onboarding. Instead, restart the direct action. This tests a case
-        // where the client already exists, but the controller does not.
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.performDirectAction(
-                    "onboarding_and_start", arguments, mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("I agree"), isDisplayed());
-
-        onView(withText("I agree")).perform(click());
-        waitUntil(() -> !checkElementExists(mTestRule.getWebContents(), "touch_area_one"));
-        verify(mDirectActionResultCallback)
-                .onResult(argThat(bundle -> bundle.getBoolean("success")));
-    }
-
-    /**
-     * Regression test for b/195417453.
-     */
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    @DisabledTest(message = "https://crbug.com/1272997")
-    public void
-    testStatusMessageResetsBetweenRuns() {
-        setBooleanPref(Pref.AUTOFILL_ASSISTANT_CONSENT, true);
-
-        ArrayList<ActionProto> list = new ArrayList<>();
-        list.add(ActionProto.newBuilder()
-                         .setPrompt(PromptProto.newBuilder().addChoices(
-                                 PromptProto.Choice.newBuilder().setChip(
-                                         ChipProto.newBuilder().setText("Prompt"))))
-                         .build());
-        list.add(ActionProto.newBuilder()
-                         .setShowInfoBox(ShowInfoBoxProto.newBuilder().setInfoBox(
-                                 InfoBoxProto.newBuilder().setExplanation(
-                                         "InfoBox message from previous run")))
-                         .build());
-        list.add(ActionProto.newBuilder()
-                         .setTell(TellProto.newBuilder().setMessage(
-                                 "Status message from previous run"))
-                         .build());
-        list.add(ActionProto.newBuilder().setStop(StopProto.newBuilder()).build());
-
-        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
-                SupportedScriptProto.newBuilder()
-                        .setPath("autofill_assistant_target_website.html")
-                        .setPresentation(PresentationProto.newBuilder().setDirectAction(
-                                DirectActionProto.newBuilder()
-                                        .addNames("some_direct_action")
-                                        .build()))
-                        .build(),
-                list);
-
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.singletonList(script));
-        testService.scheduleForInjection();
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions"));
-            mDirectActionHandler.performDirectAction(
-                    "fetch_website_actions", new Bundle(), mDirectActionResultCallback);
-            verify(mDirectActionResultCallback)
-                    .onResult(argThat(bundle -> bundle.getBoolean("success")));
-
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions", "some_direct_action"));
-            mDirectActionHandler.performDirectAction(
-                    "some_direct_action", new Bundle(), mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("Prompt"), isDisplayed());
-
-        // Changes the status message, shows the info box, then gracefully stops the script.
-        onView(withText("Prompt")).perform(click());
-
-        // Run the same direct action again, but don't accept the prompt. The script won't run the
-        // showInfoBox and tell actions, thus the UI should be left at startup-default.
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.performDirectAction(
-                    "some_direct_action", new Bundle(), mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("Prompt"), isDisplayed());
-        onView(withText("InfoBox message from previous run")).check(doesNotExist());
-        onView(withId(R.id.info_box_explanation)).check(matches(not(isDisplayed())));
-        onView(withText("Status message from previous run")).check(doesNotExist());
-    }
-
-    /**
-     * Regression test for b/195417125.
-     */
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    public void
-    testLastTellMessageDisplayedAfterStop() {
-        ArrayList<ActionProto> list = new ArrayList<>();
-        list.add(ActionProto.newBuilder()
-                         .setPrompt(PromptProto.newBuilder().addChoices(
-                                 PromptProto.Choice.newBuilder().setChip(
-                                         ChipProto.newBuilder().setText("Prompt"))))
-                         .build());
-        list.add(ActionProto.newBuilder()
-                         .setTell(TellProto.newBuilder().setMessage("Last tell message"))
-                         .build());
-        list.add(ActionProto.newBuilder().setStop(StopProto.newBuilder()).build());
-
-        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
-                SupportedScriptProto.newBuilder()
-                        .setPath("autofill_assistant_target_website.html")
-                        .setPresentation(PresentationProto.newBuilder().setDirectAction(
-                                DirectActionProto.newBuilder()
-                                        .addNames("some_direct_action")
-                                        .build()))
-                        .build(),
-                list);
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.singletonList(script));
-        testService.scheduleForInjection();
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions"));
-            mDirectActionHandler.performDirectAction(
-                    "fetch_website_actions", new Bundle(), mDirectActionResultCallback);
-            verify(mDirectActionResultCallback)
-                    .onResult(argThat(bundle -> bundle.getBoolean("success")));
-
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions", "some_direct_action"));
-            mDirectActionHandler.performDirectAction(
-                    "some_direct_action", new Bundle(), mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("Prompt"), isDisplayed());
-        onView(withText("Prompt")).perform(click());
-        waitUntilViewMatchesCondition(withText("Last tell message"), isDisplayed());
-        // The last tell message should still be visible (and not disappear
-        // immediately) after the script stops.
-        try {
-            waitUntilViewMatchesCondition(withText("Last tell message"), not(isDisplayed()), 200);
-        } catch (AssertionError e) {
-            if (e.getCause() instanceof CriteriaNotSatisfiedException) {
-                // This is ok, the view is still there, the test succeeds.
-                return;
-            }
-            throw e;
-        }
-        throw new CriteriaNotSatisfiedException(
-                "Expected last tell message to be visible after stop");
-    }
-
-    /**
-     * Regression test for b/224759196.
-     */
-    @Test
-    @MediumTest
-    @EnableFeatures({ChromeFeatureList.DIRECT_ACTIONS, AssistantFeatures.AUTOFILL_ASSISTANT_NAME,
-            AssistantFeatures.AUTOFILL_ASSISTANT_DIRECT_ACTIONS_NAME})
-    public void
-    testCloseDirectAction() {
-        ArrayList<ActionProto> list = new ArrayList<>();
-        list.add(ActionProto.newBuilder()
-                         .setPrompt(PromptProto.newBuilder().addChoices(
-                                 PromptProto.Choice.newBuilder().setChip(
-                                         ChipProto.newBuilder().setText("Prompt"))))
-                         .build());
-        list.add(ActionProto.newBuilder()
-                         .setTell(TellProto.newBuilder().setMessage("Last tell message"))
-                         .build());
-        list.add(ActionProto.newBuilder().setStop(StopProto.newBuilder()).build());
-
-        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
-                SupportedScriptProto.newBuilder()
-                        .setPath("autofill_assistant_target_website.html")
-                        .setPresentation(PresentationProto.newBuilder().setDirectAction(
-                                DirectActionProto.newBuilder()
-                                        .addNames("some_direct_action")
-                                        .build()))
-                        .build(),
-                list);
-        AutofillAssistantTestService testService =
-                new AutofillAssistantTestService(Collections.singletonList(script));
-        testService.scheduleForInjection();
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions"));
-            mDirectActionHandler.performDirectAction(
-                    "fetch_website_actions", new Bundle(), mDirectActionResultCallback);
-            verify(mDirectActionResultCallback)
-                    .onResult(argThat(bundle -> bundle.getBoolean("success")));
-
-            mDirectActionHandler.reportAvailableDirectActions(mDirectActionReporter);
-            Assert.assertThat(mDirectActionReporter.getDirectActions(),
-                    containsInAnyOrder("fetch_website_actions", "some_direct_action"));
-            mDirectActionHandler.performDirectAction(
-                    "some_direct_action", new Bundle(), mDirectActionResultCallback);
-        });
-        waitUntilViewMatchesCondition(withText("Prompt"), isDisplayed());
-        onView(withText("Prompt")).perform(click());
-        waitUntilViewMatchesCondition(withText("Last tell message"), isDisplayed());
-        onView(allOf(withContentDescription("Close"), withEffectiveVisibility(Visibility.VISIBLE)))
-                .perform(click());
-    }
-}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java
deleted file mode 100644
index a2b62ab..0000000
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill_assistant;
-
-import android.content.Context;
-import android.view.View;
-
-import org.chromium.base.Callback;
-import org.chromium.base.supplier.Supplier;
-import org.chromium.components.autofill_assistant.AssistantBrowserControlsFactory;
-import org.chromium.components.autofill_assistant.AssistantDependencies;
-import org.chromium.components.autofill_assistant.AssistantModuleInstallUi;
-import org.chromium.components.autofill_assistant.AssistantOnboardingHelper;
-import org.chromium.components.autofill_assistant.AssistantStaticDependencies;
-import org.chromium.components.autofill_assistant.AutofillAssistantActionHandler;
-import org.chromium.components.autofill_assistant.AutofillAssistantActionHandlerImpl;
-import org.chromium.components.autofill_assistant.AutofillAssistantDirectAction;
-import org.chromium.components.autofill_assistant.AutofillAssistantDirectActionImpl;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntry;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntryProvider;
-import org.chromium.components.autofill_assistant.onboarding.OnboardingCoordinatorFactory;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.content_public.browser.WebContents;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Implementation of {@link AutofillAssistantModuleEntryProvider} that can be manipulated to
- * simulate missing or uninstallable module.
- */
-class TestingAutofillAssistantModuleEntryProvider extends AutofillAssistantModuleEntryProvider {
-    private boolean mNotInstalled;
-    private boolean mCannotInstall;
-
-    /*
-     * Mock action handler. We only override returning dynamic actions.
-     *
-     * TODO(crbug/806868): Inject a service also for the DirectAction path and get rid of this
-     * mock.
-     */
-    static class MockAutofillAssistantActionHandler extends AutofillAssistantActionHandlerImpl {
-        public MockAutofillAssistantActionHandler(Context context,
-                BottomSheetController bottomSheetController,
-                AssistantBrowserControlsFactory browserControlsFactory, View rootView,
-                Supplier<WebContents> webContentsSupplier,
-                AssistantStaticDependencies staticDependencies) {
-            super(new OnboardingCoordinatorFactory(context, bottomSheetController,
-                          staticDependencies.getBrowserContext(), browserControlsFactory, rootView,
-                          staticDependencies.getAccessibilityUtil(),
-                          staticDependencies.createInfoPageUtil()),
-                    webContentsSupplier, staticDependencies);
-        }
-
-        @Override
-        public List<AutofillAssistantDirectAction> getActions() {
-            String[] search = new String[] {"search"};
-            String[] required = new String[] {"SEARCH_QUERY"};
-            String[] optional = new String[] {"arg2"};
-            String[] action2 = new String[] {"action2", "action2_alias"};
-            AutofillAssistantDirectAction[] actions = new AutofillAssistantDirectActionImpl[] {
-                    new AutofillAssistantDirectActionImpl(search, required, optional),
-                    new AutofillAssistantDirectActionImpl(action2, required, optional)};
-            return new ArrayList<>(Arrays.asList(actions));
-        }
-    }
-
-    /** Mock module entry. */
-    static class MockAutofillAssistantModuleEntry implements AutofillAssistantModuleEntry {
-        @Override
-        public AssistantOnboardingHelper createOnboardingHelper(
-                WebContents webContents, AssistantDependencies dependencies) {
-            return null;
-        }
-
-        @Override
-        public AutofillAssistantActionHandler createActionHandler(Context context,
-                BottomSheetController bottomSheetController,
-                AssistantBrowserControlsFactory browserControlsFactory, View rootView,
-                Supplier<WebContents> webContentsSupplier,
-                AssistantStaticDependencies staticDependencies) {
-            return new MockAutofillAssistantActionHandler(context, bottomSheetController,
-                    browserControlsFactory, rootView, webContentsSupplier, staticDependencies);
-        }
-    }
-
-    /** The module is already installed. This is the default state. */
-    public void setInstalled() {
-        mNotInstalled = false;
-        mCannotInstall = false;
-    }
-
-    /** The module is not installed, but can be installed. */
-    public void setNotInstalled() {
-        mNotInstalled = true;
-        mCannotInstall = false;
-    }
-
-    /** The module is not installed, and cannot be installed. */
-    public void setCannotInstall() {
-        mNotInstalled = true;
-        mCannotInstall = true;
-    }
-
-    @Override
-    public AutofillAssistantModuleEntry getModuleEntryIfInstalled() {
-        if (mNotInstalled) return null;
-        return new MockAutofillAssistantModuleEntry();
-    }
-
-    @Override
-    public void getModuleEntry(Callback<AutofillAssistantModuleEntry> callback,
-            AssistantModuleInstallUi.Provider moduleInstallUiProvider, boolean showUi) {
-        if (mCannotInstall) {
-            callback.onResult(null);
-            return;
-        }
-        mNotInstalled = false;
-        super.getModuleEntry(callback, moduleInstallUiProvider, showUi);
-    }
-}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java
deleted file mode 100644
index 9d11f7e..0000000
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.autofill_assistant;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-
-import androidx.annotation.Nullable;
-
-import org.chromium.base.Callback;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.ActivityTabProvider;
-import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
-import org.chromium.chrome.browser.directactions.DirectActionHandler;
-import org.chromium.chrome.browser.directactions.DirectActionReporter;
-import org.chromium.chrome.browser.directactions.DirectActionReporter.Definition;
-import org.chromium.chrome.browser.directactions.DirectActionReporter.Type;
-import org.chromium.chrome.browser.preferences.Pref;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.components.autofill_assistant.AutofillAssistantActionHandler;
-import org.chromium.components.autofill_assistant.AutofillAssistantDirectAction;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntry;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntryProvider;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.prefs.PrefService;
-import org.chromium.components.user_prefs.UserPrefs;
-import org.chromium.content_public.browser.WebContents;
-
-/**
- * A handler that provides just enough functionality to allow on-demand loading of the module
- * through direct actions. The actual implementation is in the module.
- */
-public class AutofillAssistantDirectActionHandler implements DirectActionHandler {
-    private static final String FETCH_WEBSITE_ACTIONS = "fetch_website_actions";
-    private static final String FETCH_WEBSITE_ACTIONS_RESULT = "success";
-    private static final String AA_ACTION_RESULT = "success";
-    private static final String ACTION_NAME = "name";
-    private static final String EXPERIMENT_IDS = "experiment_ids";
-    private static final String ONBOARDING_ACTION = "onboarding";
-    private static final String ONBOARDING_AND_START_ACTION = "onboarding_and_start";
-    private static final String USER_NAME = "user_name";
-    private static final String SHOW_ERROR_ON_FAILURE = "show_error_on_failure";
-
-    private final Context mContext;
-    private final BottomSheetController mBottomSheetController;
-    private final BrowserControlsStateProvider mBrowserControls;
-    private final View mRootView;
-    private final ActivityTabProvider mActivityTabProvider;
-    private final Supplier<WebContents> mWebContentsSupplier;
-    private final AutofillAssistantModuleEntryProvider mModuleEntryProvider;
-
-    @Nullable
-    private AutofillAssistantActionHandler mDelegate;
-
-    AutofillAssistantDirectActionHandler(Context context,
-            BottomSheetController bottomSheetController,
-            BrowserControlsStateProvider browserControls, View rootView,
-            ActivityTabProvider activityTabProvider, Supplier<WebContents> webContentsSupplier,
-            AutofillAssistantModuleEntryProvider moduleEntryProvider) {
-        mContext = context;
-        mBottomSheetController = bottomSheetController;
-        mBrowserControls = browserControls;
-        mRootView = rootView;
-        mActivityTabProvider = activityTabProvider;
-        mWebContentsSupplier = webContentsSupplier;
-        mModuleEntryProvider = moduleEntryProvider;
-    }
-
-    private PrefService getPrefs() {
-        return UserPrefs.get(Profile.getLastUsedRegularProfile());
-    }
-
-    @Override
-    public void reportAvailableDirectActions(DirectActionReporter reporter) {
-        ThreadUtils.assertOnUiThread();
-
-        if (!getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_ENABLED)) {
-            return;
-        }
-
-        if (!getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT)) {
-            reporter.addDirectAction(ONBOARDING_ACTION)
-                    .withParameter(ACTION_NAME, Type.STRING, /* required= */ false)
-                    .withParameter(EXPERIMENT_IDS, Type.STRING, /* required= */ false)
-                    .withResult(AA_ACTION_RESULT, Type.BOOLEAN);
-            reporter.addDirectAction(ONBOARDING_AND_START_ACTION)
-                    .withParameter(ACTION_NAME, Type.STRING, /* required= */ true)
-                    .withParameter(USER_NAME, Type.STRING, /* required= */ false)
-                    .withParameter(EXPERIMENT_IDS, Type.STRING, /* required= */ false)
-                    .withParameter(SHOW_ERROR_ON_FAILURE, Type.BOOLEAN, /* required= */ false)
-                    .withResult(AA_ACTION_RESULT, Type.BOOLEAN);
-            return;
-        }
-
-        if (mDelegate == null || (mDelegate != null && !mDelegate.hasRunFirstCheck())) {
-            reporter.addDirectAction(FETCH_WEBSITE_ACTIONS)
-                    .withParameter(USER_NAME, Type.STRING, /* required= */ false)
-                    .withParameter(EXPERIMENT_IDS, Type.STRING, /* required= */ false)
-                    .withResult(FETCH_WEBSITE_ACTIONS_RESULT, Type.BOOLEAN);
-        } else {
-            // Otherwise we are already done fetching scripts and can just return the ones we know
-            // about.
-            for (AutofillAssistantDirectAction action : mDelegate.getActions()) {
-                for (String name : action.getNames()) {
-                    Definition definition = reporter.addDirectAction(name)
-                                                    .withParameter(EXPERIMENT_IDS, Type.STRING,
-                                                            /* required= */ false)
-                                                    .withResult(AA_ACTION_RESULT, Type.BOOLEAN);
-
-                    // TODO(b/138833619): Support non-string arguments. Requires updating the proto
-                    // definition.
-                    for (String required : action.getRequiredArguments()) {
-                        definition.withParameter(required, Type.STRING, /* required= */ true);
-                    }
-                    for (String optional : action.getOptionalArguments()) {
-                        definition.withParameter(optional, Type.STRING, /* required= */ false);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean performDirectAction(
-            String actionId, Bundle arguments, Callback<Bundle> callback) {
-        if (actionId.equals(FETCH_WEBSITE_ACTIONS)
-                && getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT)) {
-            fetchWebsiteActions(arguments, callback);
-            return true;
-        }
-        // Only handle and perform the action if it is known to the controller.
-        if (isActionAvailable(actionId) || ONBOARDING_ACTION.equals(actionId)
-                || ONBOARDING_AND_START_ACTION.equals(actionId)) {
-            performAction(actionId, arguments, callback);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isActionAvailable(String actionId) {
-        if (mDelegate == null || !mDelegate.hasRunFirstCheck()) return false;
-        for (AutofillAssistantDirectAction action : mDelegate.getActions()) {
-            if (action.getNames().contains(actionId)) return true;
-        }
-        return false;
-    }
-
-    private void fetchWebsiteActions(Bundle arguments, Callback<Bundle> bundleCallback) {
-        Callback<Boolean> successCallback = (success) -> {
-            Bundle bundle = new Bundle();
-            bundle.putBoolean(FETCH_WEBSITE_ACTIONS_RESULT, success);
-            bundleCallback.onResult(bundle);
-        };
-
-        if (!getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_ENABLED)
-                || !getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_CONSENT)) {
-            successCallback.onResult(false);
-            return;
-        }
-
-        String userName = arguments.getString(USER_NAME, "");
-        arguments.remove(USER_NAME);
-
-        String experimentIds = arguments.getString(EXPERIMENT_IDS, "");
-        arguments.remove(EXPERIMENT_IDS);
-
-        getDelegate(/* installIfNecessary= */ false, (delegate) -> {
-            if (delegate == null) {
-                successCallback.onResult(false);
-                return;
-            }
-            delegate.fetchWebsiteActions(userName, experimentIds, arguments, successCallback);
-        });
-    }
-
-    private void performAction(String actionId, Bundle arguments, Callback<Bundle> bundleCallback) {
-        Callback<Boolean> booleanCallback = (result) -> {
-            Bundle bundle = new Bundle();
-            bundle.putBoolean(AA_ACTION_RESULT, result);
-            bundleCallback.onResult(bundle);
-        };
-
-        if (!getPrefs().getBoolean(Pref.AUTOFILL_ASSISTANT_ENABLED)) {
-            booleanCallback.onResult(false);
-            return;
-        }
-
-        String experimentIds = arguments.getString(EXPERIMENT_IDS, "");
-        arguments.remove(EXPERIMENT_IDS);
-
-        getDelegate(/* installIfNecessary= */ true, (delegate) -> {
-            if (delegate == null) {
-                booleanCallback.onResult(false);
-                return;
-            }
-            if (delegate.isSupervisedUser()) {
-                booleanCallback.onResult(false);
-                return;
-            }
-            if (ONBOARDING_ACTION.equals(actionId)) {
-                delegate.performOnboarding(experimentIds, arguments, booleanCallback);
-                return;
-            }
-            if (ONBOARDING_AND_START_ACTION.equals(actionId)) {
-                delegate.performOnboarding(experimentIds, arguments, onboardingResult -> {
-                    if (!onboardingResult) {
-                        booleanCallback.onResult(false);
-                        return;
-                    }
-                    boolean showErrorOnFailure = arguments.getBoolean(SHOW_ERROR_ON_FAILURE, false);
-                    delegate.fetchWebsiteActions(arguments.getString(USER_NAME, ""),
-                            arguments.getString(EXPERIMENT_IDS, ""), arguments,
-                            fetchActionsResult -> {
-                                if (!fetchActionsResult) {
-                                    booleanCallback.onResult(false);
-                                    if (showErrorOnFailure) {
-                                        delegate.showFatalError();
-                                    }
-                                    return;
-                                }
-                                String afterOnboardingActionId =
-                                        arguments.getString(ACTION_NAME, "");
-                                if (!isActionAvailable(afterOnboardingActionId)) {
-                                    booleanCallback.onResult(false);
-                                    if (showErrorOnFailure) {
-                                        delegate.showFatalError();
-                                    }
-                                    return;
-                                }
-                                delegate.performAction(afterOnboardingActionId, experimentIds,
-                                        arguments, booleanCallback);
-                            });
-                });
-                return;
-            }
-
-            Callback<Boolean> successCallback = (success) -> {
-                booleanCallback.onResult(success && !delegate.getActions().isEmpty());
-            };
-            delegate.performAction(actionId, experimentIds, arguments, successCallback);
-        });
-    }
-
-    /**
-     * Builds the delegate, if possible, and pass it to the callback.
-     *
-     * <p>If necessary, this function creates a delegate instance and keeps it in {@link
-     * #mDelegate}.
-     *
-     * @param installIfNecessary if true, install the DFM if necessary
-     * @param callback callback to report the delegate to
-     */
-    private void getDelegate(
-            boolean installIfNecessary, Callback<AutofillAssistantActionHandler> callback) {
-        if (mDelegate == null) {
-            mDelegate = createDelegate(mModuleEntryProvider.getModuleEntryIfInstalled());
-        }
-        if (mDelegate != null || !installIfNecessary) {
-            callback.onResult(mDelegate);
-            return;
-        }
-
-        Tab tab = mActivityTabProvider.get();
-        if (tab == null) {
-            // TODO(b/134741524): Allow DFM loading UI to work with no tabs.
-            callback.onResult(null);
-            return;
-        }
-        mModuleEntryProvider.getModuleEntry((entry) -> {
-            mDelegate = createDelegate(entry);
-            callback.onResult(mDelegate);
-        }, new AssistantModuleInstallUiProviderChrome(tab), /* showUi = */ true);
-    }
-
-    /** Creates a delegate from the given {@link AutofillAssistantModuleEntry}, if possible. */
-    @Nullable
-    private AutofillAssistantActionHandler createDelegate(
-            @Nullable AutofillAssistantModuleEntry entry) {
-        if (entry == null) return null;
-
-        return entry.createActionHandler(mContext, mBottomSheetController,
-                ()
-                        -> new AssistantBrowserControlsChrome(mBrowserControls),
-                mRootView, mWebContentsSupplier, new AssistantStaticDependenciesChrome());
-    }
-}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
index 39581be4..5db3019 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -5,29 +5,22 @@
 package org.chromium.chrome.browser.autofill_assistant;
 
 import android.app.Activity;
-import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.text.TextUtils;
-import android.view.View;
 
 import androidx.annotation.Nullable;
 
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
-import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.app.ChromeActivity;
-import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
-import org.chromium.chrome.browser.directactions.DirectActionHandler;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.autofill_assistant.AssistantFeatures;
 import org.chromium.components.autofill_assistant.AutofillAssistantMetrics;
-import org.chromium.components.autofill_assistant.AutofillAssistantModuleEntryProvider;
 import org.chromium.components.autofill_assistant.TriggerContext;
 import org.chromium.components.autofill_assistant.metrics.DropOutReason;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.external_intents.ExternalNavigationDelegate.IntentToAutofillAllowingAppResult;
 import org.chromium.content_public.browser.WebContents;
 
@@ -95,24 +88,6 @@
                 tab -> { AutofillAssistantTabHelper.get(tab).start(triggerContext); });
     }
 
-    /**
-     * Returns a {@link DirectActionHandler} for making dynamic actions available under Android Q.
-     *
-     * <p>This should only be called if {@link
-     * AssistantDependencyUtilsChrome#areDirectActionsAvailable} returns true. This method can also
-     * return null if autofill assistant is not available for some other reasons.
-     */
-    public static DirectActionHandler createDirectActionHandler(Context context,
-            BottomSheetController bottomSheetController,
-            BrowserControlsStateProvider browserControls, View rootView,
-            ActivityTabProvider activityTabProvider) {
-        Supplier<WebContents> webContentsSupplier = () -> getWebContents(activityTabProvider);
-
-        return new AutofillAssistantDirectActionHandler(context, bottomSheetController,
-                browserControls, rootView, activityTabProvider, webContentsSupplier,
-                AutofillAssistantModuleEntryProvider.INSTANCE);
-    }
-
     /** Provides the callback with a tab, waits if necessary. */
     private static void waitForTab(ChromeActivity activity, Callback<Tab> callback) {
         if (activity.getActivityTab() != null) {
diff --git a/chrome/android/features/autofill_assistant/public/java_sources.gni b/chrome/android/features/autofill_assistant/public/java_sources.gni
index 141ee5c..4b1d91b 100644
--- a/chrome/android/features/autofill_assistant/public/java_sources.gni
+++ b/chrome/android/features/autofill_assistant/public/java_sources.gni
@@ -22,7 +22,6 @@
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTabChangeObserverChrome.java",
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTabObscuringUtilChrome.java",
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTabUtilChrome.java",
-  "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandler.java",
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java",
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHistoryDeletionObserver.java",
   "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTabHelper.java",
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index 422c816f..b20d6fe 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -61,6 +61,7 @@
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java",
+    "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
index a51fd7b..60987a93 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -411,8 +411,8 @@
     private void transitionIntoState(@KeyboardExtensionState int extensionState) {
         if (!meetsStatePreconditions(extensionState)) return;
         TraceEvent.begin("ManualFillingMediator#transitionIntoState");
-        enforceStateProperties(extensionState);
         changeBottomControlSpaceForState(extensionState);
+        enforceStateProperties(extensionState); // Triggers a relayout. Call after changing insets.
         updateKeyboard(extensionState);
         TraceEvent.end("ManualFillingMediator#transitionIntoState");
     }
@@ -559,6 +559,11 @@
         }
     }
 
+    @Override
+    public void onBarFadeInAnimationEnd() {
+        mActivity.getCurrentWebContents().scrollFocusedEditableNodeIntoView();
+    }
+
     /**
      * Opens the keyboard which implicitly dismisses the sheet. Without open sheet, this is a NoOp.
      */
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
index c2a57423e..e70b07d 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -62,6 +62,12 @@
          * Called when the sheet needs to be hidden.
          */
         void onCloseAccessorySheet();
+
+        /**
+         * Signals that the accessory bar has completed the fade-in. This may be relevant to the
+         * keyboard extensions state to adjust the scroll position.
+         */
+        void onBarFadeInAnimationEnd();
     }
 
     /**
@@ -245,6 +251,7 @@
      * while the view might still be in progress of being updated accordingly.
      * @return True if the accessory should be visible, false otherwise.
      */
+    // TODO(crbug/1385400): Hide because it's only used in tests.
     public boolean isShown() {
         return mMediator.isShown();
     }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
index 6c08148..6f97991 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.bar_component;
 
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING;
@@ -73,6 +74,7 @@
         mModel.set(OBFUSCATED_CHILD_AT_CALLBACK, this::onSuggestionObfuscatedAt);
         mModel.set(SHOW_KEYBOARD_CALLBACK, this::closeSheet);
         mModel.set(SHEET_OPENER_ITEM, new SheetOpenerBarItem(sheetOpenerCallbacks));
+        mModel.set(ANIMATION_LISTENER, mVisibilityDelegate::onBarFadeInAnimationEnd);
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY)) {
             mModel.get(BAR_ITEMS).add(mModel.get(SHEET_OPENER_ITEM));
         }
@@ -275,7 +277,7 @@
                 || propertyKey == SKIP_CLOSING_ANIMATION
                 || propertyKey == DISABLE_ANIMATIONS_FOR_TESTING
                 || propertyKey == OBFUSCATED_CHILD_AT_CALLBACK || propertyKey == SHOW_SWIPING_IPH
-                || propertyKey == HAS_SUGGESTIONS) {
+                || propertyKey == HAS_SUGGESTIONS || propertyKey == ANIMATION_LISTENER) {
             return;
         }
         assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
index 36a06708..10ac0ca 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java
@@ -78,7 +78,8 @@
                     || propertyKey == KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING
                     || propertyKey == KeyboardAccessoryProperties.SHOW_SWIPING_IPH
                     || propertyKey == KeyboardAccessoryProperties.OBFUSCATED_CHILD_AT_CALLBACK
-                    || propertyKey == KeyboardAccessoryProperties.HAS_SUGGESTIONS) {
+                    || propertyKey == KeyboardAccessoryProperties.HAS_SUGGESTIONS
+                    || propertyKey == KeyboardAccessoryProperties.ANIMATION_LISTENER) {
                 return;
             }
             assert false : "Every property update needs to be handled explicitly!";
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
index 93c12a3..c12ee56b 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
@@ -13,12 +13,14 @@
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_KEYBOARD_CALLBACK;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.SHOW_SWIPING_IPH;
 
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.chromium.base.TraceEvent;
+import org.chromium.chrome.browser.autofill.AutofillUiUtils;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.keyboard_accessory.R;
 import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.AutofillBarItem;
@@ -104,16 +106,19 @@
             // the event that the bitmap is not present in the PersonalDataManager, fall back to the
             // default `iconId`.
             Bitmap customIconBitmap = null;
+            Resources res = chipView.getContext().getResources();
             if (item.getSuggestion().getCustomIconUrl() != null
                     && item.getSuggestion().getCustomIconUrl().isValid()) {
-                customIconBitmap = PersonalDataManager.getInstance()
-                                           .getCustomImageForAutofillSuggestionIfAvailable(
-                                                   item.getSuggestion().getCustomIconUrl());
+                customIconBitmap =
+                        PersonalDataManager.getInstance().getCustomImageForAutofillSuggestionIfAvailable(
+                                AutofillUiUtils.getCCIconURLWithParams(
+                                        item.getSuggestion().getCustomIconUrl(),
+                                        res.getDimensionPixelSize(
+                                                R.dimen.keyboard_accessory_bar_item_cc_icon_width),
+                                        res.getDimensionPixelSize(R.dimen.chip_icon_size)));
             }
             if (customIconBitmap != null) {
-                chipView.setIcon(new BitmapDrawable(mRootViewForIPH.getContext().getResources(),
-                                         customIconBitmap),
-                        false);
+                chipView.setIcon(new BitmapDrawable(res, customIconBitmap), false);
             } else {
                 chipView.setIcon(iconId != 0 ? iconId : ChipView.INVALID_ICON_ID, false);
             }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
index 74fceffd..164cbf6 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
@@ -56,12 +56,15 @@
     static final WritableBooleanPropertyKey HAS_SUGGESTIONS =
             new WritableBooleanPropertyKey("has_suggestions");
 
+    static final WritableObjectPropertyKey<KeyboardAccessoryView.AnimationListener>
+            ANIMATION_LISTENER = new WritableObjectPropertyKey<>("animation_listener");
+
     static PropertyModel.Builder defaultModelBuilder() {
         return new PropertyModel
                 .Builder(DISABLE_ANIMATIONS_FOR_TESTING, BAR_ITEMS, VISIBLE, SKIP_CLOSING_ANIMATION,
                         BOTTOM_OFFSET_PX, SHEET_OPENER_ITEM, KEYBOARD_TOGGLE_VISIBLE, SHEET_TITLE,
                         SHOW_KEYBOARD_CALLBACK, OBFUSCATED_CHILD_AT_CALLBACK, SHOW_SWIPING_IPH,
-                        HAS_SUGGESTIONS)
+                        HAS_SUGGESTIONS, ANIMATION_LISTENER)
                 .with(BAR_ITEMS, new ListModel<>())
                 .with(VISIBLE, false)
                 .with(SKIP_CLOSING_ANIMATION, false)
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
index 26b97a8..3e18e80 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
@@ -16,6 +16,7 @@
 import android.widget.LinearLayout;
 
 import androidx.annotation.CallSuper;
+import androidx.annotation.VisibleForTesting;
 import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -40,6 +41,16 @@
     private boolean mShouldSkipClosingAnimation;
     private boolean mDisableAnimations;
 
+    /** Interface that allows to react to animations. */
+    interface AnimationListener {
+        /**
+         * Called if the accessory bar stopped fading in. The fade-in only happens sometimes, e.g.
+         * if the bar is already visible or animations are disabled, this signal is not issued.
+         */
+        void onFadeInEnd();
+    }
+    private AnimationListener mAnimationListener;
+
     protected static class HorizontalDividerItemDecoration extends RecyclerView.ItemDecoration {
         private final int mHorizontalMargin;
 
@@ -133,6 +144,10 @@
         mBarItemsView.setAdapter(adapter);
     }
 
+    void setAnimationListener(AnimationListener animationListener) {
+        mAnimationListener = animationListener;
+    }
+
     /** Template method. Override to be notified if the bar items change. */
     @CallSuper
     protected void onItemsChanged() {}
@@ -140,7 +155,10 @@
     private void show() {
         TraceEvent.begin("KeyboardAccessoryView#show");
         bringToFront(); // Needs to overlay every component and the bottom sheet - like a keyboard.
-        if (mRunningAnimation != null) mRunningAnimation.cancel();
+        if (mRunningAnimation != null) {
+            mRunningAnimation.cancel();
+            mRunningAnimation = null;
+        }
         if (areAnimationsDisabled()) {
             mRunningAnimation = null;
             setVisibility(View.VISIBLE);
@@ -151,13 +169,20 @@
                                     .alpha(1f)
                                     .setDuration(FADE_ANIMATION_DURATION_MS)
                                     .setInterpolator(new AccelerateInterpolator())
-                                    .withStartAction(() -> setVisibility(View.VISIBLE));
+                                    .withStartAction(() -> setVisibility(View.VISIBLE))
+                                    .withEndAction(() -> {
+                                        mAnimationListener.onFadeInEnd();
+                                        mRunningAnimation = null;
+                                    });
         announceForAccessibility(getContentDescription());
         TraceEvent.end("KeyboardAccessoryView#show");
     }
 
     private void hide() {
-        if (mRunningAnimation != null) mRunningAnimation.cancel();
+        if (mRunningAnimation != null) {
+            mRunningAnimation.cancel();
+            mRunningAnimation = null;
+        }
         if (mShouldSkipClosingAnimation || areAnimationsDisabled()) {
             mRunningAnimation = null;
             setVisibility(View.GONE);
@@ -169,7 +194,10 @@
                         .setInterpolator(new AccelerateInterpolator())
                         .setStartDelay(HIDING_ANIMATION_DELAY_MS)
                         .setDuration(FADE_ANIMATION_DURATION_MS - HIDING_ANIMATION_DELAY_MS)
-                        .withEndAction(() -> setVisibility(View.GONE));
+                        .withEndAction(() -> {
+                            setVisibility(View.GONE);
+                            mRunningAnimation = null;
+                        });
     }
 
     void setSkipClosingAnimation(boolean shouldSkipClosingAnimation) {
@@ -201,4 +229,9 @@
 
         ViewCompat.setPaddingRelative(recyclerView, pad, 0, 0, 0);
     }
+
+    @VisibleForTesting
+    boolean hasRunningAnimation() {
+        return mRunningAnimation != null;
+    }
 }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
index b9dedba..b233e1a 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.bar_component;
 
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BOTTOM_OFFSET_PX;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.DISABLE_ANIMATIONS_FOR_TESTING;
@@ -113,6 +114,8 @@
             if (!model.get(VISIBLE)) view.setVisible(false); // Update to cancel any animation.
         } else if (propertyKey == BOTTOM_OFFSET_PX) {
             view.setBottomOffset(model.get(BOTTOM_OFFSET_PX));
+        } else if (propertyKey == ANIMATION_LISTENER) {
+            view.setAnimationListener(model.get(ANIMATION_LISTENER));
         } else if (propertyKey == SHOW_KEYBOARD_CALLBACK || propertyKey == KEYBOARD_TOGGLE_VISIBLE
                 || propertyKey == SHEET_TITLE || propertyKey == SHEET_OPENER_ITEM
                 || propertyKey == OBFUSCATED_CHILD_AT_CALLBACK || propertyKey == SHOW_SWIPING_IPH
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java
index 73e2acae..711ecf2 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewBinder.java
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.keyboard_accessory.sheet_tabs;
+
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.view.View;
@@ -12,6 +14,7 @@
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.chrome.browser.autofill.AutofillUiUtils;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.keyboard_accessory.R;
 import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
@@ -78,13 +81,18 @@
             // the event that the bitmap is not present in the PersonalDataManager, fall back to the
             // icon corresponding to the `mOrigin`.
             Bitmap iconBitmap = null;
+            Resources res = view.getContext().getResources();
             if (info.getIconUrl() != null && info.getIconUrl().isValid()) {
                 iconBitmap =
-                        PersonalDataManager.getInstance()
-                                .getCustomImageForAutofillSuggestionIfAvailable(info.getIconUrl());
+                        PersonalDataManager.getInstance().getCustomImageForAutofillSuggestionIfAvailable(
+                                AutofillUiUtils.getCCIconURLWithParams(info.getIconUrl(),
+                                        res.getDimensionPixelSize(
+                                                R.dimen.keyboard_accessory_bar_item_cc_icon_width),
+                                        res.getDimensionPixelSize(
+                                                R.dimen.keyboard_accessory_suggestion_icon_size)));
             }
             if (iconBitmap != null) {
-                view.setIcon(new BitmapDrawable(view.getContext().getResources(), iconBitmap));
+                view.setIcon(new BitmapDrawable(res, iconBitmap));
             } else {
                 view.setIcon(AppCompatResources.getDrawable(
                         view.getContext(), getDrawableForOrigin(info.getOrigin())));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
index 5f3f7e7..9e1147a 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -8,6 +8,8 @@
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
+import static androidx.test.espresso.contrib.RecyclerViewActions.scrollTo;
 import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
 import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -15,12 +17,12 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
-import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertNotNull;
 
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
+import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.waitToBeHidden;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
@@ -138,8 +140,11 @@
         onView(withChild(withId(R.id.keyboard_accessory_sheet))).check(doesNotExist());
 
         // Trigger the sheet and wait for it to open and the keyboard to disappear.
-        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
     }
@@ -182,8 +187,11 @@
         onView(withChild(withId(R.id.keyboard_accessory_sheet))).check(doesNotExist());
 
         // Trigger the sheet and wait for it to open and the keyboard to disappear.
-        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet))).check((view, e) -> {
             accessorySheetView.set(view);
@@ -236,14 +244,12 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
         // Click the tab again to hide the sheet and show the keyboard.
-        onView(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardAccessoryToBeShown();
         onView(withId(R.id.keyboard_accessory)).check(matches(isDisplayed()));
         waitToBeHidden(withChild(withId(R.id.keyboard_accessory_sheet)));
@@ -262,7 +268,7 @@
         // Focus the password field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()));
+        whenDisplayed(isKeyboardAccessoryTabLayout());
 
         // Clicking a field without completion hides the accessory again.
         mHelper.clickFieldWithoutCompletion();
@@ -280,8 +286,11 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -304,8 +313,11 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -327,8 +339,11 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
     }
@@ -347,8 +362,11 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
 
@@ -429,8 +447,11 @@
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
@@ -479,8 +500,11 @@
         onView(withText(kSnackbarText)).check(matches(isCompletelyDisplayed()));
 
         // Open a keyboard accessory sheet -- this also shouldn't hide the snackbar.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         onView(withText(kSnackbarText)).check(matches(isCompletelyDisplayed()));
 
@@ -516,8 +540,11 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.password_accessory_sheet_toggle)));
         whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet)));
         assertThat(mActivityTestRule.getInfoBarContainer().getVisibility(), is(not(View.VISIBLE)));
 
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
index 8807c2c..4ea31d2d 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
@@ -12,6 +12,12 @@
 import static org.hamcrest.core.AllOf.allOf;
 
 import static org.chromium.autofill.mojom.FocusedFieldType.FILLABLE_NON_SEARCH_FIELD;
+import static org.chromium.base.test.util.CriteriaHelper.pollInstrumentationThread;
+import static org.chromium.base.test.util.CriteriaHelper.pollUiThread;
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryStartedHiding;
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryStartedShowing;
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryViewFullyHidden;
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryTestHelper.accessoryViewFullyShown;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
 import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
 import static org.chromium.ui.test.util.ViewUtils.VIEW_GONE;
@@ -37,7 +43,6 @@
 
 import com.google.android.material.tabs.TabLayout;
 
-import org.chromium.ui.widget.ChromeImageButton;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
@@ -45,7 +50,6 @@
 
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.Criteria;
-import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.browser.ChromeWindow;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
@@ -69,6 +73,7 @@
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.net.test.ServerCertificate;
 import org.chromium.ui.DropdownPopupWindowInterface;
+import org.chromium.ui.widget.ChromeImageButton;
 
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
@@ -239,7 +244,7 @@
     // ---------------------------------
 
     public void waitForKeyboardToDisappear() {
-        CriteriaHelper.pollUiThread(() -> {
+        pollUiThread(() -> {
             Activity activity = mActivityTestRule.getActivity();
             return !getKeyboard().isAndroidSoftKeyboardShowing(
                     activity, activity.getCurrentFocus());
@@ -247,15 +252,8 @@
     }
 
     public void waitForKeyboardAccessoryToDisappear() {
-        CriteriaHelper.pollInstrumentationThread(() -> {
-            KeyboardAccessoryCoordinator accessory =
-                    getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
-            return accessory != null && !accessory.isShown();
-        });
-        CriteriaHelper.pollUiThread(() -> {
-            View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
-            return accessory != null && !accessory.isShown();
-        });
+        pollInstrumentationThread(() -> accessoryStartedHiding(getKeyboardAccessoryBar()));
+        pollUiThread(() -> accessoryViewFullyHidden(mActivityTestRule.getActivity()));
     }
 
     public void waitForKeyboardAccessoryToBeShown() {
@@ -263,19 +261,12 @@
     }
 
     public void waitForKeyboardAccessoryToBeShown(boolean waitForSuggestionsToLoad) {
-        CriteriaHelper.pollInstrumentationThread(() -> {
-            KeyboardAccessoryCoordinator accessory =
-                    getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
-            return accessory != null && accessory.isShown();
-        });
-        CriteriaHelper.pollUiThread(() -> {
-            View accessory = mActivityTestRule.getActivity().findViewById(R.id.keyboard_accessory);
-            return accessory != null && accessory.isShown();
-        });
+        pollInstrumentationThread(() -> accessoryStartedShowing(getKeyboardAccessoryBar()));
+        pollUiThread(() -> accessoryViewFullyShown(mActivityTestRule.getActivity()));
         if (waitForSuggestionsToLoad) {
-            CriteriaHelper.pollUiThread(()
-                                                -> getFirstAccessorySuggestion() != null,
-                    "Waited for suggestions that never appeared.");
+            pollUiThread(() -> {
+                return getFirstAccessorySuggestion() != null;
+            }, "Waited for suggestions that never appeared.");
         }
     }
 
@@ -284,14 +275,14 @@
         final View view = webContents.getViewAndroidDelegate().getContainerView();
 
         // Wait for InputConnection to be ready and fill the filterInput. Then wait for the anchor.
-        CriteriaHelper.pollUiThread(() -> {
+        pollUiThread(() -> {
             Criteria.checkThat(
                     mInputMethodManagerWrapper.getShowSoftInputCounter(), Matchers.is(1));
         });
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             ImeAdapter.fromWebContents(webContents).setComposingTextForTest(filterInput, 4);
         });
-        CriteriaHelper.pollUiThread(() -> {
+        pollUiThread(() -> {
             Criteria.checkThat("Autofill Popup anchor view was never added.",
                     view.findViewById(R.id.dropdown_popup_window), Matchers.notNullValue());
         });
@@ -300,7 +291,7 @@
         Assert.assertTrue(anchorView.getTag() instanceof DropdownPopupWindowInterface);
         final DropdownPopupWindowInterface popup =
                 (DropdownPopupWindowInterface) anchorView.getTag();
-        CriteriaHelper.pollUiThread(() -> {
+        pollUiThread(() -> {
             Criteria.checkThat(popup.isShowing(), Matchers.is(true));
             Criteria.checkThat(popup.getListView(), Matchers.notNullValue());
             Criteria.checkThat(popup.getListView().getHeight(), Matchers.not(0));
@@ -326,6 +317,10 @@
                 .getOrCreateSheet(mWebContentsRef.get(), AccessoryTabType.CREDIT_CARDS);
     }
 
+    private KeyboardAccessoryCoordinator getKeyboardAccessoryBar() {
+        return getManualFillingCoordinator().getMediatorForTesting().getKeyboardAccessory();
+    }
+
     // ----------------------------------
     // Helpers to set up the native side.
     // ----------------------------------
@@ -444,7 +439,7 @@
         return new ViewAction() {
             @Override
             public Matcher<View> getConstraints() {
-                return allOf(isDisplayed(), isAssignableFrom(TabLayout.class));
+                return allOf(isDisplayed(), isKeyboardAccessoryTabLayout());
             }
 
             @Override
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
new file mode 100644
index 0000000..6b9fac7
--- /dev/null
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
@@ -0,0 +1,60 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.keyboard_accessory.bar_component;
+
+import android.app.Activity;
+
+import org.chromium.chrome.browser.keyboard_accessory.R;
+
+/**
+ * Helpers in this class simplify interactions with the Keyboard Accessory bar component.
+ */
+public class KeyboardAccessoryTestHelper {
+    /**
+     * Returns true if the accessory becomes visible. It is not guaranteed that the view reflects
+     * this state already. Use {@link #accessoryViewFullyShown(Activity)} for that.
+     *
+     * @param accessory An {@link KeyboardAccessoryCoordinator}
+     * @return True iff the component was ordered to show.
+     */
+    public static boolean accessoryStartedShowing(KeyboardAccessoryCoordinator accessory) {
+        return accessory != null && accessory.isShown();
+    }
+
+    /**
+     * Returns true if the accessory starts hiding. It is not guaranteed that the view reflects this
+     * state already. Use {@link #accessoryViewFullyHidden(Activity)} (Activity)} for that.
+     *
+     * @param accessory An {@link KeyboardAccessoryCoordinator}
+     * @return True iff the component was ordered to hide.
+     */
+    public static boolean accessoryStartedHiding(KeyboardAccessoryCoordinator accessory) {
+        return accessory != null && !accessory.isShown();
+    }
+
+    /**
+     * Helper that finds the accessory bar and checks whether it's shown. Returns false until
+     * animations have concluded.
+     *
+     * @param activity The {@link Activity} containing the accessory bar.
+     * @return True iff the bar view is visible and animations have ended.
+     */
+    public static boolean accessoryViewFullyShown(Activity activity) {
+        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
+        return accessory != null && accessory.isShown() && !accessory.hasRunningAnimation();
+    }
+
+    /**
+     * Helper that finds the accessory bar and checks whether it's hidden. Returns false until
+     * animations have concluded.
+     *
+     * @param activity The {@link Activity} containing the accessory bar.
+     * @return True iff the bar view is hidden and animations have ended.
+     */
+    public static boolean accessoryViewFullyHidden(Activity activity) {
+        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
+        return accessory == null || (!accessory.isShown() && !accessory.hasRunningAnimation());
+    }
+}
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
index ac09334..eec8da98 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
@@ -9,22 +9,16 @@
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem;
 import static androidx.test.espresso.contrib.RecyclerViewActions.scrollTo;
-import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
-import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
 
-import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
+import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 import static org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabTestHelper.isKeyboardAccessoryTabLayout;
 
-import android.widget.TextView;
-
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
@@ -136,9 +130,12 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(withContentDescription(R.string.credit_card_accessory_sheet_toggle),
-                              not(isAssignableFrom(TextView.class))))
-                .perform(click());
+        whenDisplayed(withId(R.id.bar_items_view))
+                .perform(scrollTo(isKeyboardAccessoryTabLayout()),
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.credit_card_accessory_sheet_toggle)));
+
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.credit_card_sheet));
         onView(withText(containsString("No saved payment methods"))).check(matches(isDisplayed()));
@@ -157,7 +154,9 @@
         // Scroll to last element and click the first icon:
         whenDisplayed(withId(R.id.bar_items_view))
                 .perform(scrollTo(isKeyboardAccessoryTabLayout()),
-                        actionOnItem(isKeyboardAccessoryTabLayout(), selectTabAtPosition(0)));
+                        actionOnItem(isKeyboardAccessoryTabLayout(),
+                                selectTabWithDescription(
+                                        R.string.credit_card_accessory_sheet_toggle)));
 
         // Wait for the sheet to come up and be stable.
         whenDisplayed(withId(R.id.credit_card_sheet));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
index 4646e41f..7281b4a 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java
@@ -14,7 +14,6 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.core.AllOf.allOf;
 
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.isTransformed;
 import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.scrollToLastElement;
@@ -88,8 +87,7 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
 
         // Check that the provided elements are there.
         whenDisplayed(withText("mayapark@gmail.com"));
@@ -109,8 +107,7 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
 
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.passwords_sheet)).perform(scrollToLastElement());
@@ -127,8 +124,7 @@
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
 
         // Click the suggestion.
         whenDisplayed(withText("ShorterPassword")).perform(click());
@@ -154,8 +150,7 @@
         mHelper.waitForKeyboardAccessoryToBeShown();
 
         // Click the tab to show the sheet and hide the keyboard.
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
         mHelper.waitForKeyboardToDisappear();
         whenDisplayed(withId(R.id.passwords_sheet));
         onView(withText(containsString("No saved passwords"))).check(matches(isDisplayed()));
@@ -166,15 +161,14 @@
     @EnableFeatures({ChromeFeatureList.RECOVER_FROM_NEVER_SAVE_ANDROID,
             ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY})
     public void
-    testEnablesUndenylistingToggle() throws TimeoutException {
+    testEnablesUndenylistingToggle() throws TimeoutException, InterruptedException {
         mHelper.loadTestPage(false);
         mHelper.cacheCredentials(new String[0], new String[0], true);
 
         // Focus the field to bring up the accessory.
         mHelper.focusPasswordField();
         mHelper.waitForKeyboardAccessoryToBeShown();
-        whenDisplayed(allOf(isDisplayed(), isKeyboardAccessoryTabLayout()))
-                .perform(selectTabAtPosition(0));
+        whenDisplayed(isKeyboardAccessoryTabLayout()).perform(selectTabAtPosition(0));
 
         whenDisplayed(withId(R.id.option_toggle_switch)).check(matches(isNotChecked()));
         onView(withId(R.id.option_toggle_subtitle)).check(matches(withText(R.string.text_off)));
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
index 8eb920c7..96137b6 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -1116,6 +1116,12 @@
     }
 
     @Test
+    public void testScrollsPageUpAfterBarIsFullyShown() {
+        mMediator.onBarFadeInAnimationEnd();
+        verify(mLastMockWebContents).scrollFocusedEditableNodeIntoView();
+    }
+
+    @Test
     public void testShowAccessorySheetTab() {
         // Prepare a tab and register a new tab, so there is a reason to display the bar.
         addBrowserTab(mMediator, 1111, null);
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
index b87eede7..e6c2c8a 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -18,6 +18,7 @@
 
 import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.AUTOFILL_SUGGESTION;
 import static org.chromium.chrome.browser.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC;
+import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.ANIMATION_LISTENER;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BAR_ITEMS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.HAS_SUGGESTIONS;
 import static org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.OBFUSCATED_CHILD_AT_CALLBACK;
@@ -585,6 +586,12 @@
         assertThat(mModel.get(HAS_SUGGESTIONS), is(false));
     }
 
+    @Test
+    public void testFowardsAnimationEventsToVisibilityDelegate() {
+        mModel.get(ANIMATION_LISTENER).onFadeInEnd();
+        verify(mMockVisibilityDelegate).onBarFadeInAnimationEnd();
+    }
+
     private int getGenerationImpressionCount() {
         return RecordHistogram.getHistogramValueCountForTesting(
                 ManualFillingMetricsRecorder.UMA_KEYBOARD_ACCESSORY_ACTION_IMPRESSION,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
index c12ede7..adaa2831 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
@@ -196,11 +196,10 @@
      *         it'd be preferred over the iconId.
      */
     @CalledByNative
-    private static void addToAutofillSuggestionArray(AutofillSuggestion[] array, int index,
-            String label, String secondaryLabel, String sublabel, String secondarySublabel,
-            String itemTag, int iconId, boolean isIconAtStart, int suggestionId,
-            boolean isDeletable, boolean isLabelMultiline, boolean isLabelBold,
-            GURL customIconUrl) {
+    private void addToAutofillSuggestionArray(AutofillSuggestion[] array, int index, String label,
+            String secondaryLabel, String sublabel, String secondarySublabel, String itemTag,
+            int iconId, boolean isIconAtStart, int suggestionId, boolean isDeletable,
+            boolean isLabelMultiline, boolean isLabelBold, GURL customIconUrl) {
         int drawableId = iconId == 0 ? DropdownItem.NO_ICON : iconId;
         AutofillSuggestion.Builder builder = new AutofillSuggestion.Builder()
                                                      .setLabel(label)
@@ -214,10 +213,15 @@
                                                      .setIsDeletable(isDeletable)
                                                      .setIsMultiLineLabel(isLabelMultiline)
                                                      .setIsBoldLabel(isLabelBold);
-        if (customIconUrl != null) {
+        if (customIconUrl != null && customIconUrl.isValid()) {
             builder.setCustomIcon(
                     PersonalDataManager.getInstance()
-                            .getCustomImageForAutofillSuggestionIfAvailable(customIconUrl));
+                            .getCustomImageForAutofillSuggestionIfAvailable(
+                                    AutofillUiUtils.getCCIconURLWithParams(customIconUrl,
+                                            mContext.getResources().getDimensionPixelSize(
+                                                    R.dimen.autofill_dropdown_icon_width),
+                                            mContext.getResources().getDimensionPixelSize(
+                                                    R.dimen.autofill_dropdown_icon_height))));
         }
         array[index] = builder.build();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
index 122dd84..78d90ba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
@@ -28,6 +28,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.core.widget.TextViewCompat;
@@ -40,6 +41,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
+import org.chromium.url.GURL;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -434,4 +436,29 @@
                         new NoUnderlineClickableSpan(
                                 context, view -> onClickCallback.onResult(url))));
     }
+
+    /**
+     * Adds dimension params to card art URL for credit cards.
+     * @param customIconURL A FIFE URL to fetch the card art icon.
+     * @param width in pixels.
+     * @param height in pixels.
+     * @return {@link GURL} formatted with the icon dimensions to fetch the card art icon.
+     */
+    public static GURL getCCIconURLWithParams(GURL customIconURL, @Px int width, @Px int height) {
+        // TODO(crbug.com/1313616): There is only one gstatic card art image we are using currently.
+        // Remove this logic and append FIFE URL suffix by default when the static image is
+        // deprecated.
+        // Check if the image is gstatic stored in Static Content Service. If not append the
+        // dimension params to the FIFE URL.
+        if (customIconURL.getSpec().equals(
+                    "https://www.gstatic.com/autofill/virtualcard/icon/capitalone.png")) {
+            return customIconURL;
+        }
+        // Params can be added to a FIFE URL by appending them at the end like URL[=params]. "w"
+        // option is used to set the width in pixels, "h" is used to set the height in pixels,
+        // and "n" represents center cropping the image.
+        StringBuilder url = new StringBuilder(customIconURL.getSpec());
+        url.append("=w").append(width).append("-h").append(height).append("-n");
+        return new GURL(url.toString());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 9942fb1..ccea071 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -6,6 +6,11 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
 import android.text.format.DateUtils;
 
 import androidx.annotation.VisibleForTesting;
@@ -1348,6 +1353,7 @@
         return UserPrefs.get(Profile.getLastUsedRegularProfile());
     }
 
+    // TODO (crbug.com/1384128): Add icon dimensions to card art URL.
     private void fetchCreditCardArtImages() {
         for (CreditCard card : getCreditCardsToSuggest(/*includeServerCards= */ true)) {
             // Fetch the image using the ImageFetcher only if it is not present in the cache.
@@ -1360,7 +1366,7 @@
     }
 
     /**
-     * Return the card art image for the given `cardArtUrl`.
+     * Return the card art image for the given `customImageUrl`.
      *
      * @param customImageUrl  URL of the image. If the image is available, it is returned, otherwise
      *         it is fetched from this URL.
@@ -1372,8 +1378,23 @@
         }
         // Schedule the fetching of image and return null so that the UI thread does not have to
         // wait and can show the default network icon.
-        fetchImage(customImageUrl,
-                bitmap -> mCreditCardArtImages.put(customImageUrl.getSpec(), bitmap));
+        fetchImage(customImageUrl, bitmap -> {
+            // Create an empty mutable bitmap and set it in a canvas.
+            Bitmap cardArtImageWithGrayOverlay = Bitmap.createBitmap(
+                    bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(cardArtImageWithGrayOverlay);
+
+            // Create a gray paint with 4% opacity.
+            Paint paint = new Paint();
+            paint.setColorFilter(new PorterDuffColorFilter(
+                    Color.argb(/* alpha= */ 10, /* red= */ 68, /* green= */ 68, /* blue= */ 68),
+                    Mode.DARKEN));
+
+            // Add the icon and the 4% gray overlay.
+            canvas.drawBitmap(
+                    /* bitmap= */ bitmap, /* left= */ 0, /* top= */ 0, /* paint= */ paint);
+            mCreditCardArtImages.put(customImageUrl.getSpec(), cardArtImageWithGrayOverlay);
+        });
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java
index 0228c1c..1f5e797 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java
@@ -39,26 +39,14 @@
      * Represents synced foreign session.
      */
     static class ForeignSession {
-        // Please keep in sync with components/sync/protocol/sync_enums.proto.
-        static final int DEVICE_TYPE_UNSET = 0;
-        static final int DEVICE_TYPE_WIN = 1;
-        static final int DEVICE_TYPE_MACOSX = 2;
-        static final int DEVICE_TYPE_LINUX = 3;
-        static final int DEVICE_TYPE_CHROMEOS = 4;
-        static final int DEVICE_TYPE_OTHER = 5;
-        static final int DEVICE_TYPE_PHONE = 6;
-        static final int DEVICE_TYPE_TABLET = 7;
-
         public final String tag;
         public final String name;
-        public final int deviceType;
         public final long modifiedTime;
         public final List<ForeignSessionWindow> windows = new ArrayList<ForeignSessionWindow>();
 
-        private ForeignSession(String tag, String name, int deviceType, long modifiedTime) {
+        private ForeignSession(String tag, String name, long modifiedTime) {
             this.tag = tag;
             this.name = name;
-            this.deviceType = deviceType;
             this.modifiedTime = modifiedTime;
         }
     }
@@ -97,9 +85,8 @@
 
     @CalledByNative
     private static ForeignSession pushSession(
-            List<ForeignSession> sessions, String tag, String name, int deviceType,
-            long modifiedTime) {
-        ForeignSession session = new ForeignSession(tag, name, deviceType, modifiedTime);
+            List<ForeignSession> sessions, String tag, String name, long modifiedTime) {
+        ForeignSession session = new ForeignSession(tag, name, modifiedTime);
         sessions.add(session);
         return session;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
index 495a488..65abd22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -11,7 +11,6 @@
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CallbackController;
@@ -83,6 +82,7 @@
     private final @ColorInt int mStandardDefaultThemeColor;
     private final @ColorInt int mIncognitoDefaultThemeColor;
     private final @ColorInt int mActiveOmniboxDefaultColor;
+    private @ColorInt int mToolbarColor;
 
     private @Nullable TabModelSelector mTabModelSelector;
     private CallbackController mCallbackController = new CallbackController();
@@ -91,6 +91,7 @@
     private boolean mIsInOverviewMode;
     private boolean mIsIncognito;
     private boolean mIsOmniboxFocused;
+    private boolean mToolbarAnimationInProgress;
 
     private @ColorInt int mScrimColor;
     private float mStatusBarScrimFraction;
@@ -142,14 +143,7 @@
 
             @Override
             public void onDidChangeThemeColor(Tab tab, int color) {
-                if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()) {
-                    // The theme color change assignment will override the feature flag which
-                    // matches the toolbar and the status bar color, specifically for custom tabs
-                    // with theme colors.
-                    updateStatusBarColor(color);
-                } else {
-                    updateStatusBarColor();
-                }
+                updateStatusBarColor();
             }
 
             @Override
@@ -249,8 +243,9 @@
 
     // TopToolbarCoordinator.UrlExpansionObserver implementation.
     @Override
-    public void onUrlExpansionProgressChanged(float fraction) {
+    public void onUrlExpansionProgressChanged(float fraction, boolean changeInProgress) {
         mToolbarUrlExpansionPercentage = fraction;
+        mToolbarAnimationInProgress = changeInProgress;
         if (mShouldUpdateStatusBarColorForNTP) updateStatusBarColor();
     }
 
@@ -266,8 +261,8 @@
             return;
         }
 
-        // The status indicator will override the toolbar color match if available.
-        updateStatusBarColor(color);
+        mToolbarColor = color;
+        updateStatusBarColor();
     }
 
     // StatusIndicatorCoordinator.StatusIndicatorObserver implementation.
@@ -275,13 +270,7 @@
     @Override
     public void onStatusIndicatorColorChanged(@ColorInt int newColor) {
         mStatusIndicatorColor = newColor;
-        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()) {
-            // The status indicator color assignment will override the feature flag which matches
-            // the toolbar and the status bar color.
-            updateStatusBarColor(calculateBaseStatusBarColor());
-        } else {
-            updateStatusBarColor();
-        }
+        updateStatusBarColor();
     }
 
     @Override
@@ -296,13 +285,7 @@
      */
     public void setStatusBarScrimFraction(float fraction) {
         mStatusBarScrimFraction = fraction;
-        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()) {
-            // The scrim fraction color assignment will override the feature flag which matches
-            // the toolbar and the status bar color.
-            updateStatusBarColor(calculateBaseStatusBarColor());
-        } else {
-            updateStatusBarColor();
-        }
+        updateStatusBarColor();
     }
 
     /**
@@ -319,22 +302,7 @@
      * Calculate and update the status bar's color.
      */
     public void updateStatusBarColor() {
-        // We will synchronize the status bar's color with toolbar's color if the feature flag is
-        // toggled, so we skip the original color assignment here.
-        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()) {
-            return;
-        }
-        updateStatusBarColor(calculateBaseStatusBarColor());
-    }
-
-    /**
-     * Update the status bar's color with provided color.
-     * @param color The color to be applied to status bar.
-     */
-    @VisibleForTesting
-    public void updateStatusBarColor(@ColorInt int color) {
-        mStatusBarColorWithoutStatusIndicator = color;
-
+        mStatusBarColorWithoutStatusIndicator = calculateBaseStatusBarColor();
         int statusBarColor = applyStatusBarIndicatorColor(mStatusBarColorWithoutStatusIndicator);
         statusBarColor = applyCurrentScrimToColor(statusBarColor);
         setStatusBarColor(mWindow, statusBarColor);
@@ -365,7 +333,14 @@
 
         // When Omnibox gains focus, we want to clear the status bar theme color.
         // The theme should be restored when Omnibox focus clears.
-        if (mIsOmniboxFocused) return calculateDefaultStatusBarColor();
+        if (mIsOmniboxFocused) {
+            // If the flag is enabled, we will use the toolbar color.
+            if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor()
+                    && mToolbarAnimationInProgress) {
+                return mToolbarColor;
+            }
+            return calculateDefaultStatusBarColor();
+        }
 
         // Return status bar color in overview mode.
         if (mIsInOverviewMode) {
@@ -384,6 +359,10 @@
         }
 
         // Return status bar color to match the toolbar.
+        // If the flag is enabled, we will use the toolbar color.
+        if (OmniboxFeatures.shouldMatchToolbarAndStatusBarColor() && mToolbarAnimationInProgress) {
+            return mToolbarColor;
+        }
         return mTopUiThemeColor.getThemeColorOrFallback(
                 mCurrentTab, calculateDefaultStatusBarColor());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java
index b37b8714..edcde3b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java
@@ -271,7 +271,6 @@
 
     @Test
     @SmallTest
-    @DisabledTest(message = "crbug.com/1385530")
     public void testAddBookmark() throws Exception {
         mActivityTestRule.loadUrl(mTestPage);
         // Check partner bookmarks are lazily loaded.
@@ -1161,7 +1160,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/1385530")
     public void testMoveButtonsGoneForPartnerBookmarks() throws Exception {
         loadFakePartnerBookmarkShimForTesting();
         BookmarkPromoHeader.forcePromoStateForTests(SyncPromoState.NO_PROMO);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
index 52f5958..f13bc23 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -229,6 +229,31 @@
     @Test
     @SmallTest
     @Feature({"Autofill"})
+    public void testCreditCardArtURLIsFormattedWithImageSpecs() throws TimeoutException {
+        GURL virtualCardIconURL =
+                new GURL("https://www.gstatic.com/autofill/virtualcard/icon/capitalone.png");
+        GURL cardArtURL = new GURL("http://google.com/test");
+        int widthPixels = 32;
+        int heightPixels = 20;
+
+        // For virtual card icon, the URL should not be updated. For card art icon, the URL should
+        // be updated as `cardArtURL=w{width}-h{height}-n`.
+        assertThat(AutofillUiUtils.getCCIconURLWithParams(
+                           virtualCardIconURL, widthPixels, heightPixels))
+                .isEqualTo(virtualCardIconURL);
+        assertThat(AutofillUiUtils.getCCIconURLWithParams(cardArtURL, widthPixels, heightPixels))
+                .isEqualTo(new GURL(new StringBuilder(cardArtURL.getSpec())
+                                            .append("=w")
+                                            .append(widthPixels)
+                                            .append("-h")
+                                            .append(heightPixels)
+                                            .append("-n")
+                                            .toString()));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Autofill"})
     public void testAddAndDeleteCreditCard() throws TimeoutException {
         CreditCard card = createLocalCreditCard("Visa", "1234123412341234", "5", "2020");
         card.setOrigin("Chrome settings");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
index dc2e262..931172b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
@@ -49,6 +49,7 @@
 import org.chromium.chrome.test.util.browser.ThemeTestUtils;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.test.util.DisableAnimationsTestRule;
 import org.chromium.ui.test.util.UiRestriction;
 import org.chromium.ui.util.ColorUtils;
 
@@ -67,6 +68,9 @@
 public class StatusBarColorControllerTest {
     // clang-format on
     @ClassRule
+    public static DisableAnimationsTestRule sEnableAnimationsRule =
+            new DisableAnimationsTestRule(false);
+    @ClassRule
     public static ChromeTabbedActivityTestRule sActivityTestRule =
             new ChromeTabbedActivityTestRule();
 
@@ -237,13 +241,16 @@
                 "/chrome/test/data/android/theme_color_test.html");
         sActivityTestRule.loadUrl(pageWithBrandColorUrl);
         ThemeTestUtils.waitForThemeColor(activity, Color.RED);
+        mOmniboxUtils.waitAnimationsComplete();
         waitForStatusBarColor(activity, Color.RED);
         waitForStatusBarColorToMatchToolbarColor(activity);
 
         mOmniboxUtils.requestFocus();
+        mOmniboxUtils.waitAnimationsComplete();
         waitForStatusBarColor(activity, expectedDefaultStandardColor);
         waitForStatusBarColorToMatchToolbarColor(activity);
         mOmniboxUtils.clearFocus();
+        mOmniboxUtils.waitAnimationsComplete();
         waitForStatusBarColor(activity, Color.RED);
         waitForStatusBarColorToMatchToolbarColor(activity);
     }
diff --git a/chrome/app/password_manager_ui_strings_grdp/OWNERS b/chrome/app/password_manager_ui_strings_grdp/OWNERS
new file mode 100644
index 0000000..2d3493b
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/password_manager/OWNERS
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index ac89d8c..5159f05b 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -245,6 +245,7 @@
   "+components/paint_preview/browser",
   "+components/paint_preview/buildflags",
   "+components/password_manager/content/browser",
+  "+components/password_manager/content/common",
   "+components/password_manager/core/browser",
   "+components/password_manager/core/common",
   "+components/payments/content",
diff --git a/chrome/browser/android/foreign_session_helper.cc b/chrome/browser/android/foreign_session_helper.cc
index bec11fb..b1bedfb 100644
--- a/chrome/browser/android/foreign_session_helper.cc
+++ b/chrome/browser/android/foreign_session_helper.cc
@@ -234,7 +234,7 @@
 
     last_pushed_session.Reset(Java_ForeignSessionHelper_pushSession(
         env, result, ConvertUTF8ToJavaString(env, session.session_tag),
-        ConvertUTF8ToJavaString(env, session.session_name), session.device_type,
+        ConvertUTF8ToJavaString(env, session.session_name),
         session.modified_time.ToJavaTime()));
 
     // Push the full session, with tabs ordered by visual position.
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
index a7221e2..c460370 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.cc
@@ -35,6 +35,7 @@
 const test::UIPath kErrorCancelButton = {"main-element",
                                          "cancelButtonErrorScreen"};
 const test::UIPath kSamlCancelButton = {"main-element", "saml-close-button"};
+const test::UIPath kChangeIdPButton = {"main-element", "change-account"};
 const test::UIPath kMainScreen = {"main-element", "verifyAccountScreen"};
 const test::UIPath kErrorScreen = {"main-element", "errorScreen"};
 const test::UIPath kSamlConfirmPasswordScreen = {"main-element",
@@ -167,6 +168,11 @@
   DialogJS().TapOnPath(kSamlCancelButton);
 }
 
+void LockScreenReauthDialogTestHelper::ClickChangeIdPButtonOnSamlScreen() {
+  ExpectSamlScreenVisible();
+  DialogJS().TapOnPath(kChangeIdPButton);
+}
+
 void LockScreenReauthDialogTestHelper::WaitForSamlScreen() {
   WaitForAuthenticatorToLoad();
   DialogJS().CreateVisibilityWaiter(true, kSamlContainer)->Wait();
@@ -194,6 +200,10 @@
   DialogJS().ExpectHiddenPath(kSamlContainer);
 }
 
+void LockScreenReauthDialogTestHelper::ExpectGaiaScreenVisible() {
+  DialogJS().ExpectAttributeEQ("isDefaultSsoProvider", {"main-element"}, false);
+}
+
 void LockScreenReauthDialogTestHelper::ExpectSamlConfirmPasswordVisible() {
   DialogJS().CreateVisibilityWaiter(true, kSamlConfirmPasswordScreen)->Wait();
   DialogJS().ExpectVisiblePath(kSamlConfirmPasswordScreen);
diff --git a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
index 4a2a22c..98efb49 100644
--- a/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
+++ b/chrome/browser/ash/login/saml/lockscreen_reauth_dialog_test_helper.h
@@ -72,6 +72,9 @@
   // Clicks the 'Cancel' button on the 'Saml Account' screen.
   void ClickCancelButtonOnSamlScreen();
 
+  // Clicks the 'Enter Google Account Info' button on the SAML screen.
+  void ClickChangeIdPButtonOnSamlScreen();
+
   // Waits for a screen with the `saml-container` element to be shown.
   void WaitForSamlScreen();
 
@@ -83,6 +86,8 @@
   void ExpectSamlScreenVisible();
   void ExpectSamlScreenHidden();
 
+  void ExpectGaiaScreenVisible();
+
   // Next members allow to check visibility of some elements on 'confirm
   // password screen' and also help to fill forms. Precondition: 'confirm
   // password screen' is visible.
diff --git a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
index 9f944e2..74aa1970 100644
--- a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
@@ -206,6 +206,23 @@
   UnlockWithSAML();
 }
 
+// Tests that we can switch from SAML page to GAIA page on the lock screen.
+IN_PROC_BROWSER_TEST_F(LockscreenWebUiTest, SamlSwitchToGaia) {
+  fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
+
+  Login();
+
+  // Lock the screen and trigger the lock screen SAML reauth dialog.
+  ScreenLockerTester().Lock();
+
+  absl::optional<LockScreenReauthDialogTestHelper> reauth_dialog_helper =
+      LockScreenReauthDialogTestHelper::StartSamlAndWaitForIdpPageLoad();
+
+  reauth_dialog_helper->ClickChangeIdPButtonOnSamlScreen();
+
+  reauth_dialog_helper->ExpectGaiaScreenVisible();
+}
+
 // Tests the cancel button in Verify Screen.
 IN_PROC_BROWSER_TEST_F(LockscreenWebUiTest, VerifyScreenCancel) {
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
index c02b463..136a6ac6 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job.cc
@@ -505,6 +505,14 @@
           std::move(response_callback));
       break;
     }
+    case ash::cros_healthd::mojom::DiagnosticRoutineEnum::kPrivacyScreen: {
+      constexpr char kPrivacyScreenTargetState[] = "targetState";
+      absl::optional<bool> target_state =
+          params_dict_.GetDict().FindBool(kPrivacyScreenTargetState);
+      diagnostics_service->RunPrivacyScreenRoutine(
+          target_state.value_or(true), std::move(response_callback));
+      break;
+    }
   }
 }
 
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job_unittest.cc b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job_unittest.cc
index 655a9a1..db28720 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_run_routine_job_unittest.cc
@@ -65,6 +65,10 @@
 constexpr char kMinimumChargePercentRequiredFieldName[] =
     "minimumChargePercentRequired";
 
+// String constants identifying the parameter field for the privacy screen
+// routine.
+constexpr char kPrivacyScreenTargetStateFieldName[] = "targetState";
+
 constexpr uint32_t kId = 11;
 constexpr auto kStatus =
     ash::cros_healthd::mojom::DiagnosticRoutineStatusEnum::kRunning;
@@ -1463,4 +1467,43 @@
       })));
 }
 
+// Test that privacy screen routine succeeds with all parameters specified.
+TEST_F(DeviceCommandRunRoutineJobTest, RunPrivacyScreenRoutineSuccess) {
+  auto run_routine_response =
+      ash::cros_healthd::mojom::RunRoutineResponse::New(kId, kStatus);
+  ash::cros_healthd::FakeCrosHealthd::Get()->SetRunRoutineResponseForTesting(
+      run_routine_response);
+  base::Value params_dict(base::Value::Type::DICTIONARY);
+  params_dict.SetBoolKey(kPrivacyScreenTargetStateFieldName, true);
+  EXPECT_TRUE(
+      RunJob(ash::cros_healthd::mojom::DiagnosticRoutineEnum::kPrivacyScreen,
+             std::move(params_dict),
+             base::BindLambdaForTesting([](RemoteCommandJob* job) {
+               EXPECT_EQ(job->status(), RemoteCommandJob::SUCCEEDED);
+               std::unique_ptr<std::string> payload = job->GetResultPayload();
+               EXPECT_TRUE(payload);
+               EXPECT_EQ(CreateSuccessPayload(kId, kStatus), *payload);
+             })));
+}
+
+// Test that privacy screen routine succeeds without the optional parameter
+// |targetState| specified.
+TEST_F(DeviceCommandRunRoutineJobTest,
+       RunPrivacyScreenRoutineSuccessNoOptionalTargetState) {
+  auto run_routine_response =
+      ash::cros_healthd::mojom::RunRoutineResponse::New(kId, kStatus);
+  ash::cros_healthd::FakeCrosHealthd::Get()->SetRunRoutineResponseForTesting(
+      run_routine_response);
+  base::Value params_dict(base::Value::Type::DICTIONARY);
+  EXPECT_TRUE(
+      RunJob(ash::cros_healthd::mojom::DiagnosticRoutineEnum::kPrivacyScreen,
+             std::move(params_dict),
+             base::BindLambdaForTesting([](RemoteCommandJob* job) {
+               EXPECT_EQ(job->status(), RemoteCommandJob::SUCCEEDED);
+               std::unique_ptr<std::string> payload = job->GetResultPayload();
+               EXPECT_TRUE(payload);
+               EXPECT_EQ(CreateSuccessPayload(kId, kStatus), *payload);
+             })));
+}
+
 }  // namespace policy
diff --git a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
index 8852908..df44a183 100644
--- a/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop_browsertest.cc
@@ -8,6 +8,7 @@
 
 #include "base/callback.h"
 #include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -32,6 +33,8 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/webapps/browser/banners/app_banner_metrics.h"
 #include "components/webapps/browser/banners/app_banner_settings_helper.h"
 #include "components/webapps/browser/install_result_code.h"
@@ -46,20 +49,27 @@
 
 namespace webapps {
 
+namespace {
+
+std::vector<base::test::FeatureRef> GetDisabledFeatures() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  return {features::kWebAppsCrosapi, chromeos::features::kLacrosPrimary};
+#else
+  return {};
+#endif
+}
+
+}  // namespace
+
 using State = AppBannerManager::State;
 
 class AppBannerManagerDesktopBrowserTest
     : public AppBannerManagerBrowserTestBase {
  public:
-  AppBannerManagerDesktopBrowserTest() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    // With Lacros, web apps are not installed using the Ash browser.
-    scoped_feature_list_.InitWithFeatures(
-        {}, {features::kWebAppsCrosapi, chromeos::features::kLacrosPrimary});
-#endif
-  }
+  AppBannerManagerDesktopBrowserTest() = default;
 
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatures({}, GetDisabledFeatures());
     TestAppBannerManagerDesktop::SetUp();
     AppBannerManagerBrowserTestBase::SetUp();
   }
@@ -81,7 +91,7 @@
   AppBannerManagerDesktopBrowserTest& operator=(
       const AppBannerManagerDesktopBrowserTest&) = delete;
 
- private:
+ protected:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
@@ -450,4 +460,38 @@
   EXPECT_TRUE(manager->IsPromptAvailableForTesting());
 }
 
+class AppBannerManagerDesktopBrowserTestForPasswordManagerPage
+    : public AppBannerManagerDesktopBrowserTest {
+ public:
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures(
+        {password_manager::features::kPasswordManagerRedesign},
+        GetDisabledFeatures());
+    TestAppBannerManagerDesktop::SetUp();
+    AppBannerManagerBrowserTestBase::SetUp();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AppBannerManagerDesktopBrowserTestForPasswordManagerPage,
+                       WebUiPasswordManagerApp) {
+  TestAppBannerManagerDesktop* manager =
+      TestAppBannerManagerDesktop::FromWebContents(
+          browser()->tab_strip_model()->GetActiveWebContents());
+
+  // Simulate loading a PasswordManager page.
+  {
+    base::RunLoop run_loop;
+    manager->PrepareDone(run_loop.QuitClosure());
+
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(
+        browser(),
+        GURL(base::StrCat(
+            {"chrome://", password_manager::kChromeUIPasswordManagerHost}))));
+    run_loop.Run();
+  }
+
+  EXPECT_EQ(AppBannerManager::InstallableWebAppCheckResult::kYes_ByUserRequest,
+            manager->GetInstallableWebAppCheckResultForTesting());
+}
+
 }  // namespace webapps
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 0505739..024d8278 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -37,6 +37,7 @@
 #include "components/favicon/content/content_favicon_driver.h"
 #include "components/favicon/core/favicon_driver_observer.h"
 #include "components/nacl/common/buildflags.h"
+#include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -58,6 +59,7 @@
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "ppapi/shared_impl/ppapi_switches.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/messaging/string_message_codec.h"
 #include "third_party/blink/public/common/storage_key/storage_key.h"
@@ -314,6 +316,82 @@
       kInstallAndWaitForActivatedPageWithModuleScript);
 }
 
+IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerTest, SubresourceCount) {
+  base::RunLoop ukm_loop;
+  ukm::TestAutoSetUkmRecorder test_recorder;
+  test_recorder.SetOnAddEntryCallback(
+      ukm::builders::ServiceWorker_OnLoad::kEntryName, ukm_loop.QuitClosure());
+
+  WriteFile(FILE_PATH_LITERAL("fallback.css"), "");
+  WriteFile(FILE_PATH_LITERAL("nofallback.css"), "");
+  WriteFile(FILE_PATH_LITERAL("subresources.html"),
+            "<link href='./fallback.css' rel='stylesheet'>"
+            "<link href='./nofallback.css' rel='stylesheet'>");
+  WriteFile(FILE_PATH_LITERAL("sw.js"),
+            "this.onactivate = function(event) {"
+            "  event.waitUntil(self.clients.claim());"
+            "};"
+            "this.onfetch = function(event) {"
+            // We will fallback fallback.css.
+            "  if (event.request.url.endsWith('/fallback.css')) {"
+            "    return;"
+            "  }"
+            "  event.respondWith(fetch(event.request));"
+            "};");
+  WriteFile(FILE_PATH_LITERAL("test.html"),
+            "<script>"
+            "navigator.serviceWorker.register('./sw.js', {scope: './'})"
+            "  .then(function(reg) {"
+            "      reg.addEventListener('updatefound', function() {"
+            "          var worker = reg.installing;"
+            "          worker.addEventListener('statechange', function() {"
+            "              if (worker.state == 'activated')"
+            "                document.title = 'READY';"
+            "            });"
+            "        });"
+            "    });"
+            "</script>");
+
+  InitializeServer();
+
+  {
+    // The message "READY" will be sent when the service worker is activated.
+    const std::u16string expected_title = u"READY";
+    content::TitleWatcher title_watcher(
+        browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(
+        browser(), embedded_test_server()->GetURL("/test.html")));
+    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+  }
+
+  // Navigate to the service worker controlled page.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/subresources.html")));
+
+  // Navigate away to record metrics.
+  ASSERT_TRUE(
+      ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)));
+
+  // Wait until the UKM record is updated.
+  ukm_loop.Run();
+  auto entries = test_recorder.GetEntriesByName(
+      ukm::builders::ServiceWorker_OnLoad::kEntryName);
+  ASSERT_EQ(entries.size(), 1u);
+  test_recorder.ExpectEntryMetric(
+      entries[0],
+      ukm::builders::ServiceWorker_OnLoad::kMainAndSubResourceLoadLocationName,
+      6 /* = kMainResourceNotFallbackAndSubResourceMixed */);
+  test_recorder.ExpectEntryMetric(
+      entries[0],
+      ukm::builders::ServiceWorker_OnLoad::kTotalSubResourceLoadName, 2);
+  test_recorder.ExpectEntryMetric(
+      entries[0],
+      ukm::builders::ServiceWorker_OnLoad::kTotalSubResourceFallbackName, 1);
+  test_recorder.ExpectEntryMetric(
+      entries[0],
+      ukm::builders::ServiceWorker_OnLoad::kSubResourceFallbackRatioName, 50);
+}
+
 class ChromeServiceWorkerFetchTest : public ChromeServiceWorkerTest {
  public:
   ChromeServiceWorkerFetchTest(const ChromeServiceWorkerFetchTest&) = delete;
diff --git a/chrome/browser/device_api/device_attribute_api.cc b/chrome/browser/device_api/device_attribute_api.cc
index 5b24bb5..a98aad6 100644
--- a/chrome/browser/device_api/device_attribute_api.cc
+++ b/chrome/browser/device_api/device_attribute_api.cc
@@ -108,14 +108,12 @@
 
 void GetSerialNumber(DeviceAPIService::GetSerialNumberCallback callback) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const std::string attribute =
-      chromeos::system::StatisticsProvider::GetInstance()
-          ->GetEnterpriseMachineID();
-  if (attribute.empty())
-    std::move(callback).Run(
-        Result::NewAttribute(absl::optional<std::string>()));
-  else
-    std::move(callback).Run(Result::NewAttribute(attribute));
+  const absl::optional<base::StringPiece> attribute =
+      chromeos::system::StatisticsProvider::GetInstance()->GetMachineID();
+  std::move(callback).Run(Result::NewAttribute(
+      attribute ? absl::optional<std::string>(attribute.value())
+                : absl::nullopt));
+
 #elif BUILDFLAG(IS_CHROMEOS_LACROS)
   // TODO(crbug.com/1328100): Replace with crosapi BrowserInitParams.
   chromeos::LacrosService::Get()
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 3f9e3493..cf14d148 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -216,8 +216,6 @@
     "api/image_writer_private/operation_manager.h",
     "api/image_writer_private/removable_storage_provider.cc",
     "api/image_writer_private/removable_storage_provider.h",
-    "api/image_writer_private/single_file_tar_reader.cc",
-    "api/image_writer_private/single_file_tar_reader.h",
     "api/image_writer_private/tar_extractor.cc",
     "api/image_writer_private/tar_extractor.h",
     "api/image_writer_private/write_from_file_operation.cc",
diff --git a/chrome/browser/extensions/api/image_writer_private/extractor_browsertest.cc b/chrome/browser/extensions/api/image_writer_private/extractor_browsertest.cc
index c746300..17464b7 100644
--- a/chrome/browser/extensions/api/image_writer_private/extractor_browsertest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/extractor_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/test/mock_callback.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
 #include "chrome/browser/extensions/api/image_writer_private/extraction_properties.h"
+#include "chrome/browser/extensions/api/image_writer_private/tar_extractor.h"
 #include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
 #include "chrome/browser/extensions/api/image_writer_private/xz_extractor.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -54,6 +55,26 @@
   base::ScopedTempDir temp_dir_;
 };
 
+IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ExtractTar) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+
+  base::FilePath test_data_dir;
+  ASSERT_TRUE(GetTestDataDirectory(&test_data_dir));
+  properties_.image_path = test_data_dir.AppendASCII("test.tar");
+
+  base::FilePath out_path;
+  base::RunLoop run_loop;
+  EXPECT_CALL(open_callback_, Run(_)).WillOnce(SaveArg<0>(&out_path));
+  EXPECT_CALL(complete_callback_, Run())
+      .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
+  TarExtractor::Extract(std::move(properties_));
+  run_loop.Run();
+
+  std::string contents;
+  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
+  EXPECT_EQ("foo\n", contents);
+}
+
 IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ExtractTarXz) {
   base::ScopedAllowBlockingForTesting allow_blocking;
 
@@ -89,7 +110,7 @@
 }
 
 // Verify that tar.xz with a 0 byte file works.
-IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ZeroByteFile) {
+IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ZeroByteTarXzFile) {
   base::ScopedAllowBlockingForTesting allow_blocking;
 
   base::FilePath test_data_dir;
@@ -114,7 +135,7 @@
   EXPECT_TRUE(contents.empty());
 }
 
-IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ExtractBigFile) {
+IN_PROC_BROWSER_TEST_F(ExtractorBrowserTest, ExtractBigTarXzFile) {
   base::ScopedAllowBlockingForTesting allow_blocking;
 
   base::FilePath test_data_dir;
diff --git a/chrome/browser/extensions/api/image_writer_private/extractor_unittest.cc b/chrome/browser/extensions/api/image_writer_private/extractor_unittest.cc
index f40811d1..6425363 100644
--- a/chrome/browser/extensions/api/image_writer_private/extractor_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/extractor_unittest.cc
@@ -2,17 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <string>
-#include <utility>
-
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
-#include "chrome/browser/extensions/api/image_writer_private/extraction_properties.h"
 #include "chrome/browser/extensions/api/image_writer_private/tar_extractor.h"
 #include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
 #include "chrome/browser/extensions/api/image_writer_private/xz_extractor.h"
@@ -22,91 +13,17 @@
 namespace extensions {
 namespace image_writer {
 
-using ::testing::_;
-using ::testing::NiceMock;
-using ::testing::SaveArg;
-using ::testing::StrictMock;
-
 class ExtractorTest : public testing::Test {
  protected:
   ExtractorTest() = default;
   ~ExtractorTest() override = default;
 
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    properties_.temp_dir_path = temp_dir_.GetPath();
-    properties_.open_callback = open_callback_.Get();
-    properties_.complete_callback = complete_callback_.Get();
-    properties_.failure_callback = failure_callback_.Get();
-    properties_.progress_callback = progress_callback_.Get();
-  }
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
 
  protected:
-  StrictMock<base::MockCallback<ExtractionProperties::OpenCallback>>
-      open_callback_;
-  StrictMock<base::MockCallback<ExtractionProperties::CompleteCallback>>
-      complete_callback_;
-  StrictMock<base::MockCallback<ExtractionProperties::FailureCallback>>
-      failure_callback_;
-  NiceMock<base::MockCallback<ExtractionProperties::ProgressCallback>>
-      progress_callback_;
-
-  ExtractionProperties properties_;
   base::ScopedTempDir temp_dir_;
-
-  base::test::TaskEnvironment task_environment_;
 };
 
-TEST_F(ExtractorTest, ExtractTar) {
-  base::FilePath test_data_dir;
-  ASSERT_TRUE(GetTestDataDirectory(&test_data_dir));
-  properties_.image_path = test_data_dir.AppendASCII("test.tar");
-
-  base::FilePath out_path;
-  base::RunLoop run_loop;
-  EXPECT_CALL(open_callback_, Run(_)).WillOnce(SaveArg<0>(&out_path));
-  EXPECT_CALL(complete_callback_, Run())
-      .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
-  TarExtractor::Extract(std::move(properties_));
-  run_loop.Run();
-
-  std::string contents;
-  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
-  EXPECT_EQ("foo\n", contents);
-}
-
-TEST_F(ExtractorTest, ExtractTarLargerThanChunk) {
-  base::FilePath test_data_dir;
-  ASSERT_TRUE(GetTestDataDirectory(&test_data_dir));
-  properties_.image_path = test_data_dir.AppendASCII("test_large.tar");
-
-  base::FilePath out_path;
-  base::RunLoop run_loop;
-  EXPECT_CALL(open_callback_, Run(_)).WillOnce(SaveArg<0>(&out_path));
-  EXPECT_CALL(complete_callback_, Run())
-      .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
-  TarExtractor::Extract(std::move(properties_));
-  run_loop.Run();
-
-  std::string contents;
-  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
-  // Larger than the buffer of SingleFileTarReader.
-  EXPECT_EQ(10u * 1024u, contents.size());
-}
-
-TEST_F(ExtractorTest, ExtractNonExistentTar) {
-  base::FilePath test_data_dir;
-  ASSERT_TRUE(GetTestDataDirectory(&test_data_dir));
-  properties_.image_path = test_data_dir.AppendASCII("non_existent.tar");
-
-  base::RunLoop run_loop;
-  EXPECT_CALL(failure_callback_, Run(error::kUnzipGenericError))
-      .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
-  TarExtractor::Extract(std::move(properties_));
-  run_loop.Run();
-}
-
 TEST_F(ExtractorTest, IsZipFile) {
   base::FilePath test_data_dir;
   ASSERT_TRUE(GetTestDataDirectory(&test_data_dir));
diff --git a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.cc b/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.cc
deleted file mode 100644
index 206ca48..0000000
--- a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.cc
+++ /dev/null
@@ -1,125 +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 "chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h"
-
-#include <algorithm>
-#include <string>
-
-#include "base/check.h"
-#include "base/containers/span.h"
-#include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
-
-namespace extensions {
-namespace image_writer {
-
-namespace {
-constexpr int kTarBufferSize = 8192;
-}  // namespace
-
-SingleFileTarReader::SingleFileTarReader(Delegate* delegate)
-    : delegate_(delegate), buffer_(kTarBufferSize) {}
-
-SingleFileTarReader::~SingleFileTarReader() = default;
-
-SingleFileTarReader::Result SingleFileTarReader::ExtractChunk() {
-  // Drain as much of the data as we can fit into the buffer.
-  base::span<char> storage = base::make_span(buffer_);
-  size_t bytes_read = 0;
-  bool pipe_drained = false;
-  do {
-    uint32_t num_bytes = static_cast<uint32_t>(storage.size());
-    const Result result =
-        delegate_->ReadTarFile(storage.data(), &num_bytes, &error_id_);
-    switch (result) {
-      case Result::kFailure:
-        return result;
-
-      case Result::kSuccess:
-        if (num_bytes == 0) {
-          pipe_drained = true;
-        } else {
-          storage = storage.subspan(num_bytes);
-          bytes_read += num_bytes;
-        }
-        break;
-
-      case Result::kShouldWait:
-        pipe_drained = true;
-        break;
-    }
-  } while (!pipe_drained && !storage.empty());
-
-  int offset = 0;
-
-  // We haven't read the header.
-  if (!total_bytes_.has_value()) {
-    if (bytes_read < 512) {
-      error_id_ = error::kUnzipInvalidArchive;
-      return Result::kFailure;
-    }
-
-    // TODO(tetsui): check the file header checksum
-
-    // Read the actual file size.
-    total_bytes_ = ReadOctalNumber(buffer_.data() + 124, 12);
-
-    // Skip the rest of the header.
-    offset += 512;
-  }
-
-  DCHECK(total_bytes_.has_value());
-
-  // A tar file always has a padding at the end of the file. As they should not
-  // be included in the output, we should take the minimum of the actual
-  // remaining bytes versus the bytes read.
-  uint64_t bytes_written = std::min<uint64_t>(
-      total_bytes_.value() - curr_bytes_, bytes_read - offset);
-  if (!delegate_->WriteContents(buffer_.data() + offset, bytes_written,
-                                &error_id_)) {
-    return Result::kFailure;
-  }
-  curr_bytes_ += bytes_written;
-
-  // TODO(tetsui): check it's the end of the file
-
-  return Result::kSuccess;
-}
-
-bool SingleFileTarReader::IsComplete() const {
-  if (!total_bytes_.has_value())
-    return false;
-  return total_bytes_.value() == curr_bytes_;
-}
-
-// static
-uint64_t SingleFileTarReader::ReadOctalNumber(const char* buffer,
-                                              size_t length) {
-  DCHECK(length > 8);
-
-  uint64_t num = 0;
-
-  // In GNU tar extension, when the number starts with an invalid ASCII
-  // character 0x80, then non-leading 8 bytes of the field should be interpreted
-  // as a big-endian integer.
-  // https://www.gnu.org/software/tar/manual/html_node/Extensions.html
-  if (static_cast<unsigned char>(buffer[0]) == 0x80) {
-    for (size_t i = length - 8; i < length; ++i) {
-      num <<= 8;
-      num += static_cast<unsigned char>(buffer[i]);
-    }
-    return num;
-  }
-
-  for (size_t i = 0; i < length; ++i) {
-    if (buffer[i] == '\0')
-      break;
-    num *= 8;
-    num += buffer[i] - '0';
-  }
-  return num;
-}
-
-}  // namespace image_writer
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h b/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h
deleted file mode 100644
index 2541d57..0000000
--- a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h
+++ /dev/null
@@ -1,96 +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 CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_SINGLE_FILE_TAR_READER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_SINGLE_FILE_TAR_READER_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/raw_ptr.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace extensions {
-namespace image_writer {
-
-class SingleFileTarReaderTest;
-
-// SingleFileTarReader is a reader of tar archives with limited function. It
-// only supports a tar archive with a single file entry. An archive with
-// multiple files is rejected as error.
-class SingleFileTarReader {
- public:
-  enum class Result { kSuccess, kFailure, kShouldWait };
-
-  // An interface that delegates file I/O of SingleFileTarReader.
-  class Delegate {
-   public:
-    using Result = SingleFileTarReader::Result;
-
-    virtual ~Delegate() = default;
-
-    // Reads input data and returns kSuccess if it succeeds.
-    // The input data will be written to |data|. |*size| is initially the size
-    // of the |data| buffer. |*size| will be set to the amount actually read.
-    // Returns kShouldWait if the data is still not available.
-    // Returns kFailure and sets |error_id| if it fails.
-    virtual Result ReadTarFile(char* data,
-                               uint32_t* size,
-                               std::string* error_id) = 0;
-
-    // Writes the passed data. |size| is the size of the |data| buffer.
-    // Returns false and sets |error_id| if it fails.
-    virtual bool WriteContents(const char* data,
-                               int size,
-                               std::string* error_id) = 0;
-  };
-
-  explicit SingleFileTarReader(Delegate* delegate);
-  SingleFileTarReader(const SingleFileTarReader&) = delete;
-  SingleFileTarReader& operator=(const SingleFileTarReader&) = delete;
-  ~SingleFileTarReader();
-
-  // Extracts a chunk of the tar file. To fully extract the file, the caller has
-  // to repeatedly call this function until IsComplete() returns true.
-  // Returns kShouldWait if the input data is still not available. The caller
-  // has to call ExtractChunk() again when the data is ready. The detail depends
-  // on the implementation of the delegate.
-  // Returns kFailure if it fails. error_id() identifies the reason of the
-  // error.
-  Result ExtractChunk();
-
-  bool IsComplete() const;
-
-  absl::optional<uint64_t> total_bytes() const { return total_bytes_; }
-  uint64_t curr_bytes() const { return curr_bytes_; }
-
-  const std::string& error_id() const { return error_id_; }
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(SingleFileTarReaderTest, ReadOctalNumber);
-
-  // Read a number in Tar file header. It is normally a null-terminated octal
-  // ASCII number but can be big-endian integer with padding when GNU extension
-  // is used. |length| must greater than 8.
-  static uint64_t ReadOctalNumber(const char* buffer, size_t length);
-
-  const raw_ptr<Delegate> delegate_;
-
-  // Populated once the size has been parsed. The value 0 means the file in
-  // the tar is empty.
-  absl::optional<uint64_t> total_bytes_;
-  uint64_t curr_bytes_ = 0;
-
-  std::vector<char> buffer_;
-
-  std::string error_id_;
-};
-
-}  // namespace image_writer
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_SINGLE_FILE_TAR_READER_H_
diff --git a/chrome/browser/extensions/api/image_writer_private/tar_extractor.cc b/chrome/browser/extensions/api/image_writer_private/tar_extractor.cc
index 09e10b5..5190c6d 100644
--- a/chrome/browser/extensions/api/image_writer_private/tar_extractor.cc
+++ b/chrome/browser/extensions/api/image_writer_private/tar_extractor.cc
@@ -4,11 +4,15 @@
 
 #include "chrome/browser/extensions/api/image_writer_private/tar_extractor.h"
 
-#include <algorithm>
 #include <utility>
 
-#include "base/task/sequenced_task_runner.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
+#include "chrome/browser/file_util_service.h"
+
+// TarExtractor extracts a .tar file. The actual .tar file extraction is
+// performed in a utility process.
 
 namespace extensions {
 namespace image_writer {
@@ -24,16 +28,17 @@
 }  // namespace
 
 bool TarExtractor::IsTarFile(const base::FilePath& image_path) {
-  base::File infile(image_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
-                                    base::File::FLAG_WIN_EXCLUSIVE_WRITE |
-                                    base::File::FLAG_WIN_SHARE_DELETE);
-  if (!infile.IsValid())
+  base::File src_file(image_path, base::File::FLAG_OPEN |
+                                      base::File::FLAG_READ |
+                                      base::File::FLAG_WIN_EXCLUSIVE_WRITE |
+                                      base::File::FLAG_WIN_SHARE_DELETE);
+  if (!src_file.IsValid())
     return false;
 
   // Tar header record is always 512 bytes, so if the file is shorter than that,
   // it's not tar.
   char header[512] = {};
-  if (infile.ReadAtCurrentPos(header, sizeof(header)) != sizeof(header))
+  if (src_file.ReadAtCurrentPos(header, sizeof(header)) != sizeof(header))
     return false;
 
   return std::equal(kExpectedMagic, kExpectedMagic + sizeof(kExpectedMagic),
@@ -49,75 +54,85 @@
 }
 
 TarExtractor::TarExtractor(ExtractionProperties properties)
-    : tar_reader_(this), properties_(std::move(properties)) {}
+    : properties_(std::move(properties)) {}
 
 TarExtractor::~TarExtractor() = default;
 
-SingleFileTarReader::Result TarExtractor::ReadTarFile(char* data,
-                                                      uint32_t* size,
-                                                      std::string* error_id) {
-  const int bytes_read = infile_.ReadAtCurrentPos(data, *size);
-  if (bytes_read < 0) {
-    *error_id = error::kUnzipGenericError;
-    return SingleFileTarReader::Result::kFailure;
-  }
-  *size = bytes_read;
-  return SingleFileTarReader::Result::kSuccess;
-}
-
-bool TarExtractor::WriteContents(const char* data,
-                                 int size,
-                                 std::string* error_id) {
-  const int bytes_written = outfile_.WriteAtCurrentPos(data, size);
-  if (bytes_written < 0 || bytes_written != size) {
-    *error_id = error::kTempFileError;
-    return false;
-  }
-  return true;
+void TarExtractor::OnProgress(uint64_t total_bytes, uint64_t progress_bytes) {
+  properties_.progress_callback.Run(total_bytes, progress_bytes);
 }
 
 void TarExtractor::ExtractImpl() {
-  infile_.Initialize(properties_.image_path,
-                     base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!infile_.IsValid()) {
-    std::move(properties_.failure_callback).Run(error::kUnzipGenericError);
-    delete this;
+  service_.Bind(LaunchFileUtilService());
+  service_->BindSingleFileTarFileExtractor(
+      remote_single_file_extractor_.BindNewPipeAndPassReceiver());
+
+  // TODO(b/254591810): Run on a pooled worker thread to avoid blocking
+  // operation on the main UI thread.
+  base::File src_file(properties_.image_path,
+                      base::File::FLAG_OPEN | base::File::FLAG_READ |
+                          // Do not allow others to write to the file.
+                          base::File::FLAG_WIN_EXCLUSIVE_WRITE |
+                          base::File::FLAG_WIN_SHARE_DELETE);
+  if (!src_file.IsValid()) {
+    RunFailureCallbackAndDeleteThis(error::kUnzipGenericError);
     return;
   }
 
   base::FilePath out_image_path =
       properties_.temp_dir_path.Append(kExtractedBinFileName);
-  outfile_.Initialize(out_image_path,
-                      base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
-  if (!outfile_.IsValid()) {
-    std::move(properties_.failure_callback).Run(error::kTempFileError);
-    delete this;
+  // TODO(b/254591810): Run on a pooled worker thread to avoid blocking
+  // operation on the main UI thread.
+  base::File dst_file(out_image_path,
+                      base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+                          // Do not allow others to read the file.
+                          base::File::FLAG_WIN_EXCLUSIVE_READ |
+                          // Do not allow others to write to the file.
+                          base::File::FLAG_WIN_EXCLUSIVE_WRITE |
+                          base::File::FLAG_WIN_SHARE_DELETE);
+  if (!dst_file.IsValid()) {
+    RunFailureCallbackAndDeleteThis(error::kTempFileError);
     return;
   }
   std::move(properties_.open_callback).Run(out_image_path);
 
-  ExtractChunk();
+  // base::Unretained(this) is safe here because callback won't be called once
+  // `remote_single_file_extractor_` is destroyed.
+  remote_single_file_extractor_->Extract(
+      std::move(src_file), std::move(dst_file),
+      listener_.BindNewPipeAndPassRemote(),
+      base::BindOnce(&TarExtractor::OnRemoteFinished, base::Unretained(this)));
 }
 
-void TarExtractor::ExtractChunk() {
-  if (tar_reader_.ExtractChunk() != SingleFileTarReader::Result::kSuccess) {
-    std::move(properties_.failure_callback).Run(tar_reader_.error_id());
-    delete this;
-    return;
+void TarExtractor::OnRemoteFinished(
+    chrome::file_util::mojom::ExtractionResult result) {
+  switch (result) {
+    case chrome::file_util::mojom::ExtractionResult::kSuccess: {
+      auto complete_callback = std::move(properties_.complete_callback);
+      delete this;
+      std::move(complete_callback).Run();
+      return;
+    }
+    case chrome::file_util::mojom::ExtractionResult::kGenericError: {
+      RunFailureCallbackAndDeleteThis(error::kUnzipGenericError);
+      return;
+    }
+    case chrome::file_util::mojom::ExtractionResult::kInvalidSrcFile: {
+      RunFailureCallbackAndDeleteThis(error::kUnzipInvalidArchive);
+      return;
+    }
+    case chrome::file_util::mojom::ExtractionResult::kDstFileError: {
+      RunFailureCallbackAndDeleteThis(error::kTempFileError);
+      return;
+    }
   }
+}
 
-  if (tar_reader_.IsComplete()) {
-    std::move(properties_.complete_callback).Run();
-    delete this;
-    return;
-  }
-
-  properties_.progress_callback.Run(tar_reader_.total_bytes().value(),
-                                    tar_reader_.curr_bytes());
-
-  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindRepeating(&TarExtractor::ExtractChunk,
-                                     weak_ptr_factory_.GetWeakPtr()));
+void TarExtractor::RunFailureCallbackAndDeleteThis(
+    const std::string& error_id) {
+  auto failure_callback = std::move(properties_.failure_callback);
+  delete this;
+  std::move(failure_callback).Run(error_id);
 }
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/tar_extractor.h b/chrome/browser/extensions/api/image_writer_private/tar_extractor.h
index 25fb1cd..7c138ab 100644
--- a/chrome/browser/extensions/api/image_writer_private/tar_extractor.h
+++ b/chrome/browser/extensions/api/image_writer_private/tar_extractor.h
@@ -5,19 +5,24 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_TAR_EXTRACTOR_H_
 #define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_TAR_EXTRACTOR_H_
 
-#include "base/files/file_util.h"
+#include <string>
+
 #include "chrome/browser/extensions/api/image_writer_private/extraction_properties.h"
-#include "chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h"
+#include "chrome/services/file_util/public/mojom/constants.mojom.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace extensions {
 namespace image_writer {
 
-class TarExtractor : public SingleFileTarReader::Delegate {
+class TarExtractor : public chrome::mojom::SingleFileExtractorListener {
  public:
   static bool IsTarFile(const base::FilePath& image_path);
 
-  // Start extracting the archive at |image_path| to |temp_dir_path| in
-  // |properties|.
+  // Start extracting the archive at `image_path` to `temp_dir_path` in
+  // `properties`.
   static void Extract(ExtractionProperties properties);
 
   TarExtractor(const TarExtractor&) = delete;
@@ -28,25 +33,27 @@
   explicit TarExtractor(ExtractionProperties properties);
   ~TarExtractor() override;
 
+  // chrome::mojom::SingleFileExtractorListener implementation.
+  void OnProgress(uint64_t total_bytes, uint64_t progress_bytes) override;
+
   void ExtractImpl();
-  void ExtractChunk();
+  void OnRemoteFinished(chrome::file_util::mojom::ExtractionResult result);
+  void RunFailureCallbackAndDeleteThis(const std::string& error_id);
 
-  // SingleFileTarReader::Delegate:
-  SingleFileTarReader::Result ReadTarFile(char* data,
-                                          uint32_t* size,
-                                          std::string* error_id) override;
-  bool WriteContents(const char* data,
-                     int size,
-                     std::string* error_id) override;
+  // `service_` is a class member so that the utility process where the actual
+  // .tar file extraction is performed is kept alive while extraction is in
+  // progress.
+  mojo::Remote<chrome::mojom::FileUtilService> service_;
 
-  SingleFileTarReader tar_reader_;
+  mojo::Remote<chrome::mojom::SingleFileExtractor>
+      remote_single_file_extractor_;
 
-  base::File infile_;
-  base::File outfile_;
+  // Listener receiver.
+  // This class listens for tar extraction progress reports from the utility
+  // process.
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener_{this};
 
   ExtractionProperties properties_;
-
-  base::WeakPtrFactory<TarExtractor> weak_ptr_factory_{this};
 };
 
 }  // namespace image_writer
diff --git a/chrome/browser/extensions/api/image_writer_private/xz_extractor.cc b/chrome/browser/extensions/api/image_writer_private/xz_extractor.cc
index 1ff2f6c..615a131 100644
--- a/chrome/browser/extensions/api/image_writer_private/xz_extractor.cc
+++ b/chrome/browser/extensions/api/image_writer_private/xz_extractor.cc
@@ -59,8 +59,11 @@
 }
 
 void XzExtractor::ExtractImpl() {
+  // TODO(b/254591810): Run on a pooled worker thread to avoid blocking
+  // operation on the main UI thread.
   base::File src_file(properties_.image_path,
                       base::File::FLAG_OPEN | base::File::FLAG_READ |
+                          // Do not allow others to write to the file.
                           base::File::FLAG_WIN_EXCLUSIVE_WRITE |
                           base::File::FLAG_WIN_SHARE_DELETE);
   if (!src_file.IsValid()) {
@@ -70,11 +73,15 @@
 
   base::FilePath out_image_path =
       properties_.temp_dir_path.Append(kExtractedBinFileName);
-  base::File dst_file(out_image_path, base::File::FLAG_CREATE_ALWAYS |
-                                          base::File::FLAG_WRITE |
-                                          base::File::FLAG_WIN_EXCLUSIVE_READ |
-                                          base::File::FLAG_WIN_EXCLUSIVE_WRITE |
-                                          base::File::FLAG_WIN_SHARE_DELETE);
+  // TODO(b/254591810): Run on a pooled worker thread to avoid blocking
+  // operation on the main UI thread.
+  base::File dst_file(out_image_path,
+                      base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+                          // Do not allow others to read the file.
+                          base::File::FLAG_WIN_EXCLUSIVE_READ |
+                          // Do not allow others to write to the file.
+                          base::File::FLAG_WIN_EXCLUSIVE_WRITE |
+                          base::File::FLAG_WIN_SHARE_DELETE);
   if (!dst_file.IsValid()) {
     RunFailureCallbackAndDeleteThis(error::kTempFileError);
     return;
@@ -83,9 +90,9 @@
 
   service_.Bind(LaunchFileUtilService());
   service_->BindSingleFileTarXzFileExtractor(
-      remote_single_file_tar_xz_file_extractor_.BindNewPipeAndPassReceiver());
+      remote_single_file_extractor_.BindNewPipeAndPassReceiver());
 
-  remote_single_file_tar_xz_file_extractor_->Extract(
+  remote_single_file_extractor_->Extract(
       std::move(src_file), std::move(dst_file),
       listener_.BindNewPipeAndPassRemote(),
       base::BindOnce(&XzExtractor::OnRemoteFinished, base::Unretained(this)));
@@ -100,22 +107,22 @@
       std::move(complete_callback).Run();
       return;
     }
-    case chrome::file_util::mojom::ExtractionResult::kUnzipGenericError: {
+    case chrome::file_util::mojom::ExtractionResult::kGenericError: {
       RunFailureCallbackAndDeleteThis(error::kUnzipGenericError);
       return;
     }
-    case chrome::file_util::mojom::ExtractionResult::kUnzipInvalidArchive: {
+    case chrome::file_util::mojom::ExtractionResult::kInvalidSrcFile: {
       RunFailureCallbackAndDeleteThis(error::kUnzipInvalidArchive);
       return;
     }
-    case chrome::file_util::mojom::ExtractionResult::kTempFileError: {
+    case chrome::file_util::mojom::ExtractionResult::kDstFileError: {
       RunFailureCallbackAndDeleteThis(error::kTempFileError);
       return;
     }
   }
 }
 
-void XzExtractor::RunFailureCallbackAndDeleteThis(std::string error_id) {
+void XzExtractor::RunFailureCallbackAndDeleteThis(const std::string& error_id) {
   auto failure_callback = std::move(properties_.failure_callback);
   delete this;
   std::move(failure_callback).Run(error_id);
diff --git a/chrome/browser/extensions/api/image_writer_private/xz_extractor.h b/chrome/browser/extensions/api/image_writer_private/xz_extractor.h
index 6db6e6e..ec143ec 100644
--- a/chrome/browser/extensions/api/image_writer_private/xz_extractor.h
+++ b/chrome/browser/extensions/api/image_writer_private/xz_extractor.h
@@ -10,7 +10,7 @@
 #include "chrome/browser/extensions/api/image_writer_private/extraction_properties.h"
 #include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
-#include "chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
@@ -23,7 +23,7 @@
 
 // .tar.xz archive extractor. Should be called from a SequencedTaskRunner
 // context.
-class XzExtractor : public chrome::mojom::SingleFileTarXzFileExtractorListener {
+class XzExtractor : public chrome::mojom::SingleFileExtractorListener {
  public:
   static bool IsXzFile(const base::FilePath& image_path);
 
@@ -41,23 +41,25 @@
   explicit XzExtractor(ExtractionProperties properties);
   ~XzExtractor() override;
 
-  // chrome::mojom::SingleFileTarXzFileExtractorListener implementation.
+  // chrome::mojom::SingleFileExtractorListener implementation.
   void OnProgress(uint64_t total_bytes, uint64_t progress_bytes) override;
 
   void ExtractImpl();
   void OnRemoteFinished(chrome::file_util::mojom::ExtractionResult result);
-  // |error_id| might be a member variable, so it cannot be a reference.
-  void RunFailureCallbackAndDeleteThis(std::string error_id);
+  void RunFailureCallbackAndDeleteThis(const std::string& error_id);
 
+  // `service_` is a class member so that the utility process where the actual
+  // .tar.xz file extraction is performed is kept alive while extraction is in
+  // progress.
   mojo::Remote<chrome::mojom::FileUtilService> service_;
-  mojo::Remote<chrome::mojom::SingleFileTarXzFileExtractor>
-      remote_single_file_tar_xz_file_extractor_;
+
+  mojo::Remote<chrome::mojom::SingleFileExtractor>
+      remote_single_file_extractor_;
 
   // Listener receiver.
   // This class listens for .tar.xz extraction progress reports from the utility
   // process.
-  mojo::Receiver<chrome::mojom::SingleFileTarXzFileExtractorListener> listener_{
-      this};
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener_{this};
 
   ExtractionProperties properties_;
 };
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
index 6971683..ffe63c7 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -10,6 +10,7 @@
 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
 #include "content/public/browser/navigation_handle.h"
 #include "net/http/http_response_headers.h"
+#include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
@@ -117,6 +118,19 @@
   return transition & ui::PAGE_TRANSITION_FORWARD_BACK;
 }
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ServiceWorkerResourceLoadStatus {
+  kMainResourceFallbackAndSubResourceFallback = 0,
+  kMainResourceFallbackAndSubResourceNotFallback = 1,
+  kMainResourceFallbackAndSubResourceMixed = 2,
+  kMainResourceFallbackAndNoSubResource = 3,
+  kMainResourceNotFallbackAndSubResourceFallback = 4,
+  kMainResourceNotFallbackAndSubResourceNotFallback = 5,
+  kMainResourceNotFallbackAndSubResourceMixed = 6,
+  kMainResourceNotFallbackAndNoSubResource = 7,
+};
+
 }  // namespace
 
 ServiceWorkerPageLoadMetricsObserver::ServiceWorkerPageLoadMetricsObserver() {}
@@ -382,6 +396,7 @@
           all_frames_largest_contentful_paint.Time().value());
     }
   }
+  RecordSubresourceLoad();
 }
 
 bool ServiceWorkerPageLoadMetricsObserver::IsServiceWorkerControlled() {
@@ -397,3 +412,76 @@
           blink::LoadingBehaviorFlag::
               kLoadingBehaviorServiceWorkerFetchHandlerSkippable) != 0;
 }
+
+void ServiceWorkerPageLoadMetricsObserver::RecordSubresourceLoad() {
+  const auto& optional_metrics = GetDelegate().GetSubresourceLoadMetrics();
+  if (!optional_metrics) {
+    return;
+  }
+  auto metrics = *optional_metrics;
+  // serviceworker's subresource load must always be smaller than
+  // or equals to total subresource loads.
+  if (metrics.number_of_subresource_loads_handled_by_service_worker >
+      metrics.number_of_subresources_loaded) {
+    // If the data is not set or invalid, it should not be worth recording.
+    return;
+  }
+
+  ServiceWorkerResourceLoadStatus status;
+  if (GetDelegate().GetMainFrameMetadata().behavior_flags &
+      blink::LoadingBehaviorFlag::
+          kLoadingBehaviorServiceWorkerMainResourceFetchFallback) {
+    if (metrics.number_of_subresource_loads_handled_by_service_worker == 0) {
+      status = ServiceWorkerResourceLoadStatus::
+          kMainResourceFallbackAndSubResourceFallback;
+    } else if (metrics.number_of_subresources_loaded ==
+               metrics.number_of_subresource_loads_handled_by_service_worker) {
+      if (metrics.number_of_subresources_loaded == 0) {
+        status = ServiceWorkerResourceLoadStatus::
+            kMainResourceFallbackAndSubResourceNotFallback;
+      } else {
+        status = ServiceWorkerResourceLoadStatus::
+            kMainResourceFallbackAndNoSubResource;
+      }
+    } else {
+      status = ServiceWorkerResourceLoadStatus::
+          kMainResourceFallbackAndSubResourceMixed;
+    }
+  } else {
+    if (metrics.number_of_subresource_loads_handled_by_service_worker == 0) {
+      status = ServiceWorkerResourceLoadStatus::
+          kMainResourceNotFallbackAndSubResourceFallback;
+    } else if (metrics.number_of_subresources_loaded ==
+               metrics.number_of_subresource_loads_handled_by_service_worker) {
+      if (metrics.number_of_subresources_loaded == 0) {
+        status = ServiceWorkerResourceLoadStatus::
+            kMainResourceNotFallbackAndSubResourceNotFallback;
+      } else {
+        status = ServiceWorkerResourceLoadStatus::
+            kMainResourceNotFallbackAndNoSubResource;
+      }
+    } else {
+      status = ServiceWorkerResourceLoadStatus::
+          kMainResourceNotFallbackAndSubResourceMixed;
+    }
+  }
+
+  // We calculate the number of fallbacks here.
+  uint32_t number_of_fallback =
+      metrics.number_of_subresources_loaded -
+      metrics.number_of_subresource_loads_handled_by_service_worker;
+  int64_t fallback_ratio = -1;
+  if (metrics.number_of_subresources_loaded > 0) {
+    fallback_ratio =
+        100 * number_of_fallback / metrics.number_of_subresources_loaded;
+  }
+
+  ukm::builders::ServiceWorker_OnLoad(GetDelegate().GetPageUkmSourceId())
+      .SetMainAndSubResourceLoadLocation(static_cast<int64_t>(status))
+      .SetTotalSubResourceLoad(ukm::GetExponentialBucketMinForCounts1000(
+          metrics.number_of_subresources_loaded))
+      .SetTotalSubResourceFallback(
+          ukm::GetExponentialBucketMinForCounts1000(number_of_fallback))
+      .SetSubResourceFallbackRatio(fallback_ratio)
+      .Record(ukm::UkmRecorder::Get());
+}
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
index 5a00b25..0a17468c 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
@@ -93,6 +93,7 @@
   void RecordTimingHistograms();
   bool IsServiceWorkerControlled();
   bool IsServiceWorkerFetchHandlerSkippable();
+  void RecordSubresourceLoad();
 
   ui::PageTransition transition_ = ui::PAGE_TRANSITION_LINK;
   bool was_no_store_main_resource_ = false;
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index 6ead7355..3fe0973 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -676,7 +676,9 @@
   bridge_->SetConsumer(weak_ptr_factory_.GetWeakPtr());
   sync_controller_delegate_ =
       std::make_unique<PasswordSyncControllerDelegateAndroid>(
-          std::make_unique<PasswordSyncControllerDelegateBridgeImpl>());
+          std::make_unique<PasswordSyncControllerDelegateBridgeImpl>(),
+          base::BindOnce(&PasswordStoreAndroidBackend::SyncShutdown,
+                         weak_ptr_factory_.GetWeakPtr()));
 }
 
 PasswordStoreAndroidBackend::PasswordStoreAndroidBackend(
@@ -712,6 +714,7 @@
 
 void PasswordStoreAndroidBackend::Shutdown(
     base::OnceClosure shutdown_completed) {
+  sync_service_ = nullptr;
   lifecycle_helper_->UnregisterObserver();
   // TODO(https://crbug.com/1229654): Implement (e.g. unsubscribe from GMS).
   std::move(shutdown_completed).Run();
@@ -1393,4 +1396,8 @@
   });
 }
 
+void PasswordStoreAndroidBackend::SyncShutdown() {
+  sync_service_ = nullptr;
+}
+
 }  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.h b/chrome/browser/password_manager/android/password_store_android_backend.h
index e9657375..5b5249b 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.h
+++ b/chrome/browser/password_manager/android/password_store_android_backend.h
@@ -319,6 +319,10 @@
   // each task cleared this way that it could have failed.
   void ClearZombieTasks();
 
+  // Clears |sync_service_| when syncer::SyncServiceObserver::OnSyncShutdown is
+  // called.
+  void SyncShutdown();
+
   // Observer to propagate potential password changes to.
   RemoteChangesReceived stored_passwords_changed_;
 
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
index a94f53a..6ae5e3fc 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/callback_forward.h"
 #include "base/callback_helpers.h"
+#include "base/functional/callback_helpers.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/strcat.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -259,7 +260,8 @@
   CreatePasswordSyncControllerDelegate() {
     auto unique_delegate = std::make_unique<
         PasswordSyncControllerDelegateAndroid>(
-        std::make_unique<NiceMock<MockPasswordSyncControllerDelegateBridge>>());
+        std::make_unique<NiceMock<MockPasswordSyncControllerDelegateBridge>>(),
+        base::DoNothing());
     sync_controller_delegate_ = unique_delegate.get();
     return unique_delegate;
   }
diff --git a/chrome/browser/password_manager/android/password_sync_controller_delegate_android.cc b/chrome/browser/password_manager/android/password_sync_controller_delegate_android.cc
index 15095bf..225b73c2 100644
--- a/chrome/browser/password_manager/android/password_sync_controller_delegate_android.cc
+++ b/chrome/browser/password_manager/android/password_sync_controller_delegate_android.cc
@@ -31,8 +31,10 @@
 }  // namespace
 
 PasswordSyncControllerDelegateAndroid::PasswordSyncControllerDelegateAndroid(
-    std::unique_ptr<PasswordSyncControllerDelegateBridge> bridge)
-    : bridge_(std::move(bridge)) {
+    std::unique_ptr<PasswordSyncControllerDelegateBridge> bridge,
+    base::OnceClosure on_sync_shutdown)
+    : bridge_(std::move(bridge)),
+      on_sync_shutdown_(std::move(on_sync_shutdown)) {
   DCHECK(bridge_);
   bridge_->SetConsumer(weak_ptr_factory_.GetWeakPtr());
 }
@@ -144,6 +146,14 @@
   }
 }
 
+void PasswordSyncControllerDelegateAndroid::OnSyncShutdown(
+    syncer::SyncService* sync) {
+  sync_service_ = nullptr;
+  if (!on_sync_shutdown_)
+    return;
+  std::move(on_sync_shutdown_).Run();
+}
+
 void PasswordSyncControllerDelegateAndroid::OnCredentialManagerNotified() {
   base::UmaHistogramBoolean(
       BuildCredentialManagerNotificationMetricName("Success"), 1);
diff --git a/chrome/browser/password_manager/android/password_sync_controller_delegate_android.h b/chrome/browser/password_manager/android/password_sync_controller_delegate_android.h
index 0709f51f..cb345df 100644
--- a/chrome/browser/password_manager/android/password_sync_controller_delegate_android.h
+++ b/chrome/browser/password_manager/android/password_sync_controller_delegate_android.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/functional/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/types/strong_alias.h"
@@ -31,7 +32,8 @@
       public PasswordSyncControllerDelegateBridge::Consumer {
  public:
   explicit PasswordSyncControllerDelegateAndroid(
-      std::unique_ptr<PasswordSyncControllerDelegateBridge> bridge);
+      std::unique_ptr<PasswordSyncControllerDelegateBridge> bridge,
+      base::OnceClosure on_sync_shutdown);
   PasswordSyncControllerDelegateAndroid(
       const PasswordSyncControllerDelegateAndroid&) = delete;
   PasswordSyncControllerDelegateAndroid(
@@ -54,6 +56,7 @@
 
   // syncer::SyncServiceObserver implementation.
   void OnStateChanged(syncer::SyncService* sync) override;
+  void OnSyncShutdown(syncer::SyncService* sync) override;
 
   // PasswordStoreAndroidBackendBridge::Consumer implementation.
   void OnCredentialManagerNotified() override;
@@ -83,6 +86,8 @@
   // Last sync status set in CredentialManager.
   absl::optional<IsSyncEnabled> credential_manager_sync_setting_;
 
+  base::OnceClosure on_sync_shutdown_;
+
   base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
       sync_observation_{this};
 
diff --git a/chrome/browser/password_manager/android/password_sync_controller_delegate_android_unittest.cc b/chrome/browser/password_manager/android/password_sync_controller_delegate_android_unittest.cc
index f90cb43..f63fac52 100644
--- a/chrome/browser/password_manager/android/password_sync_controller_delegate_android_unittest.cc
+++ b/chrome/browser/password_manager/android/password_sync_controller_delegate_android_unittest.cc
@@ -6,7 +6,9 @@
 
 #include <memory>
 
+#include "base/functional/callback_helpers.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/password_manager/android/mock_password_sync_controller_delegate_bridge.h"
 #include "components/password_manager/core/browser/android_backend_error.h"
@@ -32,7 +34,8 @@
  protected:
   PasswordSyncControllerDelegateAndroidTest() {
     sync_controller_delegate_ =
-        std::make_unique<PasswordSyncControllerDelegateAndroid>(CreateBridge());
+        std::make_unique<PasswordSyncControllerDelegateAndroid>(
+            CreateBridge(), base::DoNothing());
   }
 
   ~PasswordSyncControllerDelegateAndroidTest() override {
@@ -50,7 +53,6 @@
     return *sync_controller_delegate_;
   }
 
- private:
   std::unique_ptr<PasswordSyncControllerDelegateBridge> CreateBridge() {
     auto unique_delegate_bridge = std::make_unique<
         StrictMock<MockPasswordSyncControllerDelegateBridge>>();
@@ -59,6 +61,7 @@
     return unique_delegate_bridge;
   }
 
+ private:
   base::test::SingleThreadTaskEnvironment task_environment_;
   syncer::TestSyncService sync_service_;
   std::unique_ptr<PasswordSyncControllerDelegateAndroid>
@@ -205,4 +208,15 @@
   EXPECT_TRUE(sync_service()->HasObserver(sync_controller_delegate()));
 }
 
+TEST_F(PasswordSyncControllerDelegateAndroidTest, OnSyncShutdown) {
+  base::MockCallback<base::OnceClosure> mock_callback;
+  auto sync_controller =
+      std::make_unique<PasswordSyncControllerDelegateAndroid>(
+          CreateBridge(), mock_callback.Get());
+  syncer::TestSyncService sync_service;
+
+  EXPECT_CALL(mock_callback, Run);
+  sync_controller->OnSyncShutdown(&sync_service);
+}
+
 }  // namespace password_manager
diff --git a/chrome/browser/resources/apc_internals/apc_internals.js b/chrome/browser/resources/apc_internals/apc_internals.js
index 1726c734..5fb5ea2 100644
--- a/chrome/browser/resources/apc_internals/apc_internals.js
+++ b/chrome/browser/resources/apc_internals/apc_internals.js
@@ -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 {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 function createButton(text, onClickClosure) {
@@ -158,14 +158,14 @@
 }
 
 document.addEventListener('DOMContentLoaded', function(event) {
-  addWebUIListener('on-flags-information-received', onFlagsInfoReceived);
-  addWebUIListener('on-prefs-information-received', onPrefsInfoReceived);
-  addWebUIListener(
+  addWebUiListener('on-flags-information-received', onFlagsInfoReceived);
+  addWebUiListener('on-prefs-information-received', onPrefsInfoReceived);
+  addWebUiListener(
       'on-script-fetching-information-received', onScriptFetchingInfoReceived);
-  addWebUIListener(
+  addWebUiListener(
       'on-autofill-assistant-information-received',
       onAutofillAssistantInfoReceived);
-  addWebUIListener('on-script-cache-received', onScriptCacheReceived);
+  addWebUiListener('on-script-cache-received', onScriptCacheReceived);
 
   hideScriptCache();
   $('script-cache-hide').onclick = hideScriptCache;
diff --git a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.html b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.html
index e823e33..2a6392a 100644
--- a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.html
+++ b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.html
@@ -41,6 +41,7 @@
     display: flex;
     font: var(--cros-body-1-font);
     height: 54px;
+    margin-block-end: 4px;
   }
 
   .radio-label:has(> input[type='radio']) {
@@ -76,7 +77,7 @@
     <div class="icon-placeholder"></div>
     <span id="drive-app-name"></span>
   </label>
-  <div class="normal-text">
+  <div class="normal-text" id="available-to-install">
     Apps available to install
   </div>
 
diff --git a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
index 7953d8a1b..b959ddcc 100644
--- a/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
+++ b/chrome/browser/resources/chromeos/cloud_upload/file_handler_page.ts
@@ -38,9 +38,17 @@
   // Sets the dynamic content of the page like the file name.
   async initDynamicContent() {
     try {
-      const dialogArgs = await this.proxy.handler.getDialogArgs();
+      const [dialogArgs, {installed: isOfficePwaInstalled}] =
+          await Promise.all([
+            this.proxy.handler.getDialogArgs(),
+            this.proxy.handler.isOfficePWAInstalled(),
+          ]);
       assert(dialogArgs.args);
 
+      if (isOfficePwaInstalled) {
+        this.shadowRoot!.querySelector('#available-to-install')!.remove();
+      }
+
       const fileNameElement =
           this.shadowRoot!.querySelector<HTMLSpanElement>('#file-name');
       assert(fileNameElement);
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
index b6853955..49455f3 100644
--- a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
@@ -1,3 +1,4 @@
+<!-- TODO(b/259386106): reduce duplication with login screen code -->
 <style>
   :host {
     --lock-screen-reauth-dialog-buttons-horizontal-padding: 40px;
@@ -93,8 +94,8 @@
   }
 
   #samlContainer[saml-notice-message] {
-    /* #F1F3F4 */
-    background: rgb(241, 243, 244);
+    /* #FFFFFF */
+    background: white;
   }
 
   #samlNoticeMessage {
@@ -105,6 +106,18 @@
     padding-top: 15px;
   }
 
+  #saml-footer-container {
+    align-items: center;
+    background: white;
+    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.17);
+     /* #6a6a6a */
+    color: rgb(106, 106, 106);
+    display: flex;
+    height: 58px;
+    justify-content: flex-end;
+    min-height: 0;
+  }
+
   #saml-close-button {
     --cr-icon-button-margin-end: 0;
     --cr-icon-button-margin-start: 0;
@@ -116,6 +129,12 @@
     width: 100%;
   }
 
+  #change-account {
+    margin: 0 4px;
+    padding-inline-end: 8px;
+    padding-inline-start: 8px;
+  }
+
   .title-icon {
     /* #1a73e8 */
     --iron-icon-fill-color: rgb(26, 115, 232);
@@ -292,6 +311,14 @@
   </div>
   <webview id="signin-frame" name="signin-frame" class="flex">
   </webview>
+  <div id="saml-footer-container" hidden="[[!isDefaultSsoProvider]]"
+     class="layout horizontal">
+    <div>[[i18nDynamic(locale, 'samlChangeProviderMessage')]]</div>
+    <oobe-text-button id="change-account"
+        text-key="samlChangeProviderButton"
+        on-click="onChangeSigninProviderClicked_">
+    </oobe-text-button>
+  </div>
 </div>
 
 <div id="samlConfirmPasswordScreen" class="content-wrapper"
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js
index 1882ba46..bc9d2fe2 100644
--- a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js
@@ -13,6 +13,7 @@
 import 'chrome://resources/cr_elements/cr_input/cr_input.js';
 import 'chrome://resources/cr_elements/icons.html.js';
 import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
+import './components/buttons/oobe_text_button.js';
 import './components/oobe_icons.m.js';
 
 import {I18nBehavior} from 'chrome://resources/ash/common/i18n_behavior.js';
@@ -73,6 +74,14 @@
     },
 
     /**
+     * Whether default SAML IdP is shown.
+     */
+    isDefaultSsoProvider: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
      * Whether there is a failure to scrape the user's password.
      */
     isConfirmPassword_: {
@@ -191,6 +200,7 @@
 
     this.authenticatorParams_ = params;
     this.email_ = data.email;
+    this.isDefaultSsoProvider = data.doSamlRedirect;
     if (!data['doSamlRedirect']) {
       this.doGaiaRedirect_();
     }
@@ -381,4 +391,15 @@
                          'passwordChangedIncorrectOldPassword');
   },
 
+  /**
+   * Invoked when "Enter Google Account info" button is pressed on SAML screen.
+   * @private
+   */
+  onChangeSigninProviderClicked_() {
+    this.authenticatorParams_.doSamlRedirect = false;
+    this.authenticatorParams_.enableGaiaActionButtons = true;
+    this.isDefaultSsoProvider = false;
+    this.authenticator_.load(AuthMode.DEFAULT, this.authenticatorParams_);
+  },
+
 });
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.js b/chrome/browser/resources/device_log_ui/device_log_ui.js
index 8fd3b5c..8335e5f 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.js
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.js
@@ -4,7 +4,7 @@
 
 import './strings.m.js';
 
-import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {sendWithPromise} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {$} from 'chrome://resources/js/util.js';
 
diff --git a/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js
index b4ed094..864bfd2 100644
--- a/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js
+++ b/chrome/browser/resources/family_link_user_internals/family_link_user_internals.js
@@ -4,7 +4,7 @@
 
 import 'chrome://resources/js/jstemplate_compiled.js';
 
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 function initialize() {
@@ -24,9 +24,9 @@
   // Make the prototype jscontent element disappear.
   jstProcess({}, $('filtering-results-container'));
 
-  addWebUIListener('basic-info-received', receiveBasicInfo);
-  addWebUIListener('user-settings-received', receiveUserSettings);
-  addWebUIListener('filtering-result-received', receiveFilteringResult);
+  addWebUiListener('basic-info-received', receiveBasicInfo);
+  addWebUiListener('user-settings-received', receiveUserSettings);
+  addWebUiListener('filtering-result-received', receiveFilteringResult);
 
   chrome.send('registerForEvents');
 
diff --git a/chrome/browser/resources/invalidations/about_invalidations.js b/chrome/browser/resources/invalidations/about_invalidations.js
index 94630ff..21781f3 100644
--- a/chrome/browser/resources/invalidations/about_invalidations.js
+++ b/chrome/browser/resources/invalidations/about_invalidations.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/js/jstemplate_compiled.js';
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 import {loadTestModule} from './test_loader_util.js';
 
@@ -195,15 +195,15 @@
  * ready to receive real-time notifications.
  */
 function onLoadWork() {
-  addWebUIListener('handlers-updated', handlers => updateHandlers(handlers));
-  addWebUIListener(
+  addWebUiListener('handlers-updated', handlers => updateHandlers(handlers));
+  addWebUiListener(
       'state-updated',
       (state, lastChanged) => updateInvalidatorState(state, lastChanged));
-  addWebUIListener(
+  addWebUiListener(
       'ids-updated', (registrar, ids) => updateIds(registrar, ids));
-  addWebUIListener(
+  addWebUiListener(
       'log-invalidations', invalidations => logInvalidations(invalidations));
-  addWebUIListener(
+  addWebUiListener(
       'detailed-status-updated',
       networkDetails => updateDetailedStatus(networkDetails));
   $('request-detailed-status').onclick = function() {
diff --git a/chrome/browser/resources/net_internals/browser_bridge.js b/chrome/browser/resources/net_internals/browser_bridge.js
index 0411d18..41bc387 100644
--- a/chrome/browser/resources/net_internals/browser_bridge.js
+++ b/chrome/browser/resources/net_internals/browser_bridge.js
@@ -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 {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {sendWithPromise} from 'chrome://resources/js/cr.js';
 
 /** @type {?BrowserBridge} */
 let instance = null;
diff --git a/chrome/browser/resources/ntp4/incognito_tab.js b/chrome/browser/resources/ntp4/incognito_tab.js
index 78608423..5a955b13 100644
--- a/chrome/browser/resources/ntp4/incognito_tab.js
+++ b/chrome/browser/resources/ntp4/incognito_tab.js
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 window.addEventListener('load', function() {
   let cookieSettingsUrl;
 
-  addWebUIListener('theme-changed', themeData => {
+  addWebUiListener('theme-changed', themeData => {
     document.documentElement.setAttribute(
         'hascustombackground', themeData.hasCustomBackground);
     $('incognitothemecss').href =
@@ -16,7 +16,7 @@
   });
   chrome.send('observeThemeChanges');
 
-  addWebUIListener('cookie-controls-changed', dict => {
+  addWebUiListener('cookie-controls-changed', dict => {
     $('cookie-controls-tooltip-icon').hidden = !dict.enforced;
     $('cookie-controls-tooltip-icon').iconClass = dict.icon;
     $('cookie-controls-toggle').disabled = dict.enforced;
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js
index d873b0f..b8a879a 100644
--- a/chrome/browser/resources/ntp4/new_tab.js
+++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -5,7 +5,7 @@
 import './strings.m.js';
 
 import {assert} from 'chrome://resources/js/assert.js';
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {$, appendParam, getRequiredElement} from 'chrome://resources/js/util.js';
 
@@ -110,7 +110,7 @@
 
     startTime = Date.now();
 
-    addWebUIListener('theme-changed', () => {
+    addWebUiListener('theme-changed', () => {
       $('themecss').href = 'chrome://theme/css/new_tab_theme.css?' + Date.now();
     });
     chrome.send('observeThemeChanges');
diff --git a/chrome/browser/resources/settings/chromeos/os_privacy_page/privacy_hub_page.html b/chrome/browser/resources/settings/chromeos/os_privacy_page/privacy_hub_page.html
index 386a867d..5519ab1 100644
--- a/chrome/browser/resources/settings/chromeos/os_privacy_page/privacy_hub_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_privacy_page/privacy_hub_page.html
@@ -1,7 +1,12 @@
 <style include="settings-shared">
-    iron-list > :not(:last-of-type) {
+    .list-item:not(:last-of-type) {
       border-bottom: var(--cr-separator-line);
     }
+
+    .list-frame {
+      padding-bottom: 8px;
+      padding-top: 8px;
+    }
 </style>
 
 <div id="camera">
@@ -24,13 +29,11 @@
     </template>
 
     <template is="dom-if" if="[[!isCameraListEmpty_]]" restamp>
-      <iron-list id="cameraList" items="[[camerasConnected_]]">
-        <template>
-          <div class="list-item">
-            [[item]]
-          </div>
-        </template>
-      </iron-list>
+      <template id="cameraList" is="dom-repeat" items="[[camerasConnected_]]">
+        <div class="list-item">
+          [[item]]
+        </div>
+      </template>
     </template>
   </div>
 </div>
@@ -55,13 +58,11 @@
     </template>
 
     <template is="dom-if" if="[[!isMicListEmpty_]]" restamp>
-      <iron-list id="micList" items="[[microphonesConnected_]]">
-        <template>
-          <div class="list-item">
-            [[item]]
-          </div>
-        </template>
-      </iron-list>
+      <template id="micList" is="dom-repeat" items="[[microphonesConnected_]]">
+        <div class="list-item">
+          [[item]]
+        </div>
+      </template>
     </template>
   </div>
 </div>
diff --git a/chrome/browser/signin/account_reconcilor_factory.cc b/chrome/browser/signin/account_reconcilor_factory.cc
index d353893..c90dd191 100644
--- a/chrome/browser/signin/account_reconcilor_factory.cc
+++ b/chrome/browser/signin/account_reconcilor_factory.cc
@@ -20,6 +20,7 @@
 #include "components/signin/core/browser/mirror_account_reconcilor_delegate.h"
 #include "components/signin/public/base/account_consistency_method.h"
 #include "components/signin/public/base/signin_buildflags.h"
+#include "components/signin/public/base/signin_client.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
@@ -218,7 +219,8 @@
     case signin::AccountConsistencyMethod::kDice:
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
       return std::make_unique<signin::DiceAccountReconcilorDelegate>(
-          IdentityManagerFactory::GetForProfile(profile));
+          IdentityManagerFactory::GetForProfile(profile),
+          ChromeSigninClientFactory::GetForProfile(profile));
 #else
       NOTREACHED();
       return nullptr;
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 58111bd7..f518588e 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -38,6 +38,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/cookie_settings_util.h"
 #include "components/signin/public/base/signin_buildflags.h"
+#include "components/signin/public/base/signin_client.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/access_token_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -199,6 +200,11 @@
       ->RemoveObserver(observer);
 }
 
+bool ChromeSigninClient::IsClearPrimaryAccountAllowed() const {
+  return UserSignoutSettingToSignoutDecision(profile_) ==
+         SigninClient::SignoutDecision::ALLOW;
+}
+
 void ChromeSigninClient::PreSignOut(
     base::OnceCallback<void(SignoutDecision)> on_signout_decision_reached,
     signin_metrics::ProfileSignout signout_source_metric) {
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index ad785bc..a743e48 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -49,6 +49,7 @@
 
   // SigninClient implementation.
   PrefService* GetPrefs() override;
+  bool IsClearPrimaryAccountAllowed() const override;
   void PreSignOut(
       base::OnceCallback<void(SignoutDecision)> on_signout_decision_reached,
       signin_metrics::ProfileSignout signout_source_metric) override;
diff --git a/chrome/browser/signin/chrome_signin_client_unittest.cc b/chrome/browser/signin/chrome_signin_client_unittest.cc
index be605b6f..69fe52d 100644
--- a/chrome/browser/signin/chrome_signin_client_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_client_unittest.cc
@@ -265,6 +265,8 @@
     case signin_metrics::ProfileSignout::
         IOS_ACCOUNT_REMOVED_FROM_DEVICE_AFTER_RESTORE:
     case signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES:
+    case signin_metrics::ProfileSignout::GAIA_COOKIE_UPDATED:
+    case signin_metrics::ProfileSignout::ACCOUNT_RECONCILOR_RECONCILE:
     // There's no special-casing for these in ChromeSigninClient, as they only
     // happen when there's no sync account and policies aren't enforced.
     // PrimaryAccountManager won't actually invoke PreSignOut in this case,
@@ -429,6 +431,8 @@
     signin_metrics::ProfileSignout::ACCOUNT_EMAIL_UPDATED,
     signin_metrics::ProfileSignout::
         USER_CLICKED_SIGNOUT_FROM_CLEAR_BROWSING_DATA_PAGE,
+    signin_metrics::ProfileSignout::GAIA_COOKIE_UPDATED,
+    signin_metrics::ProfileSignout::ACCOUNT_RECONCILOR_RECONCILE,
 };
 // kNumberOfObsoleteSignoutSources should be updated when a ProfileSignout
 // value is deprecated.
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index 646c139..159e15f 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/signin/core/browser/about_signin_internals.h"
 #include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/public/base/consent_level.h"
 #include "components/signin/public/base/signin_client.h"
 #include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/identity_manager/accounts_mutator.h"
@@ -323,8 +324,14 @@
     const std::vector<signin::DiceResponseParams::AccountInfo>& account_infos) {
   VLOG(1) << "Start processing Dice signout response";
 
-  CoreAccountId primary_account =
-      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSync);
+  // If there is a restriction on removing the primary account. Do not remove
+  // the account regardless of the consent level. Else, the sync account can
+  // only be invalidated.
+  signin::ConsentLevel level = signin_client_->IsClearPrimaryAccountAllowed()
+                                   ? signin::ConsentLevel::kSync
+                                   : signin::ConsentLevel::kSignin;
+
+  CoreAccountId primary_account = identity_manager_->GetPrimaryAccountId(level);
   bool primary_account_signed_out = false;
   auto* accounts_mutator = identity_manager_->GetAccountsMutator();
   for (const auto& account_info : account_infos) {
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 3840333..1b30418 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -36,6 +36,15 @@
 const char kEmail[] = "test@email.com";
 const int kSessionIndex = 42;
 
+DiceResponseParams::AccountInfo GetDiceResponseParamsAccountInfo(
+    const std::string& email) {
+  DiceResponseParams::AccountInfo account_info;
+  account_info.gaia_id = signin::GetTestGaiaIdForEmail(email);
+  account_info.email = kEmail;
+  account_info.session_index = kSessionIndex;
+  return account_info;
+}
+
 // TestSigninClient implementation that intercepts the GaiaAuthConsumer and
 // replaces it by a dummy one.
 class DiceTestSigninClient : public TestSigninClient, public GaiaAuthConsumer {
@@ -113,7 +122,7 @@
     AboutSigninInternals::RegisterPrefs(pref_service_.registry());
     auto account_reconcilor_delegate =
         std::make_unique<signin::DiceAccountReconcilorDelegate>(
-            identity_manager());
+            identity_manager(), &signin_client_);
     account_reconcilor_ = std::make_unique<AccountReconcilor>(
         identity_test_env_.identity_manager(), &signin_client_,
         std::move(account_reconcilor_delegate));
@@ -140,10 +149,8 @@
   DiceResponseParams MakeDiceParams(DiceAction action) {
     DiceResponseParams dice_params;
     dice_params.user_intention = action;
-    DiceResponseParams::AccountInfo account_info;
-    account_info.gaia_id = signin::GetTestGaiaIdForEmail(kEmail);
-    account_info.email = kEmail;
-    account_info.session_index = kSessionIndex;
+    DiceResponseParams::AccountInfo account_info =
+        GetDiceResponseParamsAccountInfo(kEmail);
     switch (action) {
       case DiceAction::SIGNIN:
         dice_params.signin_info =
@@ -822,6 +829,53 @@
           account_id_2));
 }
 
+TEST_F(DiceResponseHandlerTest,
+       SignoutMainNonSyncAccountWithSignoutRestrictions) {
+  signin_client_.set_is_clear_primary_account_allowed(
+      SigninClient::SignoutDecision::CLEAR_PRIMARY_ACCOUNT_DISALLOWED);
+  const char kSecondaryEmail[] = "other@gmail.com";
+  DiceResponseParams dice_params = MakeDiceParams(DiceAction::SIGNOUT);
+  dice_params.signout_info->account_infos.push_back(
+      GetDiceResponseParamsAccountInfo(kSecondaryEmail));
+  const auto& dice_account_info = dice_params.signout_info->account_infos[0];
+  AccountInfo account_info = identity_test_env_.MakePrimaryAccountAvailable(
+      dice_account_info.email, signin::ConsentLevel::kSignin);
+  AccountInfo secondary_account_info =
+      identity_test_env_.MakeAccountAvailable(kSecondaryEmail);
+  EXPECT_TRUE(
+      identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
+  EXPECT_TRUE(identity_manager()->HasAccountWithRefreshToken(
+      secondary_account_info.account_id));
+  EXPECT_FALSE(
+      identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync));
+  EXPECT_TRUE(
+      identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin));
+  // Receive signout response.
+  dice_response_handler_->ProcessDiceHeader(
+      dice_params, std::make_unique<TestProcessDiceHeaderDelegate>(this));
+  // User is not signed out, token for the main account is now invalid.
+  // Secondary account removed.
+  EXPECT_TRUE(
+      identity_manager()->HasAccountWithRefreshToken(account_info.account_id));
+  EXPECT_TRUE(
+      identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
+          account_info.account_id));
+  auto error = identity_manager()->GetErrorStateOfRefreshTokenForAccount(
+      account_info.account_id);
+  EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error.state());
+  EXPECT_EQ(GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+                CREDENTIALS_REJECTED_BY_CLIENT,
+            error.GetInvalidGaiaCredentialsReason());
+  EXPECT_FALSE(identity_manager()->HasAccountWithRefreshToken(
+      secondary_account_info.account_id));
+
+  EXPECT_TRUE(
+      identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin));
+  // Check that the reconcilor was not blocked.
+  EXPECT_EQ(0, reconcilor_blocked_count_);
+  EXPECT_EQ(0, reconcilor_unblocked_count_);
+}
+
 // Tests that the DiceResponseHandler is created for a normal profile but not
 // for off-the-record profiles.
 TEST(DiceResponseHandlerFactoryTest, NotInOffTheRecord) {
diff --git a/chrome/browser/support_tool/support_tool_util.cc b/chrome/browser/support_tool/support_tool_util.cc
index c2f0d50..a499b19 100644
--- a/chrome/browser/support_tool/support_tool_util.cc
+++ b/chrome/browser/support_tool/support_tool_util.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/files/file_path.h"
 #include "build/chromeos_buildflags.h"
@@ -42,6 +43,45 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+namespace {
+
+// Data collector types that can work on every platform.
+constexpr support_tool::DataCollectorType kDataCollectors[] = {
+    support_tool::CHROME_INTERNAL, support_tool::CRASH_IDS,
+    support_tool::MEMORY_DETAILS, support_tool::POLICIES};
+
+// Data collector types can only work on Chrome OS Ash.
+constexpr support_tool::DataCollectorType kDataCollectorsChromeosAsh[] = {
+    support_tool::CHROMEOS_UI_HIERARCHY,
+    support_tool::CHROMEOS_COMMAND_LINE,
+    support_tool::CHROMEOS_DEVICE_EVENT,
+    support_tool::CHROMEOS_IWL_WIFI_DUMP,
+    support_tool::CHROMEOS_TOUCH_EVENTS,
+    support_tool::CHROMEOS_DBUS,
+    support_tool::CHROMEOS_NETWORK_ROUTES,
+    support_tool::CHROMEOS_SHILL,
+    support_tool::CHROMEOS_SYSTEM_STATE,
+    support_tool::CHROMEOS_SYSTEM_LOGS,
+    support_tool::CHROMEOS_CHROME_USER_LOGS,
+    support_tool::CHROMEOS_BLUETOOTH_FLOSS,
+    support_tool::CHROMEOS_CONNECTED_INPUT_DEVICES,
+    support_tool::CHROMEOS_TRAFFIC_COUNTERS,
+    support_tool::CHROMEOS_VIRTUAL_KEYBOARD};
+
+// Data collector types that can only work on if IS_CHROMEOS_WITH_HW_DETAILS
+// flag is turned on. IS_CHROMEOS_WITH_HW_DETAILS flag will be turned on for
+// Chrome OS Flex devices.
+constexpr support_tool::DataCollectorType kDataCollectorsChromeosHwDetails[] = {
+    support_tool::CHROMEOS_REVEN};
+
+// Data collector types that may be available on the device depending on other
+// components or flags. Currently consists of data collactors that collect
+// logs for Lacros.
+constexpr support_tool::DataCollectorType kOptionalDataCollectors[] = {
+    support_tool::CHROMEOS_CROS_API, support_tool::CHROMEOS_LACROS};
+
+}  // namespace
+
 std::unique_ptr<SupportToolHandler> GetSupportToolHandler(
     std::string case_id,
     std::string email_address,
@@ -201,3 +241,44 @@
   }
   return handler;
 }
+
+std::vector<support_tool::DataCollectorType> GetAllDataCollectors() {
+  std::vector<support_tool::DataCollectorType> data_collectors;
+  for (const auto& type : kDataCollectors) {
+    data_collectors.push_back(type);
+  }
+  for (const auto& type : kDataCollectorsChromeosAsh) {
+    data_collectors.push_back(type);
+  }
+  for (const auto& type : kDataCollectorsChromeosHwDetails) {
+    data_collectors.push_back(type);
+  }
+  for (const auto& type : kOptionalDataCollectors) {
+    data_collectors.push_back(type);
+  }
+  return data_collectors;
+}
+
+std::vector<support_tool::DataCollectorType>
+GetAllAvailableDataCollectorsOnDevice() {
+  std::vector<support_tool::DataCollectorType> data_collectors;
+  for (const auto& type : kDataCollectors) {
+    data_collectors.push_back(type);
+  }
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  for (const auto& type : kDataCollectorsChromeosAsh) {
+    data_collectors.push_back(type);
+  }
+  if (crosapi::browser_util::IsLacrosEnabled())
+    data_collectors.push_back(support_tool::CHROMEOS_LACROS);
+  if (crosapi::BrowserManager::Get()->IsRunning() &&
+      crosapi::BrowserManager::Get()->GetFeedbackDataSupported())
+    data_collectors.push_back(support_tool::CHROMEOS_CROS_API);
+#if BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
+  for (const auto& type : kDataCollectorsChromeosHwDetails) {
+    data_collectors.push_back(type);
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  return data_collectors;
+}
diff --git a/chrome/browser/support_tool/support_tool_util.h b/chrome/browser/support_tool/support_tool_util.h
index 0b6ee0b..92cee75 100644
--- a/chrome/browser/support_tool/support_tool_util.h
+++ b/chrome/browser/support_tool/support_tool_util.h
@@ -5,42 +5,14 @@
 #ifndef CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_UTIL_H_
 #define CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_UTIL_H_
 
+#include <set>
+#include <vector>
+
 #include "chrome/browser/support_tool/data_collection_module.pb.h"
 #include "chrome/browser/support_tool/support_tool_handler.h"
 
 class Profile;
 
-// Data collector types that can work on every platform.
-static constexpr support_tool::DataCollectorType kDataCollectors[] = {
-    support_tool::CHROME_INTERNAL, support_tool::CRASH_IDS,
-    support_tool::MEMORY_DETAILS, support_tool::POLICIES};
-
-// Data collector types can only work on Chrome OS Ash.
-static constexpr support_tool::DataCollectorType kDataCollectorsChromeosAsh[] =
-    {support_tool::CHROMEOS_UI_HIERARCHY,
-     support_tool::CHROMEOS_COMMAND_LINE,
-     support_tool::CHROMEOS_DEVICE_EVENT,
-     support_tool::CHROMEOS_IWL_WIFI_DUMP,
-     support_tool::CHROMEOS_TOUCH_EVENTS,
-     support_tool::CHROMEOS_CROS_API,
-     support_tool::CHROMEOS_LACROS,
-     support_tool::CHROMEOS_DBUS,
-     support_tool::CHROMEOS_NETWORK_ROUTES,
-     support_tool::CHROMEOS_SHILL,
-     support_tool::CHROMEOS_SYSTEM_STATE,
-     support_tool::CHROMEOS_SYSTEM_LOGS,
-     support_tool::CHROMEOS_CHROME_USER_LOGS,
-     support_tool::CHROMEOS_BLUETOOTH_FLOSS,
-     support_tool::CHROMEOS_CONNECTED_INPUT_DEVICES,
-     support_tool::CHROMEOS_TRAFFIC_COUNTERS,
-     support_tool::CHROMEOS_VIRTUAL_KEYBOARD};
-
-// Data collector types that can only work on if IS_CHROMEOS_WITH_HW_DETAILS
-// flag is turned on. IS_CHROMEOS_WITH_HW_DETAILS flag will be turned on for
-// Chrome OS Flex devices.
-static constexpr support_tool::DataCollectorType
-    kDataCollectorsChromeosHwDetails[] = {support_tool::CHROMEOS_REVEN};
-
 // Returns SupportToolHandler that is created for collecting logs from the
 // given information. Adds the corresponding DataCollectors that were listed in
 // `included_data_collectors` to the returned SupportToolHandler.
@@ -51,4 +23,9 @@
     Profile* profile,
     std::set<support_tool::DataCollectorType> included_data_collectors);
 
+std::vector<support_tool::DataCollectorType> GetAllDataCollectors();
+
+std::vector<support_tool::DataCollectorType>
+GetAllAvailableDataCollectorsOnDevice();
+
 #endif  // CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_UTIL_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 2029edbf..33261c5 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -534,6 +534,7 @@
     "//components/optimization_guide/optimization_guide_internals/webui",
     "//components/optimization_guide/optimization_guide_internals/webui:mojo_bindings",
     "//components/password_manager/content/browser",
+    "//components/password_manager/content/common",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/browser:affiliation",
     "//components/password_manager/core/browser:import_results",
@@ -1847,6 +1848,7 @@
       "//components/network_session_configurator/common",
       "//components/page_load_metrics/browser",
       "//components/paint_preview/buildflags",
+      "//components/password_manager/content/common",
       "//components/performance_manager:site_data_proto",
       "//components/reading_list/features:flags",
       "//components/safe_browsing/core/common:safe_browsing_policy_handler",
@@ -2097,8 +2099,6 @@
       "app_list/search/common/string_util.h",
       "app_list/search/common/types_util.cc",
       "app_list/search/common/types_util.h",
-      "app_list/search/common/url_icon_source.cc",
-      "app_list/search/common/url_icon_source.h",
       "app_list/search/cros_action_history/cros_action_recorder.cc",
       "app_list/search/cros_action_history/cros_action_recorder.h",
       "app_list/search/cros_action_history/cros_action_recorder_tab_tracker.cc",
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
index 7923755..9b29d4a9 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
@@ -126,7 +126,8 @@
         suggestion.frontend_id == POPUP_ITEM_ID_MIXED_FORM_MESSAGE;
 
     Java_AutofillPopupBridge_addToAutofillSuggestionArray(
-        env, data_array, i, base::android::ConvertUTF16ToJavaString(env, label),
+        env, java_object_, data_array, i,
+        base::android::ConvertUTF16ToJavaString(env, label),
         base::android::ConvertUTF16ToJavaString(env, secondary_label),
         base::android::ConvertUTF16ToJavaString(env, sublabel),
         base::android::ConvertUTF16ToJavaString(env, secondary_sublabel),
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 5c01d8b..621c04c 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -976,7 +976,8 @@
                 Math.max(Math.max(mNtpSearchBoxScrollFraction, mStartSurfaceScrollFraction),
                         mUrlFocusChangeFraction);
         for (UrlExpansionObserver observer : mUrlExpansionObservers) {
-            observer.onUrlExpansionProgressChanged(mUrlExpansionFraction);
+            observer.onUrlExpansionProgressChanged(
+                    mUrlExpansionFraction, mUrlFocusChangeInProgress);
         }
         assert mUrlExpansionFraction >= 0;
         assert mUrlExpansionFraction <= 1;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 41e1558c..13e59de 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -67,8 +67,10 @@
          * @param fraction The toolbar expansion progress. 0 indicates that the URL bar is not
          *                   expanded. 1 indicates that the URL bar is expanded to the maximum
          *                   width.
+         *
+         * @param changeInProgress Whether the toolbar animation is still in progress or not.
          */
-        void onUrlExpansionProgressChanged(float fraction);
+        void onUrlExpansionProgressChanged(float fraction, boolean changeInProgress);
     }
 
     /**
diff --git a/chrome/browser/ui/app_list/search/chrome_search_result.h b/chrome/browser/ui/app_list/search/chrome_search_result.h
index c32f661..e524026 100644
--- a/chrome/browser/ui/app_list/search/chrome_search_result.h
+++ b/chrome/browser/ui/app_list/search/chrome_search_result.h
@@ -220,7 +220,7 @@
   // obtained from. These can include scores from intermediate ranking steps, as
   // well as prototype scores to be inspected for experimentation.
   //
-  // TODO(crbug.com/1199206): Move this to a map<string, string> of debug info
+  // TODO(crbug.com/1292783): Move this to a map<string, string> of debug info
   // that contains more than just scores, and display the contents of
   // |scoring_| in chrome://launcher-internals
   base::flat_map<std::string, double> ranker_scores_;
diff --git a/chrome/browser/ui/app_list/search/common/url_icon_source.cc b/chrome/browser/ui/app_list/search/common/url_icon_source.cc
deleted file mode 100644
index 19b6a4e..0000000
--- a/chrome/browser/ui/app_list/search/common/url_icon_source.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
-
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/load_flags.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/image/image_skia_rep.h"
-
-using content::BrowserThread;
-
-namespace app_list {
-
-UrlIconSource::UrlIconSource(IconLoadedCallback icon_loaded_callback,
-                             content::BrowserContext* browser_context,
-                             const GURL& icon_url,
-                             int icon_size,
-                             int default_icon_resource_id)
-    : icon_loaded_callback_(std::move(icon_loaded_callback)),
-      browser_context_(browser_context),
-      icon_url_(icon_url),
-      icon_size_(icon_size),
-      default_icon_resource_id_(default_icon_resource_id),
-      icon_fetch_attempted_(false) {
-  DCHECK(!icon_loaded_callback_.is_null());
-}
-
-UrlIconSource::~UrlIconSource() {
-}
-
-void UrlIconSource::StartIconFetch() {
-  icon_fetch_attempted_ = true;
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = icon_url_;
-  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("url_icon_source_fetch", R"(
-          semantics {
-            sender: "URL Icon Source"
-            description:
-              "Chrome OS downloads an app icon for display in the app list."
-            trigger:
-              "An icon/image needs to be downloaded to be displayed."
-            data:
-              "URL of the icon/image. "
-              "No user information is sent."
-            destination: WEBSITE
-          }
-          policy {
-            cookies_allowed: NO
-            setting: "Unconditionally enabled on Chrome OS."
-            policy_exception_justification:
-              "Not implemented, considered not useful."
-          })");
-  simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
-                                                    traffic_annotation);
-  network::mojom::URLLoaderFactory* loader_factory =
-      browser_context_->GetDefaultStoragePartition()
-          ->GetURLLoaderFactoryForBrowserProcess()
-          .get();
-  simple_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-      loader_factory, base::BindOnce(&UrlIconSource::OnSimpleLoaderComplete,
-                                     base::Unretained(this)));
-}
-
-gfx::ImageSkiaRep UrlIconSource::GetImageForScale(float scale) {
-  if (!icon_fetch_attempted_)
-    StartIconFetch();
-
-  if (!icon_.isNull())
-    return icon_.GetRepresentation(scale);
-
-  return ui::ResourceBundle::GetSharedInstance()
-      .GetImageSkiaNamed(default_icon_resource_id_)->GetRepresentation(scale);
-}
-
-void UrlIconSource::OnSimpleLoaderComplete(
-    std::unique_ptr<std::string> response_body) {
-  if (!response_body) {
-    return;
-  }
-
-  // Call start to begin decoding.  The ImageDecoder will call OnImageDecoded
-  // with the data when it is done.
-  ImageDecoder::Start(this, std::move(*response_body));
-}
-
-void UrlIconSource::OnImageDecoded(const SkBitmap& decoded_image) {
-  const float scale = decoded_image.width() / icon_size_;
-  icon_ = gfx::ImageSkia::CreateFromBitmap(decoded_image, scale);
-  DCHECK(!icon_loaded_callback_.is_null());
-  std::move(icon_loaded_callback_).Run();
-}
-
-void UrlIconSource::OnDecodeImageFailed() {
-  // Failed to decode image. Do nothing and just use the default icon.
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/common/url_icon_source.h b/chrome/browser/ui/app_list/search/common/url_icon_source.h
deleted file mode 100644
index 65505d4..0000000
--- a/chrome/browser/ui/app_list/search/common/url_icon_source.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2013 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_APP_LIST_SEARCH_COMMON_URL_ICON_SOURCE_H_
-#define CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_URL_ICON_SOURCE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "chrome/browser/image_decoder/image_decoder.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_source.h"
-#include "url/gurl.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace network {
-class SimpleURLLoader;
-}
-
-namespace app_list {
-
-// An ImageSkiaSource for icons fetched from a URL. Till the URL icon is
-// fetched, the default icon (specified by it's resource id) is shown.
-class UrlIconSource : public gfx::ImageSkiaSource,
-                      public ImageDecoder::ImageRequest {
- public:
-  typedef base::OnceClosure IconLoadedCallback;
-
-  // Create a URL Icon source with the given URL. The post_process parameter
-  // specifies a function to post-process the result icon before displaying it.
-  UrlIconSource(IconLoadedCallback icon_loaded_callback,
-                content::BrowserContext* browser_context,
-                const GURL& icon_url,
-                int icon_size,
-                int default_icon_resource_id);
-
-  UrlIconSource(const UrlIconSource&) = delete;
-  UrlIconSource& operator=(const UrlIconSource&) = delete;
-
-  ~UrlIconSource() override;
-
- private:
-  // Invoked from GetImageForScale to download the app icon when the hosting
-  // ImageSkia gets painted on screen.
-  void StartIconFetch();
-
-  // Invoked from SimpleURLLoader after download is complete.
-  void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
-
-  // gfx::ImageSkiaSource overrides:
-  gfx::ImageSkiaRep GetImageForScale(float scale) override;
-
-  // ImageDecoder::ImageRequest overrides:
-  void OnImageDecoded(const SkBitmap& decoded_image) override;
-  void OnDecodeImageFailed() override;
-
-  IconLoadedCallback icon_loaded_callback_;
-  content::BrowserContext* browser_context_;
-  const GURL icon_url_;
-  const int icon_size_;
-  const int default_icon_resource_id_;
-
-  bool icon_fetch_attempted_;
-  std::unique_ptr<network::SimpleURLLoader> simple_loader_;
-
-  gfx::ImageSkia icon_;
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_COMMON_URL_ICON_SOURCE_H_
diff --git a/chrome/browser/ui/app_list/search/ranking/launch_data.h b/chrome/browser/ui/app_list/search/ranking/launch_data.h
index 9bd7424..b6af55cd 100644
--- a/chrome/browser/ui/app_list/search/ranking/launch_data.h
+++ b/chrome/browser/ui/app_list/search/ranking/launch_data.h
@@ -24,7 +24,7 @@
   ash::AppListSearchResultType result_type =
       ash::AppListSearchResultType::kUnknown;
   // The type of the result used for ranking.
-  // TODO(crbug.com/1199206): This is no longer needed and can be removed when
+  // TODO(crbug.com/1378861): This is no longer needed and can be removed when
   // the search_result_ranker/ directory is removed.
   RankingItemType ranking_item_type = RankingItemType::kUnknown;
   ash::AppListLaunchedFrom launched_from =
diff --git a/chrome/browser/ui/app_list/search/ranking/ranker_manager.cc b/chrome/browser/ui/app_list/search/ranking/ranker_manager.cc
index f4d0f0e1..5a17ac29 100644
--- a/chrome/browser/ui/app_list/search/ranking/ranker_manager.cc
+++ b/chrome/browser/ui/app_list/search/ranking/ranker_manager.cc
@@ -39,7 +39,6 @@
   score_normalizer_params.max_bins = 5;
 
   // Result ranking parameters.
-  // TODO(crbug.com/1199206): These need tweaking.
   FtrlOptimizer::Params ftrl_result_params;
   ftrl_result_params.alpha = 0.1;
   ftrl_result_params.gamma = 0.1;
@@ -51,7 +50,6 @@
   mrfu_result_params.max_items = 200u;
 
   // Category ranking parameters.
-  // TODO(crbug.com/1199206): These need tweaking.
   FtrlOptimizer::Params ftrl_category_params;
   ftrl_category_params.alpha = 0.1;
   ftrl_category_params.gamma = 0.1;
diff --git a/chrome/browser/ui/app_list/search/ranking/util.h b/chrome/browser/ui/app_list/search/ranking/util.h
index 97da8ebd..d9c626e 100644
--- a/chrome/browser/ui/app_list/search/ranking/util.h
+++ b/chrome/browser/ui/app_list/search/ranking/util.h
@@ -22,7 +22,7 @@
 
 Category StringToCategory(const std::string& value);
 
-// TODO(crbug.com/1199206): This can be removed once LaunchData contains the
+// TODO(crbug.com/1378862): This can be removed once LaunchData contains the
 // result category.
 //
 // This is slightly inconsistent with the true result->category mapping, because
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl.cc b/chrome/browser/ui/app_list/search/search_controller_impl.cc
index 8df8c361..df70ee1 100644
--- a/chrome/browser/ui/app_list/search/search_controller_impl.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_impl.cc
@@ -316,7 +316,7 @@
   std::vector<ChromeSearchResult*> all_results;
   for (const auto& type_results : results_) {
     for (const auto& result : type_results.second) {
-      // TODO(crbug.com/1199206): Category-based search combines apps into the
+      // TODO(crbug.com/1385194): Category-based search combines apps into the
       // results list, so redirect any kTile results to kList before updating
       // the UI. Once SearchControllerImpl is the only search controller,
       // this can be removed and all results can be created as kList.
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 6048fa0..cb56154 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -44,6 +44,7 @@
 #include "chrome/common/url_constants.h"
 #include "components/captive_portal/core/buildflags.h"
 #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_url_handler.h"
 #include "content/public/browser/navigation_entry.h"
@@ -913,7 +914,7 @@
          host != chrome::kChromeUIHistoryHost &&
          host != chrome::kChromeUIExtensionsHost &&
          host != chrome::kChromeUIBookmarksHost &&
-         host != chrome::kChromeUIPasswordManagerHost;
+         host != password_manager::kChromeUIPasswordManagerHost;
 }
 
 bool IsURLAllowedInIncognito(const GURL& url,
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
index 068a555..a382dcb 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
@@ -126,6 +126,10 @@
       const zoom::ZoomController::ZoomChangedEventData& data) override;
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if defined(UNIT_TEST)
+  PasswordGenerationPopupView* view() const { return view_; }
+#endif
+
  protected:
   PasswordGenerationPopupControllerImpl(
       const gfx::RectF& bounds,
@@ -135,9 +139,6 @@
       content::WebContents* web_contents,
       content::RenderFrameHost* frame);
 
-  // Handle to the popup. May be NULL if popup isn't showing.
-  raw_ptr<PasswordGenerationPopupView> view_;
-
  private:
   class KeyPressRegistrator;
   // PasswordGenerationPopupController implementation:
@@ -171,6 +172,9 @@
   // Accept password if it's selected.
   bool PossiblyAcceptPassword();
 
+  // Handle to the popup. May be NULL if popup isn't showing.
+  raw_ptr<PasswordGenerationPopupView> view_;
+
   const autofill::FormData form_data_;
 
   base::WeakPtr<password_manager::PasswordManagerDriver> const driver_;
diff --git a/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc b/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc
index 38c00008..051cb79 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc
+++ b/chrome/browser/ui/passwords/password_generation_popup_view_browsertest.cc
@@ -6,117 +6,116 @@
 
 #include <string>
 
-#include "base/memory/raw_ptr.h"
-#include "build/build_config.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller_impl.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_view_tester.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/autofill/core/common/unique_ids.h"
 #include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event_utils.h"
 
 namespace autofill {
 
-class TestPasswordGenerationPopupController
-    : public PasswordGenerationPopupControllerImpl {
- public:
-  // |vertical_offset| specifies the vertical offset of the popup relative to
-  // the web contents container.
-  explicit TestPasswordGenerationPopupController(
-      content::WebContents* web_contents,
-      int vertical_offset = 0)
-      : PasswordGenerationPopupControllerImpl(
-            gfx::RectF(web_contents->GetContainerBounds().x(),
-                       web_contents->GetContainerBounds().y() + vertical_offset,
-                       10,
-                       10),
-            autofill::password_generation::PasswordGenerationUIData(
-                /*bounds=*/gfx::RectF(web_contents->GetContainerBounds().x(),
-                                      web_contents->GetContainerBounds().y(),
-                                      10,
-                                      10),
-                /*max_length=*/10,
-                /*generation_element=*/std::u16string(),
-                /*user_typed_password=*/std::u16string(),
-                autofill::FieldRendererId(100),
-                /*is_generation_element_password_type=*/true,
-                /*text_direction=*/base::i18n::TextDirection(),
-                FormData()),
-            password_manager::ContentPasswordManagerDriverFactory::
-                FromWebContents(web_contents)
-                    ->GetDriverForFrame(web_contents->GetPrimaryMainFrame())
-                    ->AsWeakPtr(),
-            nullptr /* PasswordGenerationPopupObserver*/,
-            web_contents,
-            web_contents->GetPrimaryMainFrame()) {}
-
-  ~TestPasswordGenerationPopupController() override {}
-
-  PasswordGenerationPopupView* view() { return view_; }
-};
-
-class PasswordGenerationPopupViewTest : public InProcessBrowserTest {
- public:
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  std::unique_ptr<PasswordGenerationPopupViewTester> GetViewTester() {
-    return PasswordGenerationPopupViewTester::For(controller_->view());
-  }
-
- protected:
-  raw_ptr<TestPasswordGenerationPopupController, DanglingUntriaged> controller_;
-};
+class PasswordGenerationPopupViewTest : public InProcessBrowserTest {};
 
 // Regression test for crbug.com/400543. Verifying that moving the mouse in the
 // editing dialog doesn't crash.
 IN_PROC_BROWSER_TEST_F(PasswordGenerationPopupViewTest,
                        MouseMovementInEditingPopup) {
-  controller_ =
-      new autofill::TestPasswordGenerationPopupController(GetWebContents());
-  controller_->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
-  EXPECT_TRUE(controller_->IsVisible());
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  password_generation::PasswordGenerationUIData ui_data(
+      gfx::RectF(web_contents->GetContainerBounds().x(),
+                 web_contents->GetContainerBounds().y(), 10, 10),
+      /*max_length=*/10,
+      /*generation_element=*/std::u16string(),
+      /*user_typed_password=*/std::u16string(), FieldRendererId(100),
+      /*is_generation_element_password_type=*/true, base::i18n::TextDirection(),
+      FormData());
 
-  GetViewTester()->SimulateMouseMovementAt(
-      gfx::Point(GetWebContents()->GetContainerBounds().x() + 1,
-                 GetWebContents()->GetContainerBounds().y() + 1));
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data.bounds, ui_data,
+          password_manager::ContentPasswordManagerDriverFactory::
+              FromWebContents(web_contents)
+                  ->GetDriverForFrame(web_contents->GetPrimaryMainFrame())
+                  ->AsWeakPtr(),
+          /*observer=*/nullptr, web_contents,
+          web_contents->GetPrimaryMainFrame());
+
+  controller->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
+  EXPECT_TRUE(controller->IsVisible());
+
+  PasswordGenerationPopupViewTester::For(controller->view())
+      ->SimulateMouseMovementAt(
+          gfx::Point(web_contents->GetContainerBounds().x() + 1,
+                     web_contents->GetContainerBounds().y() + 1));
 
   // This hides the popup and destroys the controller.
-  GetWebContents()->Close();
+  web_contents->Close();
 }
 
 // Verify that destroying web contents with visible popup does not crash.
 IN_PROC_BROWSER_TEST_F(PasswordGenerationPopupViewTest,
                        CloseWebContentsWithVisiblePopup) {
-  controller_ =
-      new autofill::TestPasswordGenerationPopupController(GetWebContents());
-  controller_->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
-  EXPECT_TRUE(controller_->IsVisible());
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  password_generation::PasswordGenerationUIData ui_data(
+      gfx::RectF(web_contents->GetContainerBounds().x(),
+                 web_contents->GetContainerBounds().y(), 10, 10),
+      /*max_length=*/10,
+      /*generation_element=*/std::u16string(),
+      /*user_typed_password=*/std::u16string(), FieldRendererId(100),
+      /*is_generation_element_password_type=*/true, base::i18n::TextDirection(),
+      FormData());
 
-  GetWebContents()->Close();
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data.bounds, ui_data,
+          password_manager::ContentPasswordManagerDriverFactory::
+              FromWebContents(web_contents)
+                  ->GetDriverForFrame(web_contents->GetPrimaryMainFrame())
+                  ->AsWeakPtr(),
+          /*observer=*/nullptr, web_contents,
+          web_contents->GetPrimaryMainFrame());
+
+  controller->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
+  EXPECT_TRUE(controller->IsVisible());
+
+  web_contents->Close();
 }
 
 // Verify that controller is not crashed in case of insufficient vertical space
 // for showing popup.
 IN_PROC_BROWSER_TEST_F(PasswordGenerationPopupViewTest,
-                       DoNotCrashInCaseOfInsuffucientVertialSpace) {
-  // TODO(crbug.com/1365893): Remove TestPasswordGenerationPopupController class
-  // so that only GetOrCreate() would be used and then GetWeakPtr() won't be
-  // needed.
-  controller_ = new autofill::TestPasswordGenerationPopupController(
-      GetWebContents(), /*vertical_offset=*/-20);
-  base::WeakPtr<PasswordGenerationPopupControllerImpl> weak_controller =
-      controller_->GetWeakPtr();
-  controller_->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
-  // Check that the object |controller_| points to was invalidated.
-  EXPECT_FALSE(weak_controller);
+                       DoNotCrashInCaseOfInsuffucientVerticalSpace) {
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  password_generation::PasswordGenerationUIData ui_data(
+      gfx::RectF(web_contents->GetContainerBounds().x(),
+                 web_contents->GetContainerBounds().y() - 20, 10, 10),
+      /*max_length=*/10,
+      /*generation_element=*/std::u16string(),
+      /*user_typed_password=*/std::u16string(), FieldRendererId(100),
+      /*is_generation_element_password_type=*/true, base::i18n::TextDirection(),
+      FormData());
+
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data.bounds, ui_data,
+          password_manager::ContentPasswordManagerDriverFactory::
+              FromWebContents(web_contents)
+                  ->GetDriverForFrame(web_contents->GetPrimaryMainFrame())
+                  ->AsWeakPtr(),
+          /*observer=*/nullptr, web_contents,
+          web_contents->GetPrimaryMainFrame());
+
+  controller->Show(PasswordGenerationPopupController::kEditGeneratedPassword);
+  // Check that the object `controller` points to was invalidated.
+  EXPECT_FALSE(controller);
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
index b85239f5..3e27d38e 100644
--- a/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
+++ b/chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_start_reauth_ui.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ui/webui/ash/in_session_password_change/lock_screen_reauth_handler.h"
+#include "chrome/browser/ui/webui/ash/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -110,17 +111,19 @@
       "passwordChangedOldPasswordHint",
       l10n_util::GetStringUTF16(IDS_LOCK_PASSWORD_CHANGED_OLD_PASSWORD_HINT));
 
+  source->AddString(
+      "samlChangeProviderMessage",
+      l10n_util::GetStringUTF16(IDS_LOGIN_SAML_CHANGE_PROVIDER_MESSAGE));
+  source->AddString(
+      "samlChangeProviderButton",
+      l10n_util::GetStringUTF16(IDS_LOGIN_SAML_CHANGE_PROVIDER_BUTTON));
+
   source->AddResourcePaths(
       base::make_span(kPasswordChangeResources, kPasswordChangeResourcesSize));
   source->SetDefaultResource(IDR_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_APP_HTML);
 
-  // Add Gaia Authenticator resources
-  source->AddResourcePaths(
-      base::make_span(kGaiaAuthHostResources, kGaiaAuthHostResourcesSize));
-
-  // Add OOBE resources
-  source->AddResourcePaths(base::make_span(kOobeUnconditionalResources,
-                                           kOobeUnconditionalResourcesSize));
+  // Add OOBE and Gaia Authenticator resources
+  OobeUI::AddOobeComponents(source);
 
   content::WebUIDataSource::Add(profile, source);
 }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 8e58900..bfc2ebe 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -84,6 +84,7 @@
 #include "components/history_clusters/history_clusters_internals/webui/url_constants.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/optimization_guide/optimization_guide_internals/webui/url_constants.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/features/reading_list_switches.h"
 #include "components/safe_browsing/buildflags.h"
@@ -861,7 +862,7 @@
        url.host_piece() == chrome::kChromeUIExtensionsHost ||
        url.host_piece() == chrome::kChromeUINewTabPageHost ||
        url.host_piece() == chrome::kChromeUINewTabPageThirdPartyHost ||
-       url.host_piece() == chrome::kChromeUIPasswordManagerHost)) {
+       url.host_piece() == password_manager::kChromeUIPasswordManagerHost)) {
     return &NewWebUI<PageNotAvailableForGuestUI>;
   }
   if (url.host_piece() == chrome::kChromeUIAppServiceInternalsHost)
@@ -869,7 +870,7 @@
   // Bookmarks are part of NTP on Android.
   if (url.host_piece() == chrome::kChromeUIBookmarksHost)
     return &NewWebUI<BookmarksUI>;
-  if (url.host_piece() == chrome::kChromeUIPasswordManagerHost &&
+  if (url.host_piece() == password_manager::kChromeUIPasswordManagerHost &&
       base::FeatureList::IsEnabled(
           password_manager::features::kPasswordManagerRedesign))
     return &NewWebUI<PasswordManagerUI>;
@@ -1396,7 +1397,7 @@
   if (page_url.host_piece() == chrome::kChromeUIHistoryHost)
     return HistoryUI::GetFaviconResourceBytes(scale_factor);
 
-  if (page_url.host_piece() == chrome::kChromeUIPasswordManagerHost)
+  if (page_url.host_piece() == password_manager::kChromeUIPasswordManagerHost)
     return PasswordManagerUI::GetFaviconResourceBytes(scale_factor);
 
   // Android uses the native download manager.
diff --git a/chrome/browser/ui/webui/page_not_available_for_guest/page_not_available_for_guest_ui.cc b/chrome/browser/ui/webui/page_not_available_for_guest/page_not_available_for_guest_ui.cc
index 33758bae..e26af95 100644
--- a/chrome/browser/ui/webui/page_not_available_for_guest/page_not_available_for_guest_ui.cc
+++ b/chrome/browser/ui/webui/page_not_available_for_guest/page_not_available_for_guest_ui.cc
@@ -9,6 +9,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -28,7 +29,7 @@
     page_title = l10n_util::GetStringUTF16(IDS_HISTORY_TITLE);
   else if (host_name == chrome::kChromeUIExtensionsHost)
     page_title = l10n_util::GetStringUTF16(IDS_EXTENSIONS_TOOLBAR_TITLE);
-  else if (host_name == chrome::kChromeUIPasswordManagerHost)
+  else if (host_name == password_manager::kChromeUIPasswordManagerHost)
     page_title = l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UI_TITLE);
   else
     page_title = base::UTF8ToUTF16(host_name);
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 70f2ca0..f65c71b 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -15,6 +15,7 @@
 #include "chrome/grit/password_manager_resources.h"
 #include "chrome/grit/password_manager_resources_map.h"
 #include "components/grit/components_scaled_resources.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -23,8 +24,8 @@
 namespace {
 
 content::WebUIDataSource* CreatePasswordsUIHTMLSource(Profile* profile) {
-  content::WebUIDataSource* source =
-      content::WebUIDataSource::Create(chrome::kChromeUIPasswordManagerHost);
+  content::WebUIDataSource* source = content::WebUIDataSource::Create(
+      password_manager::kChromeUIPasswordManagerHost);
 
   webui::SetupWebUIDataSource(
       source,
diff --git a/chrome/browser/ui/webui/support_tool/support_tool_ui.cc b/chrome/browser/ui/webui/support_tool/support_tool_ui.cc
index e33790a..baf1899 100644
--- a/chrome/browser/ui/webui/support_tool/support_tool_ui.cc
+++ b/chrome/browser/ui/webui/support_tool/support_tool_ui.cc
@@ -212,7 +212,7 @@
   AllowJavascript();
   CHECK_EQ(1U, args.size());
   const base::Value& callback_id = args[0];
-  ResolveJavascriptCallback(callback_id, GetAllDataCollectors());
+  ResolveJavascriptCallback(callback_id, GetAllDataCollectorItems());
 }
 
 // Starts data collection with the issue details and selected set of data
diff --git a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.cc b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.cc
index c54c4e6b..ec1ffe5 100644
--- a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.cc
+++ b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.cc
@@ -303,51 +303,25 @@
   base::Value::List data_collector_list;
   support_tool::DataCollectionModule module;
   InitDataCollectionModuleFromURLQuery(&module, module_query);
-  for (const auto& type : kDataCollectors) {
+  for (const auto& type : GetAllAvailableDataCollectorsOnDevice()) {
     data_collector_list.Append(GetDataCollectorItemForType(module, type));
   }
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  for (const auto& type : kDataCollectorsChromeosAsh) {
-    data_collector_list.Append(GetDataCollectorItemForType(module, type));
-  }
-#if BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
-  for (const auto& type : kDataCollectorsChromeosHwDetails) {
-    data_collector_list.Append(GetDataCollectorItemForType(module, type));
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   return data_collector_list;
 }
 
-base::Value::List GetAllDataCollectors() {
+base::Value::List GetAllDataCollectorItems() {
   base::Value::List data_collector_list;
-  for (const auto& type : kDataCollectors) {
-    data_collector_list.Append(GetDataCollectorItemForType(type));
-  }
-  for (const auto& type : kDataCollectorsChromeosAsh) {
-    data_collector_list.Append(GetDataCollectorItemForType(type));
-  }
-  for (const auto& type : kDataCollectorsChromeosHwDetails) {
+  for (const auto& type : GetAllDataCollectors()) {
     data_collector_list.Append(GetDataCollectorItemForType(type));
   }
   return data_collector_list;
 }
 
-base::Value::List GetAllDataCollectorsForDevice() {
+base::Value::List GetAllDataCollectorItemsForDeviceForTesting() {
   base::Value::List data_collector_list;
-  for (const auto& type : kDataCollectors) {
+  for (const auto& type : GetAllAvailableDataCollectorsOnDevice()) {
     data_collector_list.Append(GetDataCollectorItemForType(type));
   }
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  for (const auto& type : kDataCollectorsChromeosAsh) {
-    data_collector_list.Append(GetDataCollectorItemForType(type));
-  }
-#if BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
-  for (const auto& type : kDataCollectorsChromeosHwDetails) {
-    data_collector_list.Append(GetDataCollectorItemForType(type));
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_WITH_HW_DETAILS)
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   return data_collector_list;
 }
 
diff --git a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.h b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.h
index 77582d2..a797b74 100644
--- a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.h
+++ b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils.h
@@ -85,6 +85,7 @@
 //  protoEnum: number,
 // }
 // Returns only the data collectors that are available for user's device.
+// Sets `isIncluded` as false for all items if `module_query` is empty.
 base::Value::List GetDataCollectorItemsInQuery(std::string module_query);
 
 // Creates base::Value::List according to the format Support Tool UI
@@ -96,13 +97,13 @@
 //  isIncluded: boolean,
 //  protoEnum: number,
 // }
-base::Value::List GetAllDataCollectors();
+base::Value::List GetAllDataCollectorItems();
 
 // Creates base::Value::List according to the format Support Tool UI
 // accepts and fills the contents with all data collectors with isIncluded:
 // false as a default choice. Only return data collectors available for caller's
 // platform.
-base::Value::List GetAllDataCollectorsForDevice();
+base::Value::List GetAllDataCollectorItemsForDeviceForTesting();
 
 std::set<support_tool::DataCollectorType> GetIncludedDataCollectorTypes(
     const base::Value::List* data_collector_items);
diff --git a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils_unittest.cc b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils_unittest.cc
index f32fbb33..98246f1 100644
--- a/chrome/browser/ui/webui/support_tool/support_tool_ui_utils_unittest.cc
+++ b/chrome/browser/ui/webui/support_tool/support_tool_ui_utils_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/support_tool/support_tool_ui_utils.h"
 
+#include <memory>
 #include <set>
 #include <string>
 
@@ -14,12 +15,17 @@
 #include "chrome/browser/support_tool/data_collection_module.pb.h"
 #include "chrome/browser/support_tool/data_collector.h"
 #include "components/feedback/pii_types.h"
+#include "content/public/test/browser_task_environment.h"
 #include "net/base/url_util.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/crosapi/fake_browser_manager.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 using ::testing::ContainerEq;
 using ::testing::IsEmpty;
 using ::testing::Not;
@@ -56,9 +62,14 @@
 
 class SupportToolUiUtilsTest : public ::testing::Test {
  public:
-  SupportToolUiUtilsTest() = default;
+  SupportToolUiUtilsTest()
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+      : browser_manager_(std::make_unique<crosapi::FakeBrowserManager>()){}
+#else
+      = default;
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-  SupportToolUiUtilsTest(const SupportToolUiUtilsTest&) = delete;
+        SupportToolUiUtilsTest(const SupportToolUiUtilsTest&) = delete;
   SupportToolUiUtilsTest& operator=(const SupportToolUiUtilsTest&) = delete;
 
   // Change included field of `included_data_collectors` in `data_collectors` as
@@ -78,6 +89,12 @@
         data_collector_item.Set(support_tool_ui::kDataCollectorIncluded, true);
     }
   }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  std::unique_ptr<crosapi::FakeBrowserManager> browser_manager_;
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 };
 
 TEST_F(SupportToolUiUtilsTest, PiiItems) {
@@ -120,7 +137,8 @@
 TEST_F(SupportToolUiUtilsTest, CustomizedUrl) {
   const std::string test_case_id = "test_case_id_0";
   // Get list of all data collectors.
-  base::Value::List expected_data_collectors = GetAllDataCollectorsForDevice();
+  base::Value::List expected_data_collectors =
+      GetAllDataCollectorItemsForDeviceForTesting();
   std::set<support_tool::DataCollectorType> included_data_collectors = {
       support_tool::DataCollectorType::CHROME_INTERNAL,
       support_tool::DataCollectorType::CRASH_IDS};
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 3dc8d0e..603741f 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -339,6 +339,7 @@
     "//components/device_event_log",
     "//components/keep_alive_registry:keep_alive_registry",
     "//components/keyed_service/content",
+    "//components/password_manager/content/common",
     "//components/performance_manager",
     "//components/permissions:permissions",
     "//components/pref_registry",
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
index 63fe5ca..ce70f42 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -174,29 +175,40 @@
   DCHECK(cache_entry_it != reader_cache_.End());
   DCHECK_EQ(cache_entry_it->second.state, Cache::Entry::State::kPending);
 
-  absl::optional<ReadResponseError> error;
+  absl::optional<
+      std::pair<ReadResponseError, ReadIntegrityBlockAndMetadataStatus>>
+      error_and_status;
   if (read_integrity_block_and_metadata_error.has_value()) {
-    error =
-        ReadResponseError::ForError(*read_integrity_block_and_metadata_error);
+    error_and_status = std::make_pair(
+        ReadResponseError::ForError(*read_integrity_block_and_metadata_error),
+        GetStatusFromError(*read_integrity_block_and_metadata_error));
   }
 
   SignedWebBundleReader& reader = cache_entry_it->second.GetReader();
 
-  if (!error.has_value()) {
+  if (!error_and_status.has_value()) {
     if (auto error_message = validator_->ValidateMetadata(
             web_bundle_id, reader.GetPrimaryURL(), reader.GetEntries());
         error_message.has_value()) {
-      error = ReadResponseError::ForMetadataValidationError(*error_message);
+      error_and_status = std::make_pair(
+          ReadResponseError::ForMetadataValidationError(*error_message),
+          ReadIntegrityBlockAndMetadataStatus::kMetadataValidationError);
     }
   }
 
+  base::UmaHistogramEnumeration(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      error_and_status.has_value()
+          ? error_and_status->second
+          : ReadIntegrityBlockAndMetadataStatus::kSuccess);
+
   std::vector<std::pair<network::ResourceRequest, ReadResponseCallback>>
       pending_requests =
           std::exchange(cache_entry_it->second.pending_requests, {});
 
-  if (error.has_value()) {
+  if (error_and_status.has_value()) {
     for (auto& [resource_request, callback] : pending_requests) {
-      std::move(callback).Run(base::unexpected(*error));
+      std::move(callback).Run(base::unexpected(error_and_status->first));
     }
     reader_cache_.Erase(cache_entry_it);
     return;
@@ -260,6 +272,52 @@
   std::move(callback).Run(Response(std::move(*response_head), reader));
 }
 
+IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus
+IsolatedWebAppReaderRegistry::GetStatusFromError(
+    const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error) {
+  return absl::visit(
+      base::Overloaded{
+          [](const web_package::mojom::BundleIntegrityBlockParseErrorPtr&
+                 error) {
+            switch (error->type) {
+              case web_package::mojom::BundleParseErrorType::
+                  kParserInternalError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kIntegrityBlockParserInternalError;
+              case web_package::mojom::BundleParseErrorType::kFormatError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kIntegrityBlockParserFormatError;
+              case web_package::mojom::BundleParseErrorType::kVersionError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kIntegrityBlockParserVersionError;
+            }
+          },
+          [](const SignedWebBundleReader::AbortedByCaller& error) {
+            return ReadIntegrityBlockAndMetadataStatus::
+                kIntegrityBlockValidationError;
+          },
+          [](const web_package::SignedWebBundleSignatureVerifier::Error&
+                 error) {
+            return ReadIntegrityBlockAndMetadataStatus::
+                kSignatureVerificationError;
+          },
+          [](const web_package::mojom::BundleMetadataParseErrorPtr& error) {
+            switch (error->type) {
+              case web_package::mojom::BundleParseErrorType::
+                  kParserInternalError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kMetadataParserInternalError;
+              case web_package::mojom::BundleParseErrorType::kFormatError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kMetadataParserFormatError;
+              case web_package::mojom::BundleParseErrorType::kVersionError:
+                return ReadIntegrityBlockAndMetadataStatus::
+                    kMetadataParserVersionError;
+            }
+          }},
+      error);
+}
+
 IsolatedWebAppReaderRegistry::Response::Response(
     web_package::mojom::BundleResponsePtr head,
     base::WeakPtr<SignedWebBundleReader> reader)
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
index aba69d5c..7382770d 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
@@ -127,6 +127,31 @@
                     const network::ResourceRequest& resource_request,
                     ReadResponseCallback callback);
 
+  // This enum represents every error type that can occur during integrity block
+  // and metadata parsing, before responses are read from Signed Web Bundles.
+  //
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class ReadIntegrityBlockAndMetadataStatus {
+    kSuccess = 0,
+    // Integrity Block-related errors
+    kIntegrityBlockParserInternalError = 1,
+    kIntegrityBlockParserFormatError = 2,
+    kIntegrityBlockParserVersionError = 3,
+    kIntegrityBlockValidationError = 4,
+
+    // Signature verification errors
+    kSignatureVerificationError = 5,
+
+    // Metadata-related errors
+    kMetadataParserInternalError = 6,
+    kMetadataParserFormatError = 7,
+    kMetadataParserVersionError = 8,
+    kMetadataValidationError = 9,
+
+    kMaxValue = kMetadataValidationError
+  };
+
  private:
   FRIEND_TEST_ALL_PREFIXES(IsolatedWebAppReaderRegistryTest,
                            TestConcurrentRequests);
@@ -162,6 +187,9 @@
       base::expected<web_package::mojom::BundleResponsePtr,
                      SignedWebBundleReader::ReadResponseError> response_head);
 
+  ReadIntegrityBlockAndMetadataStatus GetStatusFromError(
+      const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error);
+
   enum class ReaderCacheState;
 
   // A thin wrapper around `base::flat_map<base::FilePath, Cache::Entry>` that
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
index b67d2c1..390a5b1 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
@@ -199,6 +199,8 @@
                    IsolatedWebAppReaderRegistry::ReadResponseError>;
 
 TEST_F(IsolatedWebAppReaderRegistryTest, TestSingleRequest) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -214,6 +216,12 @@
   ASSERT_TRUE(result.has_value()) << result.error().message;
   EXPECT_EQ(result->head()->response_code, 200);
 
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+          kSuccess,
+      1);
+
   std::string response_body = ReadAndFulfillResponseBody(
       result->head()->payload_length,
       base::BindOnce(&IsolatedWebAppReaderRegistry::Response::ReadBody,
@@ -417,7 +425,17 @@
           "Pending Tasks have been logged.");
 }
 
-TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidIntegrityBlock) {
+class IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest
+    : public IsolatedWebAppReaderRegistryTest,
+      public ::testing::WithParamInterface<std::pair<
+          web_package::mojom::BundleParseErrorType,
+          IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus>> {
+};
+
+TEST_P(IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest,
+       TestIntegrityBlockParserError) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -426,6 +444,7 @@
                           read_response_future.GetCallback());
 
   auto error = web_package::mojom::BundleIntegrityBlockParseError::New();
+  error->type = GetParam().first;
   error->message = "test error";
   parser_factory_->RunIntegrityBlockCallback(nullptr, std::move(error));
 
@@ -435,9 +454,32 @@
             IsolatedWebAppReaderRegistry::ReadResponseError::Type::kOtherError);
   EXPECT_EQ(result.error().message,
             "Failed to parse integrity block: test error");
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second,
+      1);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest,
+    ::testing::Values(
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kParserInternalError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kIntegrityBlockParserInternalError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kVersionError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kIntegrityBlockParserVersionError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kFormatError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kIntegrityBlockParserFormatError)));
+
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidIntegrityBlockContents) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -461,6 +503,12 @@
             IsolatedWebAppReaderRegistry::ReadResponseError::Type::kOtherError);
   EXPECT_EQ(result.error().message,
             "Failed to validate integrity block: test error");
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+          kIntegrityBlockValidationError,
+      1);
 }
 
 class IsolatedWebAppReaderRegistrySignatureVerificationErrorTest
@@ -470,6 +518,8 @@
 
 TEST_P(IsolatedWebAppReaderRegistrySignatureVerificationErrorTest,
        SignatureVerificationError) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -497,6 +547,12 @@
 
   ReadResult result = read_response_future.Take();
   ASSERT_TRUE(result.has_value()) << result.error().message;
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+          kSuccess,
+      1);
 #else
   ReadResult result = read_response_future.Take();
   ASSERT_FALSE(result.has_value());
@@ -505,6 +561,12 @@
   EXPECT_EQ(result.error().message,
             base::StringPrintf("Failed to verify signatures: %s",
                                GetParam().message.c_str()));
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+          kSignatureVerificationError,
+      1);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
@@ -517,7 +579,17 @@
         web_package::SignedWebBundleSignatureVerifier::Error::
             ForInvalidSignature("invalid signature")));
 
-TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadata) {
+class IsolatedWebAppReaderRegistryMetadataParserErrorTest
+    : public IsolatedWebAppReaderRegistryTest,
+      public ::testing::WithParamInterface<std::pair<
+          web_package::mojom::BundleParseErrorType,
+          IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus>> {
+};
+
+TEST_P(IsolatedWebAppReaderRegistryMetadataParserErrorTest,
+       TestMetadataParserError) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -528,6 +600,7 @@
   FulfillIntegrityBlock();
   auto error = web_package::mojom::BundleMetadataParseError::New();
   error->message = "test error";
+  error->type = GetParam().first;
   parser_factory_->RunMetadataCallback(integrity_block_->size, nullptr,
                                        std::move(error));
 
@@ -536,9 +609,32 @@
   EXPECT_EQ(result.error().type,
             IsolatedWebAppReaderRegistry::ReadResponseError::Type::kOtherError);
   EXPECT_EQ(result.error().message, "Failed to parse metadata: test error");
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second,
+      1);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    IsolatedWebAppReaderRegistryMetadataParserErrorTest,
+    ::testing::Values(
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kParserInternalError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kMetadataParserInternalError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kVersionError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kMetadataParserVersionError),
+        std::make_pair(
+            web_package::mojom::BundleParseErrorType::kFormatError,
+            IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+                kMetadataParserFormatError)));
+
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadataPrimaryUrl) {
+  base::HistogramTester histogram_tester;
+
   network::ResourceRequest resource_request;
   resource_request.url = kPrimaryUrl;
 
@@ -561,6 +657,12 @@
       base::StringPrintf(
           "Failed to validate metadata: Primary URL must be %s, but was %s",
           kPrimaryUrl.spec().c_str(), kInvalidIsolatedWebAppUrl));
+
+  histogram_tester.ExpectBucketCount(
+      "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus",
+      IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus::
+          kMetadataValidationError,
+      1);
 }
 
 TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadataInvalidExchange) {
diff --git a/chrome/browser/web_applications/web_app_helpers.cc b/chrome/browser/web_applications/web_app_helpers.cc
index 99cd3ef..a33045ef 100644
--- a/chrome/browser/web_applications/web_app_helpers.cc
+++ b/chrome/browser/web_applications/web_app_helpers.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/crx_file/id_util.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/common/content_features.h"
 #include "crypto/sha2.h"
@@ -117,7 +118,7 @@
          app_url.SchemeIs(url::kHttpsScheme) ||
          app_url.SchemeIs("chrome-extension") ||
          (app_url.SchemeIs("chrome") &&
-          (app_url.host() == chrome::kChromeUIPasswordManagerHost));
+          (app_url.host() == password_manager::kChromeUIPasswordManagerHost));
 }
 
 absl::optional<AppId> FindInstalledAppWithUrlInScope(Profile* profile,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 08ba915..15f9596f 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1668729482-dae03be88903b96c0cb8dab14f08e8268d432145.profdata
+chrome-linux-main-1668751127-43c4df5d1c2afa5ec63f00c507bd21a7240573ca.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index f1088bc..ae029f92 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1668729482-a579f9d50b0e3f0452bcbffb10fd12ec4b4d4420.profdata
+chrome-mac-arm-main-1668751127-f9da020dd08da2388edd5cadb4c9c120716836bc.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index dd3cfcf..f2a69ec9 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1668729482-08450af1d482d5db59d38586aa4751ad5f2c5dba.profdata
+chrome-mac-main-1668772733-72afca7487af2915577e91fe5203389749726ad8.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 2e452a5..19291f6 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1668729482-cda98716d89013ed34a00bfc4c3d23cdb303195d.profdata
+chrome-win32-main-1668761948-da9a7feafa1dd554dd023fb485d20466cd1496a7.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index f15a826..76b40f82 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1668729482-f0dc1ff845c24bd6650354d4915408b19fd85051.profdata
+chrome-win64-main-1668751127-16a1797a5307905ae4e126f9c5ae8740d36d0520.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 5b683ab..e645c4b 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -263,6 +263,7 @@
     "//components/no_state_prefetch/common",
     "//components/no_state_prefetch/common:mojo_bindings",
     "//components/page_load_metrics/common:common",
+    "//components/password_manager/content/common",
   ]
 
   if (enable_pdf) {
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 81130b8..ea0da1a 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -36,6 +36,7 @@
   "+components/ntp_tiles",
   "+components/nux",
   "+components/offline_pages/buildflags",
+  "+components/password_manager/content/common",
   "+components/password_manager/core/common",
   "+components/pdf/common",
   "+components/policy/core/common",
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index f1984596..87d1d13 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -632,7 +632,8 @@
     "allowlist": [
       "63ED55E43214C211F82122ED56407FF1A807F2A3",  // Media Router Dev
       "226CF815E39A363090A1E547D53063472B8279FA",  // Media Router Stable
-      "1BFB3A47AA4A1E1C4714D919217602685CDD0FA7"   // http://crbug.com/574600
+      "1BFB3A47AA4A1E1C4714D919217602685CDD0FA7",  // http://crbug.com/574600
+      "DD87C93131FF8D3DE4E483DC1EB298D73C7223A6"   // http://crbug.com/1328114
     ]
   },
   {
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 70ba0aab..c1aa0c2a 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -11,6 +11,7 @@
 #include "components/history_clusters/history_clusters_internals/webui/url_constants.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/optimization_guide/optimization_guide_internals/webui/url_constants.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/safe_browsing/core/common/web_ui_constants.h"
 #include "extensions/buildflags/buildflags.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
@@ -156,7 +157,6 @@
 #endif
 const char kChromeUIPasswordManagerInternalsHost[] =
     "password-manager-internals";
-const char kChromeUIPasswordManagerHost[] = "password-manager";
 const char kChromeUIPerformanceSettingsURL[] = "chrome://settings/performance";
 const char kChromeUIPolicyHost[] = "policy";
 const char kChromeUIPolicyURL[] = "chrome://policy/";
@@ -680,7 +680,7 @@
     kChromeUIOmniboxHost,
     optimization_guide_internals::kChromeUIOptimizationGuideInternalsHost,
     kChromeUIPasswordManagerInternalsHost,
-    kChromeUIPasswordManagerHost,
+    password_manager::kChromeUIPasswordManagerHost,
     kChromeUIPolicyHost,
     kChromeUIPredictorsHost,
     kChromeUIPrefsInternalsHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 5e2a9d1..7bed16c 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -152,7 +152,6 @@
 extern const char kChromeUIOsUrlAppURL[];
 #endif
 extern const char kChromeUIPasswordManagerInternalsHost[];
-extern const char kChromeUIPasswordManagerHost[];
 extern const char kChromeUIPerformanceSettingsURL[];
 extern const char kChromeUIPolicyHost[];
 extern const char kChromeUIPolicyURL[];
diff --git a/chrome/services/file_util/BUILD.gn b/chrome/services/file_util/BUILD.gn
index 4708517..ecbb8e02 100644
--- a/chrome/services/file_util/BUILD.gn
+++ b/chrome/services/file_util/BUILD.gn
@@ -35,11 +35,11 @@
       "zip_file_creator.h",
     ]
 
-    deps += ["//components/services/filesystem/public/mojom"]
+    deps += [ "//components/services/filesystem/public/mojom" ]
   }
 
   if (is_mac) {
-    deps += ["//chrome/utility/safe_browsing/mac"]
+    deps += [ "//chrome/utility/safe_browsing/mac" ]
   }
 
   if (safe_browsing_mode == 1) {
@@ -71,8 +71,10 @@
     }
   }
 
-  if (enable_xz_extractor) {
+  if (enable_extractors) {
     sources += [
+      "single_file_tar_file_extractor.cc",
+      "single_file_tar_file_extractor.h",
       "single_file_tar_reader.cc",
       "single_file_tar_reader.h",
       "single_file_tar_xz_file_extractor.cc",
@@ -88,8 +90,12 @@
 source_set("unit_tests") {
   testonly = true
 
-  if (enable_xz_extractor) {
-    sources = [ "single_file_tar_xz_file_extractor_unittest.cc" ]
+  if (enable_extractors) {
+    sources = [
+      "single_file_tar_file_extractor_unittest.cc",
+      "single_file_tar_reader_unittest.cc",
+      "single_file_tar_xz_file_extractor_unittest.cc",
+    ]
 
     deps = [
       ":file_util",
@@ -104,7 +110,7 @@
 buildflag_header("buildflags") {
   header = "buildflags.h"
   flags = [
-    "ENABLE_XZ_EXTRACTOR=$enable_xz_extractor",
+    "ENABLE_EXTRACTORS=$enable_extractors",
     "ENABLE_MALDOCA=$enable_maldoca",
   ]
 }
diff --git a/chrome/services/file_util/file_util_service.cc b/chrome/services/file_util/file_util_service.cc
index 7de3f7e..303907181 100644
--- a/chrome/services/file_util/file_util_service.cc
+++ b/chrome/services/file_util/file_util_service.cc
@@ -22,7 +22,8 @@
 #include "chrome/services/file_util/zip_file_creator.h"
 #endif
 
-#if BUILDFLAG(ENABLE_XZ_EXTRACTOR)
+#if BUILDFLAG(ENABLE_EXTRACTORS)
+#include "chrome/services/file_util/single_file_tar_file_extractor.h"
 #include "chrome/services/file_util/single_file_tar_xz_file_extractor.h"
 #endif
 
@@ -47,10 +48,14 @@
 }
 #endif
 
-#if BUILDFLAG(ENABLE_XZ_EXTRACTOR)
+#if BUILDFLAG(ENABLE_EXTRACTORS)
+void FileUtilService::BindSingleFileTarFileExtractor(
+    mojo::PendingReceiver<chrome::mojom::SingleFileExtractor> receiver) {
+  mojo::MakeSelfOwnedReceiver(std::make_unique<SingleFileTarFileExtractor>(),
+                              std::move(receiver));
+}
 void FileUtilService::BindSingleFileTarXzFileExtractor(
-    mojo::PendingReceiver<chrome::mojom::SingleFileTarXzFileExtractor>
-        receiver) {
+    mojo::PendingReceiver<chrome::mojom::SingleFileExtractor> receiver) {
   mojo::MakeSelfOwnedReceiver(std::make_unique<SingleFileTarXzFileExtractor>(),
                               std::move(receiver));
 }
diff --git a/chrome/services/file_util/file_util_service.h b/chrome/services/file_util/file_util_service.h
index e1e8121e..0a7350f 100644
--- a/chrome/services/file_util/file_util_service.h
+++ b/chrome/services/file_util/file_util_service.h
@@ -36,10 +36,13 @@
       override;
 #endif
 
-#if BUILDFLAG(ENABLE_XZ_EXTRACTOR)
+#if BUILDFLAG(ENABLE_EXTRACTORS)
   void BindSingleFileTarXzFileExtractor(
-      mojo::PendingReceiver<chrome::mojom::SingleFileTarXzFileExtractor>
-          receiver) override;
+      mojo::PendingReceiver<chrome::mojom::SingleFileExtractor> receiver)
+      override;
+  void BindSingleFileTarFileExtractor(
+      mojo::PendingReceiver<chrome::mojom::SingleFileExtractor> receiver)
+      override;
 #endif
 
   mojo::Receiver<chrome::mojom::FileUtilService> receiver_;
diff --git a/chrome/services/file_util/public/features.gni b/chrome/services/file_util/public/features.gni
index 2570caf..eaa5edb 100644
--- a/chrome/services/file_util/public/features.gni
+++ b/chrome/services/file_util/public/features.gni
@@ -5,10 +5,10 @@
 import("//extensions/buildflags/buildflags.gni")
 
 declare_args() {
-  # Whether the file_util service supports .xz file extraction.
+  # Whether the file_util service supports .TAR.XZ and .TAR file extraction.
   # Currently only used by imageWriterPrivate extension API, so only enabled
   # when Extensions are enabled.
-  enable_xz_extractor = enable_extensions
+  enable_extractors = enable_extensions
 
   # Enables analysis of Office documents for malicious macros
   enable_maldoca = is_linux || is_win
diff --git a/chrome/services/file_util/public/mojom/BUILD.gn b/chrome/services/file_util/public/mojom/BUILD.gn
index eac7223..b9e80cc 100644
--- a/chrome/services/file_util/public/mojom/BUILD.gn
+++ b/chrome/services/file_util/public/mojom/BUILD.gn
@@ -27,12 +27,12 @@
     public_deps += [ "//components/services/filesystem/public/mojom" ]
   }
 
-  if (enable_xz_extractor) {
+  if (enable_extractors) {
     sources += [
       "constants.mojom",
-      "single_file_tar_xz_file_extractor.mojom",
+      "single_file_extractor.mojom",
     ]
-    enabled_features += [ "xz_extractor" ]
+    enabled_features += [ "extractors" ]
   }
 
   if (safe_browsing_mode == 1 && enable_maldoca) {
diff --git a/chrome/services/file_util/public/mojom/constants.mojom b/chrome/services/file_util/public/mojom/constants.mojom
index 445ca482..93a494b 100644
--- a/chrome/services/file_util/public/mojom/constants.mojom
+++ b/chrome/services/file_util/public/mojom/constants.mojom
@@ -8,8 +8,7 @@
 // The set of errors which may occur while extracting a file.
 enum ExtractionResult {
   kSuccess,
-  // These enums mirror the extensions::image_writer::error strings.
-  kUnzipGenericError,
-  kUnzipInvalidArchive,
-  kTempFileError,
+  kGenericError,
+  kInvalidSrcFile,
+  kDstFileError,
 };
diff --git a/chrome/services/file_util/public/mojom/file_util_service.mojom b/chrome/services/file_util/public/mojom/file_util_service.mojom
index 4f4c401..3dc3cd0c 100644
--- a/chrome/services/file_util/public/mojom/file_util_service.mojom
+++ b/chrome/services/file_util/public/mojom/file_util_service.mojom
@@ -12,8 +12,8 @@
 [EnableIf=is_chromeos_ash]
 import "chrome/services/file_util/public/mojom/zip_file_creator.mojom";
 
-[EnableIf=xz_extractor]
-import "chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom";
+[EnableIf=extractors]
+import "chrome/services/file_util/public/mojom/single_file_extractor.mojom";
 
 // The main interface to the file utility service. Binds any of various
 // specific utility receivers.
@@ -27,8 +27,15 @@
   [EnableIf=full_safe_browsing]
   BindSafeArchiveAnalyzer(pending_receiver<SafeArchiveAnalyzer> receiver);
 
-  // Binds an interface of the SingleFileTarXzFileExtractor interface.
-  [EnableIf=xz_extractor]
+  // Binds a SingleFileTarFileExtractor instance of the SingleFileExtractor
+  // interface.
+  [EnableIf=extractors]
+  BindSingleFileTarFileExtractor(
+      pending_receiver<SingleFileExtractor> receiver);
+
+  // Binds a SingleFileTarXzFileExtractor instance of the SingleFileExtractor
+  // interface.
+  [EnableIf=extractors]
   BindSingleFileTarXzFileExtractor(
-      pending_receiver<SingleFileTarXzFileExtractor> receiver);
+      pending_receiver<SingleFileExtractor> receiver);
 };
diff --git a/chrome/services/file_util/public/mojom/single_file_extractor.mojom b/chrome/services/file_util/public/mojom/single_file_extractor.mojom
new file mode 100644
index 0000000..990a725
--- /dev/null
+++ b/chrome/services/file_util/public/mojom/single_file_extractor.mojom
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chrome.mojom;
+
+import "chrome/services/file_util/public/mojom/constants.mojom";
+import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
+
+// Service that extracts a single file from `src_file`. `src_file` is a .TAR.XZ
+// or .TAR file. SingleFileExtractor interface is a common interface for
+// .TAR.XZ file extraction and .TAR file extraction. `src_file` has to contain
+// a single file. If it does multiple files, the service rejects the request
+// and chrome.file_util.mojom.ExtractionResult.kInvalidSrcFile will return via
+// `result`. This service is designed to extract large files such as OS image
+// files.
+interface SingleFileExtractor {
+  // Extracts a single file from `src_file` and writes the result to
+  // `dst_file`. Progress is regularly reported via the passed `listener`.
+  Extract(mojo_base.mojom.ReadOnlyFile src_file,
+          mojo_base.mojom.File dst_file,
+          pending_remote<SingleFileExtractorListener> listener)
+          => (chrome.file_util.mojom.ExtractionResult result);
+};
+
+// Listener of extract operation.
+interface SingleFileExtractorListener {
+  // Regularly called during the extract operation to report progress.
+  // `total_bytes` indicates the size of the destination file after extraction.
+  // `progress_bytes` indicates the bytes already written to the destination
+  // file.
+  OnProgress(uint64 total_bytes,
+             uint64 progress_bytes);
+};
diff --git a/chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom b/chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom
deleted file mode 100644
index 1a607af..0000000
--- a/chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module chrome.mojom;
-
-import "chrome/services/file_util/public/mojom/constants.mojom";
-import "mojo/public/mojom/base/file.mojom";
-import "mojo/public/mojom/base/read_only_file.mojom";
-
-// Service that extracts a .TAR.XZ file. The .TAR.XZ file has to be a single
-// file which is archived and compressed with tar and xz. That is, the .TAR.XZ
-// file has to be a compressed tar archive with a single file entry. A
-// compressed archive with multiple files will be rejected and
-// chrome.file_util.mojom.ExtractionResult.kUnzipInvalidArchive will return via
-// `result`. This service is designed to extract large files such as OS image
-// files.
-interface SingleFileTarXzFileExtractor {
-  // Extracts the .TAR.XZ file `src_file` and writes the result to `dst_file`.
-  // Progress is regularly reported via the passed `listener`.
-  Extract(mojo_base.mojom.ReadOnlyFile src_file,
-          mojo_base.mojom.File dst_file,
-          pending_remote<SingleFileTarXzFileExtractorListener> listener)
-          => (chrome.file_util.mojom.ExtractionResult result);
-};
-
-// Listener of a .TAR.XZ extraction operation.
-interface SingleFileTarXzFileExtractorListener {
-  // Regularly called during the .TAR.XZ extraction operation to report
-  // progress. `total_bytes` indicates the size of the destination file after
-  // extraction. `progress_bytes` indicates the bytes already written to the
-  // destination file.
-  OnProgress(uint64 total_bytes,
-             uint64 progress_bytes);
-};
diff --git a/chrome/services/file_util/single_file_tar_file_extractor.cc b/chrome/services/file_util/single_file_tar_file_extractor.cc
new file mode 100644
index 0000000..dec83ae
--- /dev/null
+++ b/chrome/services/file_util/single_file_tar_file_extractor.cc
@@ -0,0 +1,114 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/services/file_util/single_file_tar_file_extractor.h"
+
+#include <utility>
+
+#include "chrome/services/file_util/public/mojom/constants.mojom.h"
+#include "chrome/services/file_util/single_file_tar_reader.h"
+
+namespace {
+
+// TarExtractorInner extracts a .TAR file and writes the extracted data to the
+// destination file.
+class TarExtractorInner : public SingleFileTarReader::Delegate {
+ public:
+  TarExtractorInner(
+      mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener>
+          pending_listener,
+      base::File src_file,
+      base::File dst_file)
+      : listener_(std::move(pending_listener)),
+        src_file_(std::move(src_file)),
+        dst_file_(std::move(dst_file)),
+        tar_reader_(this) {}
+
+  chrome::file_util::mojom::ExtractionResult Extract() {
+    while (true) {
+      if (tar_reader_.ExtractChunk() != SingleFileTarReader::Result::kSuccess)
+        return tar_reader_.error();
+
+      if (tar_reader_.IsComplete())
+        return chrome::file_util::mojom::ExtractionResult::kSuccess;
+
+      listener_->OnProgress(tar_reader_.total_bytes().value(),
+                            tar_reader_.curr_bytes());
+    }
+  }
+
+  void CloseFiles() {
+    src_file_.Close();
+    dst_file_.Close();
+  }
+
+ private:
+  // SingleFileTarReader::Delegate implementation.
+  // TODO(b/256967002): Use base::span<>.
+  SingleFileTarReader::Result ReadTarFile(
+      char* data,
+      uint32_t* size,
+      chrome::file_util::mojom::ExtractionResult* error) override {
+    const int bytes_read = src_file_.ReadAtCurrentPos(data, *size);
+    if (bytes_read < 0) {
+      *error = chrome::file_util::mojom::ExtractionResult::kGenericError;
+      return SingleFileTarReader::Result::kFailure;
+    }
+    if (bytes_read == 0) {
+      // After reading the last chunk of file content, it is expected that the
+      // tar_reader_.IsComplete() in the Extract function returns true and the
+      // .tar.xz file extraction ends.
+      *error = chrome::file_util::mojom::ExtractionResult::kGenericError;
+      return SingleFileTarReader::Result::kFailure;
+    }
+    *size = bytes_read;
+    return SingleFileTarReader::Result::kSuccess;
+  }
+
+  // SingleFileTarReader::Delegate implementation.
+  // TODO(b/256967002): Use base::span<>.
+  bool WriteContents(
+      const char* data,
+      int size,
+      chrome::file_util::mojom::ExtractionResult* error) override {
+    const int bytes_written = dst_file_.WriteAtCurrentPos(data, size);
+    if (bytes_written < 0 || bytes_written != size) {
+      *error = chrome::file_util::mojom::ExtractionResult::kDstFileError;
+      return false;
+    }
+    return true;
+  }
+
+  const mojo::Remote<chrome::mojom::SingleFileExtractorListener> listener_;
+
+  base::File src_file_;
+  base::File dst_file_;
+
+  SingleFileTarReader tar_reader_;
+};
+}  // namespace
+
+SingleFileTarFileExtractor::SingleFileTarFileExtractor() = default;
+SingleFileTarFileExtractor::~SingleFileTarFileExtractor() = default;
+
+void SingleFileTarFileExtractor::Extract(
+    base::File src_file,
+    base::File dst_file,
+    mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener>
+        pending_listener,
+    SingleFileExtractor::ExtractCallback callback) {
+  if (!src_file.IsValid() || !dst_file.IsValid()) {
+    std::move(callback).Run(
+        chrome::file_util::mojom::ExtractionResult::kGenericError);
+    return;
+  }
+  TarExtractorInner extractor(std::move(pending_listener), std::move(src_file),
+                              std::move(dst_file));
+  chrome::file_util::mojom::ExtractionResult result = extractor.Extract();
+
+  // Explicitly close the files before calling `callback` to ensure all
+  // extracted data is flushed to the file and the file is closed.
+  extractor.CloseFiles();
+  std::move(callback).Run(result);
+}
diff --git a/chrome/services/file_util/single_file_tar_file_extractor.h b/chrome/services/file_util/single_file_tar_file_extractor.h
new file mode 100644
index 0000000..a2dd31e6
--- /dev/null
+++ b/chrome/services/file_util/single_file_tar_file_extractor.h
@@ -0,0 +1,28 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_SERVICES_FILE_UTIL_SINGLE_FILE_TAR_FILE_EXTRACTOR_H_
+#define CHROME_SERVICES_FILE_UTIL_SINGLE_FILE_TAR_FILE_EXTRACTOR_H_
+
+#include "base/files/file.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+class SingleFileTarFileExtractor : public chrome::mojom::SingleFileExtractor {
+ public:
+  SingleFileTarFileExtractor();
+  ~SingleFileTarFileExtractor() override;
+  SingleFileTarFileExtractor(const SingleFileTarFileExtractor&) = delete;
+  SingleFileTarFileExtractor& operator=(const SingleFileTarFileExtractor&) =
+      delete;
+
+  // chrome::mojom::SingleFileExtractor implementation.
+  void Extract(
+      base::File src_file,
+      base::File dst_file,
+      mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener> listener,
+      ExtractCallback callback) override;
+};
+
+#endif  // CHROME_SERVICES_FILE_UTIL_SINGLE_FILE_TAR_FILE_EXTRACTOR_H_
diff --git a/chrome/services/file_util/single_file_tar_file_extractor_unittest.cc b/chrome/services/file_util/single_file_tar_file_extractor_unittest.cc
new file mode 100644
index 0000000..2d47685
--- /dev/null
+++ b/chrome/services/file_util/single_file_tar_file_extractor_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/services/file_util/single_file_tar_file_extractor.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/services/file_util/public/mojom/constants.mojom.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome {
+
+using ::testing::StrictMock;
+
+class SingleFileTarFileExtractorTest : public testing::Test {
+ public:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+ protected:
+  SingleFileTarFileExtractorTest() = default;
+  ~SingleFileTarFileExtractorTest() override = default;
+
+  base::FilePath GetFilePath(const char* file_name) {
+    base::FilePath test_data;
+    EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+    return test_data.AppendASCII("image_writer_private").AppendASCII(file_name);
+  }
+
+  const base::FilePath& temp_dir() const { return temp_dir_.GetPath(); }
+
+  // BindNewPipeAndPassRemote() requires a sequenced context.
+  base::test::TaskEnvironment task_environment_;
+
+ private:
+  base::ScopedTempDir temp_dir_;
+};
+
+// TODO(b/254591810): Make MockSingleFileExtractorListener a mock.
+class MockSingleFileExtractorListener
+    : public chrome::mojom::SingleFileExtractorListener {
+  // chrome::mojom::SingleFileExtractorListener implementation.
+  void OnProgress(uint64_t total_bytes, uint64_t progress_bytes) override {}
+};
+
+TEST_F(SingleFileTarFileExtractorTest, Extract) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
+  base::FilePath path;
+  ASSERT_NO_FATAL_FAILURE(path = GetFilePath("test.tar"));
+  base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+  base::FilePath out_path = temp_dir().AppendASCII("Extract_dst_file");
+  base::File dst_file(out_path,
+                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
+      mock_listener.get()};
+
+  SingleFileTarFileExtractor extractor;
+  extractor.Extract(std::move(src_file), std::move(dst_file),
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
+
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
+  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
+  std::string contents;
+  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
+  EXPECT_EQ("foo\n", contents);
+}
+
+TEST_F(SingleFileTarFileExtractorTest, ExtractTarLargerThanChunk) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
+  base::FilePath path;
+  ASSERT_NO_FATAL_FAILURE(path = GetFilePath("test_large.tar"));
+  base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+  base::FilePath out_path =
+      temp_dir().AppendASCII("ExtractTarLargerThanChunk_dst_file");
+  base::File dst_file(out_path,
+                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
+      mock_listener.get()};
+
+  SingleFileTarFileExtractor extractor;
+  extractor.Extract(std::move(src_file), std::move(dst_file),
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
+
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
+  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
+  std::string contents;
+  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
+  EXPECT_EQ(10u * 1024u, contents.size());
+}
+
+TEST_F(SingleFileTarFileExtractorTest, ExtractNonExistentTar) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
+  base::FilePath path;
+  ASSERT_NO_FATAL_FAILURE(path = GetFilePath("non_existent.tar"));
+  base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+  base::FilePath out_path =
+      temp_dir().AppendASCII("ExtractNonExistentTar_dst_file");
+  base::File dst_file(out_path,
+                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
+      mock_listener.get()};
+
+  SingleFileTarFileExtractor extractor;
+  extractor.Extract(std::move(src_file), std::move(dst_file),
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
+
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
+  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kGenericError, result);
+}
+
+// Verify that a .tar file with a 0 byte file works.
+TEST_F(SingleFileTarFileExtractorTest, ZeroByteFile) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
+  base::FilePath path;
+  ASSERT_NO_FATAL_FAILURE(path = GetFilePath("empty_file.tar"));
+  base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+  base::FilePath out_path = temp_dir().AppendASCII("ZeroByteFile_dst_file");
+  base::File dst_file(out_path,
+                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
+      mock_listener.get()};
+
+  SingleFileTarFileExtractor extractor;
+  extractor.Extract(std::move(src_file), std::move(dst_file),
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
+
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
+  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
+  std::string contents;
+  ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
+  ASSERT_TRUE(contents.empty());
+}
+
+}  // namespace chrome
diff --git a/chrome/services/file_util/single_file_tar_reader.cc b/chrome/services/file_util/single_file_tar_reader.cc
index f62e8377..f6ae8a5 100644
--- a/chrome/services/file_util/single_file_tar_reader.cc
+++ b/chrome/services/file_util/single_file_tar_reader.cc
@@ -52,7 +52,7 @@
   // We haven't read the header.
   if (!total_bytes_.has_value()) {
     if (bytes_read < 512) {
-      error_ = chrome::file_util::mojom::ExtractionResult::kUnzipInvalidArchive;
+      error_ = chrome::file_util::mojom::ExtractionResult::kInvalidSrcFile;
       return Result::kFailure;
     }
 
diff --git a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader_unittest.cc b/chrome/services/file_util/single_file_tar_reader_unittest.cc
similarity index 75%
rename from chrome/browser/extensions/api/image_writer_private/single_file_tar_reader_unittest.cc
rename to chrome/services/file_util/single_file_tar_reader_unittest.cc
index bbd19cd..33536304 100644
--- a/chrome/browser/extensions/api/image_writer_private/single_file_tar_reader_unittest.cc
+++ b/chrome/services/file_util/single_file_tar_reader_unittest.cc
@@ -2,18 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/image_writer_private/single_file_tar_reader.h"
+#include "chrome/services/file_util/single_file_tar_reader.h"
 
 #include <memory>
 #include <vector>
 
 #include "base/files/file_util.h"
-#include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace extensions {
-namespace image_writer {
-
 class SingleFileTarReaderTest : public testing::Test,
                                 public SingleFileTarReader::Delegate {
  public:
@@ -23,17 +21,26 @@
   SingleFileTarReaderTest& operator=(const SingleFileTarReaderTest&) = delete;
   ~SingleFileTarReaderTest() override = default;
 
+  bool GetTestDataDirectory(base::FilePath* path) {
+    bool success = base::PathService::Get(chrome::DIR_TEST_DATA, path);
+    if (!success)
+      return false;
+    *path = path->AppendASCII("image_writer_private");
+    return true;
+  }
+
   bool OpenTarFile(const base::FilePath& file_path) {
-    infile_ = std::make_unique<base::File>(
+    src_file_ = std::make_unique<base::File>(
         file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-    return infile_->IsValid();
+    return src_file_->IsValid();
   }
 
   // SingleFileTarReader::Delegate:
-  SingleFileTarReader::Result ReadTarFile(char* data,
-                                          uint32_t* size,
-                                          std::string* error_id) override {
-    int bytes_read = infile_->ReadAtCurrentPos(data, *size);
+  SingleFileTarReader::Result ReadTarFile(
+      char* data,
+      uint32_t* size,
+      chrome::file_util::mojom::ExtractionResult* error) override {
+    int bytes_read = src_file_->ReadAtCurrentPos(data, *size);
     if (bytes_read < 0) {
       return SingleFileTarReader::Result::kFailure;
     }
@@ -42,9 +49,10 @@
     return SingleFileTarReader::Result::kSuccess;
   }
 
-  bool WriteContents(const char* data,
-                     int size,
-                     std::string* error_id) override {
+  bool WriteContents(
+      const char* data,
+      int size,
+      chrome::file_util::mojom::ExtractionResult* error) override {
     contents_.insert(contents_.end(), data, data + size);
     return true;
   }
@@ -53,7 +61,7 @@
   const std::vector<char>& contents() const { return contents_; }
 
  private:
-  std::unique_ptr<base::File> infile_;
+  std::unique_ptr<base::File> src_file_;
   std::vector<char> contents_;
 
   SingleFileTarReader reader_;
@@ -92,6 +100,3 @@
   EXPECT_EQ(SingleFileTarReader::Result::kSuccess, reader().ExtractChunk());
   EXPECT_TRUE(reader().IsComplete());
 }
-
-}  // namespace image_writer
-}  // namespace extensions
diff --git a/chrome/services/file_util/single_file_tar_xz_file_extractor.cc b/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
index 9a1dec5..b766b1d 100644
--- a/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
+++ b/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
@@ -33,11 +33,10 @@
 // output file.
 class ExtractorInner : public SingleFileTarReader::Delegate {
  public:
-  ExtractorInner(
-      mojo::PendingRemote<chrome::mojom::SingleFileTarXzFileExtractorListener>
-          pending_listener,
-      base::File src_file,
-      base::File dst_file)
+  ExtractorInner(mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener>
+                     pending_listener,
+                 base::File src_file,
+                 base::File dst_file)
       : listener_(std::move(pending_listener)),
         src_file_(std::move(src_file)),
         dst_file_(std::move(dst_file)),
@@ -53,12 +52,12 @@
       const int bytes_read = src_file_.ReadAtCurrentPos(
           reinterpret_cast<char*>(xz_buffer.data()), xz_buffer.size());
       if (bytes_read < 0)
-        return chrome::file_util::mojom::ExtractionResult::kUnzipGenericError;
+        return chrome::file_util::mojom::ExtractionResult::kGenericError;
       if (bytes_read == 0) {
         // After reading the last chunk of file content, it is expected that the
         // ExtractChunk() below populates `result` with kSuccess and the .tar.xz
         // file extraction ends.
-        return chrome::file_util::mojom::ExtractionResult::kUnzipGenericError;
+        return chrome::file_util::mojom::ExtractionResult::kGenericError;
       }
 
       absl::optional<chrome::file_util::mojom::ExtractionResult> result;
@@ -73,6 +72,11 @@
     }
   }
 
+  void CloseFiles() {
+    src_file_.Close();
+    dst_file_.Close();
+  }
+
   ~ExtractorInner() override { XzUnpacker_Free(&state_); }
 
  private:
@@ -91,8 +95,7 @@
                                       /*srcFinished=*/xz_buffer.empty(),
                                       CODER_FINISH_ANY, &status);
       if (xz_result != SZ_OK) {
-        *result =
-            chrome::file_util::mojom::ExtractionResult::kUnzipGenericError;
+        *result = chrome::file_util::mojom::ExtractionResult::kGenericError;
         return;
       }
       xz_buffer = xz_buffer.subspan(compressed_size);
@@ -133,14 +136,13 @@
       chrome::file_util::mojom::ExtractionResult* error) override {
     const int bytes_written = dst_file_.WriteAtCurrentPos(data, size);
     if (bytes_written < 0 || bytes_written != size) {
-      *error = chrome::file_util::mojom::ExtractionResult::kTempFileError;
+      *error = chrome::file_util::mojom::ExtractionResult::kDstFileError;
       return false;
     }
     return true;
   }
 
-  const mojo::Remote<chrome::mojom::SingleFileTarXzFileExtractorListener>
-      listener_;
+  const mojo::Remote<chrome::mojom::SingleFileExtractorListener> listener_;
 
   CXzUnpacker state_;
   ISzAlloc alloc_;
@@ -168,18 +170,20 @@
 void SingleFileTarXzFileExtractor::Extract(
     base::File src_file,
     base::File dst_file,
-    mojo::PendingRemote<chrome::mojom::SingleFileTarXzFileExtractorListener>
+    mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener>
         pending_listener,
-    SingleFileTarXzFileExtractor::ExtractCallback callback) {
+    SingleFileExtractor::ExtractCallback callback) {
   if (!src_file.IsValid() || !dst_file.IsValid()) {
     std::move(callback).Run(
-        chrome::file_util::mojom::ExtractionResult::kUnzipGenericError);
+        chrome::file_util::mojom::ExtractionResult::kGenericError);
     return;
   }
-  ExtractorInner* extractor = new ExtractorInner(
-      std::move(pending_listener), std::move(src_file), std::move(dst_file));
-  chrome::file_util::mojom::ExtractionResult result = extractor->Extract();
-  // Destroy the File objects before calling `callback`.
-  delete extractor;
+  ExtractorInner extractor(std::move(pending_listener), std::move(src_file),
+                           std::move(dst_file));
+  chrome::file_util::mojom::ExtractionResult result = extractor.Extract();
+
+  // Explicitly close the files before calling `callback` to ensure all
+  // extracted data is flushed to the file and the file is closed.
+  extractor.CloseFiles();
   std::move(callback).Run(result);
 }
diff --git a/chrome/services/file_util/single_file_tar_xz_file_extractor.h b/chrome/services/file_util/single_file_tar_xz_file_extractor.h
index 1c76846..8c21f4c 100644
--- a/chrome/services/file_util/single_file_tar_xz_file_extractor.h
+++ b/chrome/services/file_util/single_file_tar_xz_file_extractor.h
@@ -6,11 +6,10 @@
 #define CHROME_SERVICES_FILE_UTIL_SINGLE_FILE_TAR_XZ_FILE_EXTRACTOR_H_
 
 #include "base/files/file.h"
-#include "chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
-class SingleFileTarXzFileExtractor
-    : public chrome::mojom::SingleFileTarXzFileExtractor {
+class SingleFileTarXzFileExtractor : public chrome::mojom::SingleFileExtractor {
  public:
   SingleFileTarXzFileExtractor();
   ~SingleFileTarXzFileExtractor() override;
@@ -18,12 +17,11 @@
   SingleFileTarXzFileExtractor& operator=(const SingleFileTarXzFileExtractor&) =
       delete;
 
-  // chrome::mojom::SingleFileTarXzFileExtractor implementation.
+  // chrome::mojom::SingleFileExtractor implementation.
   void Extract(
       base::File src_file,
       base::File dst_file,
-      mojo::PendingRemote<chrome::mojom::SingleFileTarXzFileExtractorListener>
-          listener,
+      mojo::PendingRemote<chrome::mojom::SingleFileExtractorListener> listener,
       ExtractCallback callback) override;
 };
 
diff --git a/chrome/services/file_util/single_file_tar_xz_file_extractor_unittest.cc b/chrome/services/file_util/single_file_tar_xz_file_extractor_unittest.cc
index 4d170a9..f428f1c 100644
--- a/chrome/services/file_util/single_file_tar_xz_file_extractor_unittest.cc
+++ b/chrome/services/file_util/single_file_tar_xz_file_extractor_unittest.cc
@@ -15,9 +15,10 @@
 #include "base/path_service.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/services/file_util/public/mojom/constants.mojom.h"
-#include "chrome/services/file_util/public/mojom/single_file_tar_xz_file_extractor.mojom.h"
+#include "chrome/services/file_util/public/mojom/single_file_extractor.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -51,14 +52,16 @@
   base::ScopedTempDir temp_dir_;
 };
 
-// TODO(b/254591810): Make MockSingleFileTarXzFileExtractorListener a mock.
-class MockSingleFileTarXzFileExtractorListener
-    : public chrome::mojom::SingleFileTarXzFileExtractorListener {
-  // chrome::mojom::SingleFileTarXzFileExtractorListener implementation.
+// TODO(b/254591810): Make MockSingleFileExtractorListener a mock.
+class MockSingleFileExtractorListener
+    : public chrome::mojom::SingleFileExtractorListener {
+  // chrome::mojom::SingleFileExtractorListener implementation.
   void OnProgress(uint64_t total_bytes, uint64_t progress_bytes) override {}
 };
 
 TEST_F(SingleFileTarXzFileExtractorTest, Extract) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
   base::FilePath path;
   ASSERT_NO_FATAL_FAILURE(path = GetFilePath("test.tar.xz"));
   base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -67,20 +70,15 @@
   base::File dst_file(out_path,
                       base::File::FLAG_CREATE | base::File::FLAG_WRITE);
 
-  auto mock_listener =
-      std::make_unique<MockSingleFileTarXzFileExtractorListener>();
-  mojo::Receiver<chrome::mojom::SingleFileTarXzFileExtractorListener> listener{
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
       mock_listener.get()};
 
-  StrictMock<base::MockCallback<SingleFileTarXzFileExtractor::ExtractCallback>>
-      callback;
-
-  chrome::file_util::mojom::ExtractionResult result;
-  EXPECT_CALL(callback, Run).WillOnce(testing::SaveArg<0>(&result));
   SingleFileTarXzFileExtractor extractor;
   extractor.Extract(std::move(src_file), std::move(dst_file),
-                    listener.BindNewPipeAndPassRemote(), callback.Get());
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
 
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
   EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
   std::string contents;
   ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
@@ -88,6 +86,8 @@
 }
 
 TEST_F(SingleFileTarXzFileExtractorTest, ExtractNonExistentTarXz) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
   base::FilePath path;
   ASSERT_NO_FATAL_FAILURE(path = GetFilePath("non_existent.tar.xz"));
   base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -97,25 +97,21 @@
   base::File dst_file(out_path,
                       base::File::FLAG_CREATE | base::File::FLAG_WRITE);
 
-  auto mock_listener =
-      std::make_unique<MockSingleFileTarXzFileExtractorListener>();
-  mojo::Receiver<chrome::mojom::SingleFileTarXzFileExtractorListener> listener{
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
       mock_listener.get()};
 
-  StrictMock<base::MockCallback<SingleFileTarXzFileExtractor::ExtractCallback>>
-      callback;
-
-  chrome::file_util::mojom::ExtractionResult result;
-  EXPECT_CALL(callback, Run).WillOnce(testing::SaveArg<0>(&result));
   SingleFileTarXzFileExtractor extractor;
   extractor.Extract(std::move(src_file), std::move(dst_file),
-                    listener.BindNewPipeAndPassRemote(), callback.Get());
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
 
-  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kUnzipGenericError,
-            result);
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
+  EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kGenericError, result);
 }
 
 TEST_F(SingleFileTarXzFileExtractorTest, ZeroByteFile) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
   base::FilePath path;
   ASSERT_NO_FATAL_FAILURE(path = GetFilePath("empty_file.tar.xz"));
   base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -124,20 +120,15 @@
   base::File dst_file(out_path,
                       base::File::FLAG_CREATE | base::File::FLAG_WRITE);
 
-  auto mock_listener =
-      std::make_unique<MockSingleFileTarXzFileExtractorListener>();
-  mojo::Receiver<chrome::mojom::SingleFileTarXzFileExtractorListener> listener{
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
       mock_listener.get()};
 
-  StrictMock<base::MockCallback<SingleFileTarXzFileExtractor::ExtractCallback>>
-      callback;
-
-  chrome::file_util::mojom::ExtractionResult result;
-  EXPECT_CALL(callback, Run).WillOnce(testing::SaveArg<0>(&result));
   SingleFileTarXzFileExtractor extractor;
   extractor.Extract(std::move(src_file), std::move(dst_file),
-                    listener.BindNewPipeAndPassRemote(), callback.Get());
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
 
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
   EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
   std::string contents;
   ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
@@ -145,6 +136,8 @@
 }
 
 TEST_F(SingleFileTarXzFileExtractorTest, ExtractBigFile) {
+  base::test::TestFuture<chrome::file_util::mojom::ExtractionResult> future;
+
   base::FilePath path;
   ASSERT_NO_FATAL_FAILURE(path = GetFilePath("2MBzeros.tar.xz"));
   base::File src_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -153,20 +146,15 @@
   base::File dst_file(out_path,
                       base::File::FLAG_CREATE | base::File::FLAG_WRITE);
 
-  auto mock_listener =
-      std::make_unique<MockSingleFileTarXzFileExtractorListener>();
-  mojo::Receiver<chrome::mojom::SingleFileTarXzFileExtractorListener> listener{
+  auto mock_listener = std::make_unique<MockSingleFileExtractorListener>();
+  mojo::Receiver<chrome::mojom::SingleFileExtractorListener> listener{
       mock_listener.get()};
 
-  StrictMock<base::MockCallback<SingleFileTarXzFileExtractor::ExtractCallback>>
-      callback;
-
-  chrome::file_util::mojom::ExtractionResult result;
-  EXPECT_CALL(callback, Run).WillOnce(testing::SaveArg<0>(&result));
   SingleFileTarXzFileExtractor extractor;
   extractor.Extract(std::move(src_file), std::move(dst_file),
-                    listener.BindNewPipeAndPassRemote(), callback.Get());
+                    listener.BindNewPipeAndPassRemote(), future.GetCallback());
 
+  const chrome::file_util::mojom::ExtractionResult& result = future.Get();
   EXPECT_EQ(chrome::file_util::mojom::ExtractionResult::kSuccess, result);
   std::string contents;
   ASSERT_TRUE(base::ReadFileToString(out_path, &contents));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 1aaa0a3..f38384a31 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1412,6 +1412,7 @@
       "//components/page_load_metrics/common",
       "//components/page_load_metrics/common:test_support",
       "//components/password_manager/content/browser",
+      "//components/password_manager/content/common",
       "//components/password_manager/core/browser:affiliation_proto",
       "//components/password_manager/core/browser/form_parsing",
       "//components/payments/content",
@@ -7912,7 +7913,6 @@
       "../browser/extensions/api/image_writer_private/image_writer_private_api_unittest.cc",
       "../browser/extensions/api/image_writer_private/operation_manager_unittest.cc",
       "../browser/extensions/api/image_writer_private/operation_unittest.cc",
-      "../browser/extensions/api/image_writer_private/single_file_tar_reader_unittest.cc",
       "../browser/extensions/api/image_writer_private/test_utils.cc",
       "../browser/extensions/api/image_writer_private/test_utils.h",
       "../browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc",
diff --git a/chrome/test/chromedriver/chrome/adb_impl.cc b/chrome/test/chromedriver/chrome/adb_impl.cc
index 2484642..25d2a16 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.cc
+++ b/chrome/test/chromedriver/chrome/adb_impl.cc
@@ -246,10 +246,17 @@
     const std::string& device_serial, const std::string& package,
     const std::string& activity) {
   std::string response;
+  ExecuteHostShellCommand(device_serial, "getprop ro.build.version.release",
+                          &response);
+  int android_version = stoi(response);
+  if (android_version >= 13) {
+    ExecuteHostShellCommand(
+        device_serial,
+        "pm grant " + package + " android.permission.POST_NOTIFICATIONS",
+        &response);
+  }
   Status status = ExecuteHostShellCommand(
-      device_serial,
-      "am start -W -n " + package + "/" + activity + " -d data:,",
-      &response);
+      device_serial, "am start -W -n " + package + "/" + activity, &response);
   if (!status.IsOk())
     return status;
   if (response.find("Complete") == std::string::npos)
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 68cb94c..d160931 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -248,8 +248,15 @@
     SetSafeInt(dict, "expiry", cookie.expiry);
   dict.Set("httpOnly", cookie.http_only);
   dict.Set("secure", cookie.secure);
-  if (!cookie.samesite.empty())
+  if (!cookie.samesite.empty()) {
     dict.Set("sameSite", cookie.samesite);
+  } else {
+    // The default in the standard is Lax:
+    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
+    // Chrome (mostly) treats default cookies as Lax so this seems correct:
+    // https://chromestatus.com/feature/5088147346030592
+    dict.Set("sameSite", "Lax");
+  }
   return dict;
 }
 
diff --git a/chrome/test/chromedriver/window_commands_unittest.cc b/chrome/test/chromedriver/window_commands_unittest.cc
index 5b45128..75c4184 100644
--- a/chrome/test/chromedriver/window_commands_unittest.cc
+++ b/chrome/test/chromedriver/window_commands_unittest.cc
@@ -366,6 +366,133 @@
 
 namespace {
 
+class GetCookiesWebView : public StubWebView {
+ public:
+  explicit GetCookiesWebView(std::string document_url)
+      : StubWebView("1"), document_url_(document_url) {}
+  ~GetCookiesWebView() override = default;
+
+  Status CallFunction(const std::string& frame,
+                      const std::string& function,
+                      const base::Value::List& args,
+                      std::unique_ptr<base::Value>* result) override {
+    if (function.find("document.URL") != std::string::npos) {
+      *result = std::make_unique<base::Value>(document_url_);
+    }
+    return Status(kOk);
+  }
+
+  Status GetCookies(base::Value* cookies,
+                    const std::string& current_page_url) override {
+    base::Value::List new_cookies;
+    base::Value::Dict cookie_0;
+    cookie_0.Set("name", "a");
+    cookie_0.Set("value", "0");
+    cookie_0.Set("domain", "example.com");
+    cookie_0.Set("path", "/");
+    cookie_0.Set("session", true);
+    new_cookies.Append(cookie_0.Clone());
+    base::Value::Dict cookie_1;
+    cookie_1.Set("name", "b");
+    cookie_1.Set("value", "1");
+    cookie_1.Set("domain", "example.org");
+    cookie_1.Set("path", "/test");
+    cookie_1.Set("sameSite", "None");
+    cookie_1.Set("expires", 10);
+    cookie_1.Set("httpOnly", true);
+    cookie_1.Set("session", false);
+    cookie_1.Set("secure", true);
+    new_cookies.Append(cookie_1.Clone());
+    *cookies = base::Value(new_cookies.Clone());
+    return Status(kOk);
+  }
+
+ private:
+  std::string document_url_;
+};
+
+}  // namespace
+
+TEST(WindowCommandsTest, ExecuteGetCookies) {
+  GetCookiesWebView webview = GetCookiesWebView("https://chromium.org");
+  base::Value::Dict params;
+  std::unique_ptr<base::Value> result_value;
+  Status status =
+      CallWindowCommand(ExecuteGetCookies, &webview, params, &result_value);
+  ASSERT_EQ(kOk, status.code()) << status.message();
+  base::Value::List expected_cookies;
+  base::Value::Dict cookie_0;
+  cookie_0.Set("name", "a");
+  cookie_0.Set("value", "0");
+  cookie_0.Set("domain", "example.com");
+  cookie_0.Set("path", "/");
+  cookie_0.Set("sameSite", "Lax");
+  cookie_0.Set("httpOnly", false);
+  cookie_0.Set("secure", false);
+  expected_cookies.Append(cookie_0.Clone());
+  base::Value::Dict cookie_1;
+  cookie_1.Set("name", "b");
+  cookie_1.Set("value", "1");
+  cookie_1.Set("domain", "example.org");
+  cookie_1.Set("path", "/test");
+  cookie_1.Set("sameSite", "None");
+  cookie_1.Set("expiry", 10);
+  cookie_1.Set("httpOnly", true);
+  cookie_1.Set("secure", true);
+  expected_cookies.Append(cookie_1.Clone());
+  EXPECT_EQ(result_value->GetList(), expected_cookies);
+}
+
+TEST(WindowCommandsTest, ExecuteGetNamedCookie) {
+  GetCookiesWebView webview = GetCookiesWebView("https://chromium.org");
+  base::Value::Dict params;
+  std::unique_ptr<base::Value> result_value;
+
+  // Get without cookie name.
+  Status status =
+      CallWindowCommand(ExecuteGetNamedCookie, &webview, params, &result_value);
+  ASSERT_EQ(kInvalidArgument, status.code()) << status.message();
+
+  // Get with undefined cookie.
+  params.Set("name", "missing");
+  status =
+      CallWindowCommand(ExecuteGetNamedCookie, &webview, params, &result_value);
+  ASSERT_EQ(kNoSuchCookie, status.code()) << status.message();
+
+  // Get cookie a.
+  params.Set("name", "a");
+  status =
+      CallWindowCommand(ExecuteGetNamedCookie, &webview, params, &result_value);
+  ASSERT_EQ(kOk, status.code()) << status.message();
+  base::Value::Dict expected_cookie_0;
+  expected_cookie_0.Set("name", "a");
+  expected_cookie_0.Set("value", "0");
+  expected_cookie_0.Set("domain", "example.com");
+  expected_cookie_0.Set("path", "/");
+  expected_cookie_0.Set("sameSite", "Lax");
+  expected_cookie_0.Set("httpOnly", false);
+  expected_cookie_0.Set("secure", false);
+  EXPECT_EQ(result_value->GetDict(), expected_cookie_0);
+
+  // Get cookie b.
+  params.Set("name", "b");
+  status =
+      CallWindowCommand(ExecuteGetNamedCookie, &webview, params, &result_value);
+  ASSERT_EQ(kOk, status.code()) << status.message();
+  base::Value::Dict expected_cookie_1;
+  expected_cookie_1.Set("name", "b");
+  expected_cookie_1.Set("value", "1");
+  expected_cookie_1.Set("domain", "example.org");
+  expected_cookie_1.Set("path", "/test");
+  expected_cookie_1.Set("sameSite", "None");
+  expected_cookie_1.Set("expiry", 10);
+  expected_cookie_1.Set("httpOnly", true);
+  expected_cookie_1.Set("secure", true);
+  EXPECT_EQ(result_value->GetDict(), expected_cookie_1);
+}
+
+namespace {
+
 class StorePrintParamsWebView : public StubWebView {
  public:
   StorePrintParamsWebView() : StubWebView("1") {}
diff --git a/chrome/test/data/webui/invalidations/invalidations_test.js b/chrome/test/data/webui/invalidations/invalidations_test.js
index be49504..8f0e5ff 100644
--- a/chrome/test/data/webui/invalidations/invalidations_test.js
+++ b/chrome/test/data/webui/invalidations/invalidations_test.js
@@ -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 {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 import {assertEquals, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 
diff --git a/chrome/test/data/webui/password_manager/password_manager_browsertest.js b/chrome/test/data/webui/password_manager/password_manager_browsertest.js
index 218d5e2..91971405 100644
--- a/chrome/test/data/webui/password_manager/password_manager_browsertest.js
+++ b/chrome/test/data/webui/password_manager/password_manager_browsertest.js
@@ -24,12 +24,6 @@
   }
 };
 
-// TODO(crbug.com/1383449): Failing on Mac.
-GEN('#if BUILDFLAG(IS_MAC)');
-GEN('#define MAYBE_PasswordManagerUIPasswordsSectionTest DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_PasswordManagerUIPasswordsSectionTest All');
-GEN('#endif');
 [['App', 'password_manager_app_test.js'],
  ['SideBar', 'password_manager_side_bar_test.js'],
  ['Settings', 'settings_section_test.js'],
diff --git a/chrome/test/data/webui/password_manager/passwords_section_test.ts b/chrome/test/data/webui/password_manager/passwords_section_test.ts
index 35a7958..c43d9ef 100644
--- a/chrome/test/data/webui/password_manager/passwords_section_test.ts
+++ b/chrome/test/data/webui/password_manager/passwords_section_test.ts
@@ -17,12 +17,14 @@
  * @param subsection The passwords subsection element that will be checked.
  * @param expectedPasswords The expected passwords in this subsection.
  */
-async function validatePasswordsSubsection(
+function validatePasswordsSubsection(
     list: IronListElement,
     expectedGroups: chrome.passwordsPrivate.CredentialGroup[]) {
   assertDeepEquals(expectedGroups, list.items);
 
   const listItemElements = list.querySelectorAll('password-list-item');
+  assertEquals(listItemElements.length, expectedGroups.length);
+
   for (let index = 0; index < expectedGroups.length; ++index) {
     const expectedGroup = expectedGroups[index]!;
     const listItemElement = listItemElements[index];
@@ -43,16 +45,7 @@
     return flushTasks();
   });
 
-  // TODO(crbug.com/1383225): Enable test again once the solution is found.
-  test.skip('password section listens to updates', async function() {
-    const section: PasswordsSectionElement =
-        document.createElement('passwords-section');
-    document.body.appendChild(section);
-    await flushTasks();
-
-    // PasswordsList is hidden as there are no passwords.
-    assertFalse(isVisible(section.$.passwordsList));
-
+  test('groups shown correctly', async function() {
     passwordManager.data.groups = [
       createCredentialGroup({
         name: 'test.com',
@@ -63,14 +56,28 @@
         credentials: [createPasswordEntry({username: 'user', id: 1})],
       }),
     ];
-    assertTrue(!!passwordManager.listeners.savedPasswordListChangedListener);
-    passwordManager.listeners.savedPasswordListChangedListener!([]);
+
+    const section: PasswordsSectionElement =
+        document.createElement('passwords-section');
+    document.body.appendChild(section);
+    await passwordManager.whenCalled('getCredentialGroups');
     await flushTasks();
 
     validatePasswordsSubsection(
         section.$.passwordsList, passwordManager.data.groups);
   });
 
+  test('passwords list is hidden if nothing to show', async function() {
+    const section: PasswordsSectionElement =
+        document.createElement('passwords-section');
+    document.body.appendChild(section);
+    await passwordManager.whenCalled('getCredentialGroups');
+    await flushTasks();
+
+    // PasswordsList is hidden as there are no passwords.
+    assertFalse(isVisible(section.$.passwordsList));
+  });
+
   test('clicking group navigates to details page', async function() {
     Router.getInstance().navigateTo(Page.PASSWORDS);
     passwordManager.data.groups = [createCredentialGroup({
diff --git a/chrome/test/data/webui/settings/review_notification_permissions_interactive_ui_test.ts b/chrome/test/data/webui/settings/review_notification_permissions_interactive_ui_test.ts
index 854f0b0..4c3ad64 100644
--- a/chrome/test/data/webui/settings/review_notification_permissions_interactive_ui_test.ts
+++ b/chrome/test/data/webui/settings/review_notification_permissions_interactive_ui_test.ts
@@ -10,7 +10,7 @@
 
 import {SettingsReviewNotificationPermissionsElement, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
-import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 // clang-format on
 
 suite('CrSettingsReviewNotificationPermissionsInteractiveUITest', function() {
@@ -165,4 +165,4 @@
     await focusPromise;
     assertExpandButtonFocus();
   });
-});
\ No newline at end of file
+});
diff --git a/chrome/test/data/webui/sys_internals/api_test.js b/chrome/test/data/webui/sys_internals/api_test.js
index a0b684d0..d8567d7 100644
--- a/chrome/test/data/webui/sys_internals/api_test.js
+++ b/chrome/test/data/webui/sys_internals/api_test.js
@@ -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 {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {sendWithPromise} from 'chrome://resources/js/cr.js';
 
 suite('getSysInfo', function() {
   test('Message handler integration test', function(done) {
diff --git a/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.cc b/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.cc
index 05b1849..fa3cbda 100644
--- a/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.cc
+++ b/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.cc
@@ -775,6 +775,16 @@
   std::move(callback).Run(run_routine_response_.Clone());
 }
 
+void FakeCrosHealthd::RunPrivacyScreenRoutine(
+    bool target_state,
+    RunPrivacyScreenRoutineCallback callback) {
+  last_run_routine_ = mojom::DiagnosticRoutineEnum::kPrivacyScreen;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), run_routine_response_.Clone()),
+      callback_delay_);
+}
+
 void FakeCrosHealthd::AddBluetoothObserver(
     mojo::PendingRemote<mojom::CrosHealthdBluetoothObserver> observer) {
   bluetooth_observers_.Add(std::move(observer));
diff --git a/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h b/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h
index a351d719..b74c371c7 100644
--- a/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h
+++ b/chromeos/ash/services/cros_healthd/public/cpp/fake_cros_healthd.h
@@ -324,6 +324,9 @@
   void RunFingerprintRoutine(RunFingerprintRoutineCallback callback) override;
   void RunFingerprintAliveRoutine(
       RunFingerprintAliveRoutineCallback callback) override;
+  void RunPrivacyScreenRoutine(
+      bool target_state,
+      RunPrivacyScreenRoutineCallback callback) override;
 
   // CrosHealthdEventService overrides:
   void AddBluetoothObserver(
diff --git a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom
index bfdbd1ed..1f389459 100644
--- a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom
+++ b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom
@@ -54,7 +54,7 @@
 
 // Diagnostics interface exposed by the cros_healthd daemon.
 //
-// NextMinVersion: 4, NextIndex: 36
+// NextMinVersion: 5, NextIndex: 37
 [Stable]
 interface CrosHealthdDiagnosticsService {
   // Returns an array of all diagnostic routines that the platform supports.
@@ -550,6 +550,16 @@
   // * |response| - contains a unique identifier and status for the created
   //                routine.
   [MinVersion=3] RunFingerprintAliveRoutine@35()
+    => (RunRoutineResponse response);
+
+  // Requests that the PrivacyScreen routine is created and started on the
+  // platform. This routine checks whether the privacy screen is working as
+  // expected. This routine is only available if GetAvailableRoutines returned
+  // kPrivacyScreen.
+  //
+  // The request:
+  // * |target_state| - privacy screen target state.
+  [MinVersion=4] RunPrivacyScreenRoutine@36(bool target_state)
       => (RunRoutineResponse response);
 };
 
diff --git a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom
index 3988da10..7171a944 100644
--- a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom
+++ b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom
@@ -15,7 +15,7 @@
 
 // Enumeration of each of the diagnostics routines the platform may support.
 //
-// NextMinVersion: 3, NextIndex: 34
+// NextMinVersion: 4, NextIndex: 35
 [Stable, Extensible]
 enum DiagnosticRoutineEnum {
   [Default] kUnknown = 30,
@@ -52,6 +52,7 @@
   [MinVersion=1] kSensitiveSensor = 31,
   [MinVersion=2] kFingerprint = 32,
   [MinVersion=2] kFingerprintAlive = 33,
+  [MinVersion=3] kPrivacyScreen = 34
 };
 
 // Enumeration of the possible DiskRead routine's command type
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc
index bc9e5c2..3ea55d2 100644
--- a/chromeos/services/network_config/cros_network_config.cc
+++ b/chromeos/services/network_config/cros_network_config.cc
@@ -3615,9 +3615,17 @@
   DCHECK(network_metadata_store);
 
   base::Value::List new_apns;
-  if (const base::Value::List* old_apns =
+  if (const base::Value::List* old_custom_apns =
           network_metadata_store->GetCustomApnList(network_guid)) {
-    new_apns = old_apns->Clone();
+    if (old_custom_apns->size() >= mojom::kMaxNumCustomApns) {
+      NET_LOG(ERROR)
+          << "CreateCustomApn: Cannot create new custom APN for network: "
+          << network_guid << ". Network already has the max amount allowed: "
+          << mojom::kMaxNumCustomApns;
+      return;
+    }
+
+    new_apns = old_custom_apns->Clone();
   }
 
   // Set unique Id for custom APNs
diff --git a/chromeos/services/network_config/cros_network_config_unittest.cc b/chromeos/services/network_config/cros_network_config_unittest.cc
index 49c48b5a..2bc22ac 100644
--- a/chromeos/services/network_config/cros_network_config_unittest.cc
+++ b/chromeos/services/network_config/cros_network_config_unittest.cc
@@ -1941,6 +1941,45 @@
   }
 }
 
+TEST_F(CrosNetworkConfigTest, CreateCustomApn_MaxAmountAllowed) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(ash::features::kApnRevamp);
+
+  // Register an observer to capture values sent to Shill
+  TestNetworkConfigurationObserver network_config_observer(
+      network_configuration_handler());
+
+  const base::Value::List* custom_apns =
+      network_metadata_store()->GetCustomApnList(kCellularGuid);
+  ASSERT_FALSE(custom_apns);
+
+  TestApnData test_apn1;
+  test_apn1.access_point_name = kCellularTestApn1;
+  test_apn1.name = kCellularTestApnName1;
+  test_apn1.username = kCellularTestApnUsername1;
+  test_apn1.password = kCellularTestApnPassword1;
+  test_apn1.attach = kCellularTestApnAttach1;
+  test_apn1.mojo_apn_types = {mojom::ApnType::kDefault,
+                              mojom::ApnType::kAttach};
+  test_apn1.onc_apn_types = {::onc::cellular_apn::kApnTypeDefault,
+                             ::onc::cellular_apn::kApnTypeAttach};
+
+  // Verify that the API creates as many APNs as allowed
+  for (size_t i = 0; i < mojom::kMaxNumCustomApns; ++i) {
+    CreateCustomApn(kCellularGuid, test_apn1.AsMojoApn());
+    EXPECT_EQ(i + 1,
+              network_config_observer.GetOnConfigurationModifiedCallCount());
+  }
+  // Verify that the next call does nothing
+  CreateCustomApn(kCellularGuid, test_apn1.AsMojoApn());
+  EXPECT_EQ(mojom::kMaxNumCustomApns,
+            network_config_observer.GetOnConfigurationModifiedCallCount());
+
+  custom_apns = network_metadata_store()->GetCustomApnList(kCellularGuid);
+  ASSERT_TRUE(custom_apns);
+  EXPECT_EQ(mojom::kMaxNumCustomApns, custom_apns->size());
+}
+
 TEST_F(CrosNetworkConfigTest, ConnectedAPN_ApnRevampEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(ash::features::kApnRevamp);
diff --git a/chromeos/services/network_config/public/mojom/cros_network_config.mojom b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
index 8b3acbf0..843530e 100644
--- a/chromeos/services/network_config/public/mojom/cros_network_config.mojom
+++ b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
@@ -17,6 +17,9 @@
 import "services/network/public/mojom/ip_address.mojom";
 import "url/mojom/url.mojom";
 
+// The maximum number of custom APNs that a cellular network can have.
+const uint8 kMaxNumCustomApns = 10;
+
 // Activation state for Cellular networks.
 enum ActivationStateType {
   kUnknown,
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
index 9deab27..50507d9 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
@@ -291,6 +291,10 @@
         }
         // If a customIcon is provided we prefer to use it over the iconId of the item.
         if (item.getCustomIcon() != null) {
+            // TODO(crbug.com/1381189): We need to scale the bitmap because we show custom icons to
+            // highlight certain credit card features (like virtual cards), which are available in a
+            // fixed size. In future, if we show only the card art for all cards, there is no need
+            // to scale the bitmap as we can directly fetch the icon in the required size.
             // Scale the bitmap to match the dimensions of the default resources used for other
             // items.
             Bitmap scaledBitmap = Bitmap.createScaledBitmap(item.getCustomIcon(),
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
index 7077b956..dbdc0ed 100644
--- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
+++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
@@ -6,7 +6,7 @@
 import 'chrome://resources/js/ios/web_ui.js';
 // </if>
 
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 // By default this page only records metrics for a given period of time in order
@@ -260,7 +260,7 @@
   setUpMarker();
   setUpDownload('password-manager');
   setUpStopRecording();
-  addWebUIListener(
+  addWebUiListener(
       'enable-reset-upm-eviction-button', enableResetUpmEvictionButton);
 }
 
@@ -414,13 +414,13 @@
 }
 
 document.addEventListener('DOMContentLoaded', function(event) {
-  addWebUIListener('enable-reset-cache-button', enableResetCacheButton);
-  addWebUIListener('notify-about-incognito', notifyAboutIncognito);
-  addWebUIListener('notify-about-variations', notifyAboutVariations);
-  addWebUIListener('notify-reset-done', message => showModalDialog(message));
-  addWebUIListener('add-structured-log', addStructuredLog);
-  addWebUIListener('setup-autofill-internals', setUpAutofillInternals);
-  addWebUIListener(
+  addWebUiListener('enable-reset-cache-button', enableResetCacheButton);
+  addWebUiListener('notify-about-incognito', notifyAboutIncognito);
+  addWebUiListener('notify-about-variations', notifyAboutVariations);
+  addWebUiListener('notify-reset-done', message => showModalDialog(message));
+  addWebUiListener('add-structured-log', addStructuredLog);
+  addWebUiListener('setup-autofill-internals', setUpAutofillInternals);
+  addWebUiListener(
       'setup-password-manager-internals', setUpPasswordManagerInternals);
 
   chrome.send('loaded');
diff --git a/components/autofill/core/browser/form_types.cc b/components/autofill/core/browser/form_types.cc
index 8b542bd7..15b6a13 100644
--- a/components/autofill/core/browser/form_types.cc
+++ b/components/autofill/core/browser/form_types.cc
@@ -34,13 +34,13 @@
 base::StringPiece FormTypeToStringPiece(FormType form_type) {
   switch (form_type) {
     case FormType::kAddressForm:
-      return "AddressForm";
+      return "Address";
     case FormType::kCreditCardForm:
-      return "CreditCardForm";
+      return "CreditCard";
     case FormType::kPasswordForm:
-      return "PasswordForm";
+      return "Password";
     case FormType::kUnknownFormType:
-      return "UnknownFormType";
+      return "Unknown";
   }
 
   NOTREACHED();
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index ce90a7c..597d27f 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -469,8 +469,7 @@
   base::HistogramTester histogram_tester;
   SubmitForm(form);
 
-  const std::string histogram_prefix =
-      "Autofill.FieldFillingStats.AddressForm.";
+  const std::string histogram_prefix = "Autofill.FieldFillingStats.Address.";
 
   histogram_tester.ExpectUniqueSample(histogram_prefix + "Accepted", 2, 1);
   histogram_tester.ExpectUniqueSample(histogram_prefix + "CorrectedToSameType",
diff --git a/components/autofill_assistant/android/BUILD.gn b/components/autofill_assistant/android/BUILD.gn
index cd1c36d..ac4aa8b0 100644
--- a/components/autofill_assistant/android/BUILD.gn
+++ b/components/autofill_assistant/android/BUILD.gn
@@ -76,10 +76,8 @@
     "java/src/org/chromium/components/autofill_assistant/AssistantTagsForTesting.java",
     "java/src/org/chromium/components/autofill_assistant/AssistantTextLinkDelegate.java",
     "java/src/org/chromium/components/autofill_assistant/AssistantTextUtils.java",
-    "java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandlerImpl.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantDependencyInjector.java",
-    "java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectActionImpl.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryImpl.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantUiController.java",
     "java/src/org/chromium/components/autofill_assistant/BottomSheetUtils.java",
@@ -216,8 +214,6 @@
     "public/java/src/org/chromium/components/autofill_assistant/AssistantModuleInstallUi.java",
     "public/java/src/org/chromium/components/autofill_assistant/AssistantOnboardingHelper.java",
     "public/java/src/org/chromium/components/autofill_assistant/AssistantPaymentInstrumentEditorGms.java",
-    "public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandler.java",
-    "public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectAction.java",
     "public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantMetrics.java",
     "public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntry.java",
     "public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryProvider.java",
@@ -296,7 +292,6 @@
     "java/src/org/chromium/components/autofill_assistant/AssistantOnboardingHelperImpl.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantDependencyInjector.java",
-    "java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectActionImpl.java",
     "java/src/org/chromium/components/autofill_assistant/AutofillAssistantUiController.java",
     "java/src/org/chromium/components/autofill_assistant/carousel/AssistantChip.java",
     "java/src/org/chromium/components/autofill_assistant/details/AssistantDetails.java",
diff --git a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandlerImpl.java b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandlerImpl.java
deleted file mode 100644
index cfb7c03..0000000
--- a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandlerImpl.java
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.autofill_assistant;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import androidx.annotation.Nullable;
-
-import org.chromium.base.Callback;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.supplier.Supplier;
-import org.chromium.components.autofill_assistant.onboarding.AssistantOnboardingResult;
-import org.chromium.components.autofill_assistant.onboarding.BaseOnboardingCoordinator;
-import org.chromium.components.autofill_assistant.onboarding.OnboardingCoordinatorFactory;
-import org.chromium.components.autofill_assistant.overlay.AssistantOverlayCoordinator;
-import org.chromium.components.user_prefs.UserPrefs;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.ui.base.WindowAndroid;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A handler that provides Autofill Assistant actions for a specific activity.
- */
-public class AutofillAssistantActionHandlerImpl implements AutofillAssistantActionHandler {
-    private final OnboardingCoordinatorFactory mOnboardingCoordinatorFactory;
-    private final AssistantStaticDependencies mStaticDependencies;
-    private final Supplier<WebContents> mWebContentsSupplier;
-    // Encapsulates access to {@link PrefService} pref keys for Autofill Assistant.
-    private final AutofillAssistantPreferenceManager mPreferenceManager;
-
-    public AutofillAssistantActionHandlerImpl(
-            OnboardingCoordinatorFactory onboardingCoordinatorFactory,
-            Supplier<WebContents> webContentsSupplier,
-            AssistantStaticDependencies staticDependencies) {
-        mOnboardingCoordinatorFactory = onboardingCoordinatorFactory;
-        mWebContentsSupplier = webContentsSupplier;
-        mStaticDependencies = staticDependencies;
-        mPreferenceManager = new AutofillAssistantPreferenceManager(
-                UserPrefs.get(mStaticDependencies.getBrowserContext()));
-    }
-
-    @Override
-    public void fetchWebsiteActions(
-            String userName, String experimentIds, Bundle arguments, Callback<Boolean> callback) {
-        if (!mPreferenceManager.getOnboardingConsent()) {
-            callback.onResult(false);
-            return;
-        }
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) {
-            callback.onResult(false);
-            return;
-        }
-
-        client.fetchWebsiteActions(userName, experimentIds, toArgumentMap(arguments), callback);
-    }
-
-    @Override
-    public boolean hasRunFirstCheck() {
-        if (!mPreferenceManager.getOnboardingConsent()) {
-            return false;
-        }
-
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) return false;
-        return client.hasRunFirstCheck();
-    }
-
-    @Override
-    public List<AutofillAssistantDirectAction> getActions() {
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) {
-            return Collections.emptyList();
-        }
-        return client.getDirectActions();
-    }
-
-    @Override
-    public void performOnboarding(
-            String experimentIds, Bundle arguments, Callback<Boolean> callback) {
-        Map<String, String> parameters = toArgumentMap(arguments);
-        BaseOnboardingCoordinator coordinator =
-                mOnboardingCoordinatorFactory.createBottomSheetOnboardingCoordinator(
-                        experimentIds, parameters);
-        coordinator.show(result -> {
-            coordinator.hide();
-            callback.onResult(result == AssistantOnboardingResult.ACCEPTED);
-        });
-    }
-
-    @Override
-    public void performAction(
-            String name, String experimentIds, Bundle arguments, Callback<Boolean> callback) {
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) {
-            callback.onResult(false);
-            return;
-        }
-
-        Map<String, String> argumentMap = toArgumentMap(arguments);
-        Callback<AssistantOverlayCoordinator> afterOnboarding = (overlayCoordinator) -> {
-            callback.onResult(client.performDirectAction(
-                    name, experimentIds, argumentMap, overlayCoordinator));
-        };
-
-        if (!mPreferenceManager.getOnboardingConsent()) {
-            BaseOnboardingCoordinator coordinator =
-                    mOnboardingCoordinatorFactory.createBottomSheetOnboardingCoordinator(
-                            experimentIds, argumentMap);
-            coordinator.show(result -> {
-                if (result != AssistantOnboardingResult.ACCEPTED) {
-                    coordinator.hide();
-                    callback.onResult(false);
-                    return;
-                }
-                afterOnboarding.onResult(coordinator.transferControls());
-            });
-            return;
-        }
-        afterOnboarding.onResult(null);
-    }
-
-    @Override
-    public void showFatalError() {
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) {
-            return;
-        }
-        client.showFatalError();
-    }
-
-    @Override
-    public boolean isSupervisedUser() {
-        AutofillAssistantClient client = getOrCreateClient();
-        if (client == null) {
-            return false;
-        }
-        return client.isSupervisedUser();
-    }
-
-    /**
-     * Returns a client for the current tab or {@code null} if there's no current tab or the current
-     * tab doesn't have an associated browser content.
-     */
-    @Nullable
-    private AutofillAssistantClient getOrCreateClient() {
-        ThreadUtils.assertOnUiThread();
-
-        WebContents webContents = mWebContentsSupplier.get();
-        Activity activity = getActivityFromWebContents(webContents);
-        if (webContents == null || activity == null) {
-            return null;
-        }
-
-        return AutofillAssistantClient.createForWebContents(
-                webContents, mStaticDependencies.createDependencies(activity));
-    }
-
-    /**
-     * Looks up the Activity of the given web contents. This can be null. Should never be cached,
-     * because web contents can change activities, e.g., when user selects "Open in Chrome" menu
-     * item.
-     *
-     * @param webContents The web contents for which to lookup the Activity.
-     * @return Activity currently related to webContents. Could be <c>null</c> and could change,
-     *         therefore do not cache.
-     */
-    @Nullable
-    private static Activity getActivityFromWebContents(@Nullable WebContents webContents) {
-        if (webContents == null || webContents.isDestroyed()) return null;
-
-        WindowAndroid window = webContents.getTopLevelNativeWindow();
-        if (window == null) return null;
-
-        return window.getActivity().get();
-    }
-
-    /** Extracts string arguments from a bundle. */
-    private Map<String, String> toArgumentMap(Bundle bundle) {
-        Map<String, String> map = new HashMap<>();
-        for (String key : bundle.keySet()) {
-            String value = bundle.getString(key);
-            if (value != null) {
-                map.put(key, value);
-            }
-        }
-        return map;
-    }
-}
diff --git a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java
index 8daba2c..4a854623 100644
--- a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java
+++ b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantClient.java
@@ -11,11 +11,9 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.Callback;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.components.autofill_assistant.overlay.AssistantOverlayCoordinator;
 import org.chromium.components.autofill_assistant.user_data.GmsIntegrator;
 import org.chromium.components.signin.AccessTokenData;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -23,10 +21,7 @@
 import org.chromium.content.browser.accessibility.BrowserAccessibilityState;
 import org.chromium.content_public.browser.WebContents;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 /**
  * An Autofill Assistant client, associated with a specific WebContents.
@@ -113,69 +108,6 @@
                 mNativeClientAndroid, AutofillAssistantClient.this);
     }
 
-    /** Starts the controller and fetching scripts for websites. */
-    public void fetchWebsiteActions(String userName, String experimentIds,
-            Map<String, String> arguments, Callback<Boolean> callback) {
-        if (mNativeClientAndroid == 0) {
-            callback.onResult(false);
-            return;
-        }
-
-        chooseAccountAsyncIfNecessary(userName.isEmpty() ? null : userName);
-
-        // The native side calls sendDirectActionList() on the callback once the controller has
-        // results.
-        AutofillAssistantClientJni.get().fetchWebsiteActions(mNativeClientAndroid,
-                AutofillAssistantClient.this, experimentIds,
-                arguments.keySet().toArray(new String[arguments.size()]),
-                arguments.values().toArray(new String[arguments.size()]), callback);
-    }
-
-    /** Return true if the controller exists and is in tracking mode. */
-    public boolean hasRunFirstCheck() {
-        if (mNativeClientAndroid == 0) {
-            return false;
-        }
-
-        ThreadUtils.assertOnUiThread();
-        return AutofillAssistantClientJni.get().hasRunFirstCheck(
-                mNativeClientAndroid, AutofillAssistantClient.this);
-    }
-
-    /** Lists available direct actions. */
-    public List<AutofillAssistantDirectAction> getDirectActions() {
-        if (mNativeClientAndroid == 0) {
-            return Collections.emptyList();
-        }
-        AutofillAssistantDirectAction[] actions = AutofillAssistantClientJni.get().getDirectActions(
-                mNativeClientAndroid, AutofillAssistantClient.this);
-        return Arrays.asList(actions);
-    }
-
-    /**
-     * Performs a direct action.
-     *
-     * @param actionId id of the action
-     * @param experimentIds comma-separated set of experiments to use while running the flow
-     * @param arguments report these as script parameters while performing this specific action
-     * @param overlayCoordinator if non-null, reuse existing UI elements, usually created to show
-     *         onboarding.
-     * @return true if the action was found started, false otherwise. The action can still fail
-     * after this method returns true; the failure will be displayed on the UI.
-     */
-    public boolean performDirectAction(String actionId, String experimentIds,
-            Map<String, String> arguments,
-            @Nullable AssistantOverlayCoordinator overlayCoordinator) {
-        if (mNativeClientAndroid == 0) return false;
-
-        // Note that only fetchWebsiteActions can start AA, so only it needs
-        // chooseAccountAsyncIfNecessary.
-        return AutofillAssistantClientJni.get().performDirectAction(mNativeClientAndroid,
-                AutofillAssistantClient.this, actionId, experimentIds,
-                arguments.keySet().toArray(new String[arguments.size()]),
-                arguments.values().toArray(new String[arguments.size()]), overlayCoordinator);
-    }
-
     /**
      * Displays a generic error message. Intended for direct actions only, to let specific direct
      * actions show an error on failure.
@@ -358,12 +290,6 @@
         return Build.MODEL;
     }
 
-    /** Adds a dynamic action to the given reporter. */
-    @CalledByNative
-    private void onFetchWebsiteActions(Callback<Boolean> callback, boolean success) {
-        callback.onResult(success);
-    }
-
     @CalledByNative
     private void clearNativePtr() {
         mNativeClientAndroid = 0;
@@ -380,15 +306,6 @@
                 long nativeClientAndroid, AutofillAssistantClient caller, byte[] clientToken);
         String getPrimaryAccountName(long nativeClientAndroid, AutofillAssistantClient caller);
         void onJavaDestroyUI(long nativeClientAndroid, AutofillAssistantClient caller);
-        void fetchWebsiteActions(long nativeClientAndroid, AutofillAssistantClient caller,
-                String experimentIds, String[] argumentNames, String[] argumentValues,
-                Object callback);
-        boolean hasRunFirstCheck(long nativeClientAndroid, AutofillAssistantClient caller);
-        AutofillAssistantDirectAction[] getDirectActions(
-                long nativeClientAndroid, AutofillAssistantClient caller);
-        boolean performDirectAction(long nativeClientAndroid, AutofillAssistantClient caller,
-                String actionId, String experimentId, String[] argumentNames,
-                String[] argumentValues, @Nullable AssistantOverlayCoordinator overlayCoordinator);
         void showFatalError(long nativeClientAndroid, AutofillAssistantClient caller);
         boolean isSupervisedUser(long nativeClientAndroid, AutofillAssistantClient caller);
         void onSpokenFeedbackAccessibilityServiceChanged(
diff --git a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectActionImpl.java b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectActionImpl.java
deleted file mode 100644
index 6b43c4d..0000000
--- a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectActionImpl.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.autofill_assistant;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A container that corresponds to the DirectActionProto used to store action realated data like
- * arguments.
- */
-@JNINamespace("autofill_assistant")
-public class AutofillAssistantDirectActionImpl implements AutofillAssistantDirectAction {
-    /* List of direct actions with the given names. */
-    private final List<String> mNames;
-
-    /* List of required argument names for this action. */
-    private final List<String> mRequiredArguments;
-
-    /* List of optional argument names for this action. */
-    private final List<String> mOptionalArguments;
-
-    @CalledByNative
-    public AutofillAssistantDirectActionImpl(String[] names, String[] required, String[] optional) {
-        mNames = Arrays.asList(names);
-        mRequiredArguments = Arrays.asList(required);
-        mOptionalArguments = Arrays.asList(optional);
-    }
-
-    @Override
-    public List<String> getNames() {
-        return mNames;
-    }
-
-    @Override
-    public List<String> getRequiredArguments() {
-        return mRequiredArguments;
-    }
-
-    @Override
-    public List<String> getOptionalArguments() {
-        return mOptionalArguments;
-    }
-}
diff --git a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryImpl.java b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryImpl.java
index e3f6893..1eb1f90 100644
--- a/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryImpl.java
+++ b/components/autofill_assistant/android/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntryImpl.java
@@ -4,12 +4,6 @@
 
 package org.chromium.components.autofill_assistant;
 
-import android.content.Context;
-import android.view.View;
-
-import org.chromium.base.supplier.Supplier;
-import org.chromium.components.autofill_assistant.onboarding.OnboardingCoordinatorFactory;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.content_public.browser.WebContents;
 
 /**
@@ -22,18 +16,4 @@
             WebContents webContents, AssistantDependencies dependencies) {
         return new AssistantOnboardingHelperImpl(webContents, dependencies);
     }
-
-    @Override
-    public AutofillAssistantActionHandler createActionHandler(Context context,
-            BottomSheetController bottomSheetController,
-            AssistantBrowserControlsFactory browserControlsFactory, View rootView,
-            Supplier<WebContents> webContentsSupplier,
-            AssistantStaticDependencies staticDependencies) {
-        return new AutofillAssistantActionHandlerImpl(
-                new OnboardingCoordinatorFactory(context, bottomSheetController,
-                        staticDependencies.getBrowserContext(), browserControlsFactory, rootView,
-                        staticDependencies.getAccessibilityUtil(),
-                        staticDependencies.createInfoPageUtil()),
-                webContentsSupplier, staticDependencies);
-    }
 }
diff --git a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandler.java b/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandler.java
deleted file mode 100644
index 8fdc35c9..0000000
--- a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantActionHandler.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.autofill_assistant;
-
-import android.os.Bundle;
-
-import org.chromium.base.Callback;
-
-import java.util.List;
-
-/**
- * Interface that provides implementation for AA actions, triggered by direct actions.
- */
-public interface AutofillAssistantActionHandler {
-    /**
-     * Start fetching potential actions for websites.
-     *
-     * <p>This method starts AA on the current tab, if necessary, and waits for the first results.
-     * The method hasRunFirstCheck will return true when that's done. Note that {@code callback}
-     * will receive true if fetching actions was successful and the resulting set is not empty.
-     * <p>This method needs to be called before getActions below will return anything.
-     *
-     * @param userName name of the user to use when sending RPCs. Might be empty.
-     * @param experimentIds comma-separated set of experiment ids. Might be empty
-     * @param arguments extra arguments to include into the RPC. Might be empty.
-     * @param callback callback to report when actions are available.
-     */
-    void fetchWebsiteActions(
-            String userName, String experimentIds, Bundle arguments, Callback<Boolean> callback);
-
-    /**
-     * Returns if autofill assistant has fetched actions for the current URL.
-     *
-     * <p>This method queries the underlying Autofill Assistant stack to find out if it has been
-     * started and whether the first round of fetching scripts and checking availability has been
-     * completed.
-     *
-     * @return Whether scripts have been fetched and preconditions checked.
-     */
-    boolean hasRunFirstCheck();
-
-    /**
-     * Returns the available AA actions to be reported to the direct actions framework.
-     *
-     * <p>This method simply returns the list of actions known to AA. An empty string array means
-     * either that the controller has not yet been started or there are no actions available for the
-     * current website.
-     *
-     * @return Array of actions containing the names and arguments of known actions.
-     */
-    List<AutofillAssistantDirectAction> getActions();
-
-    /** Performs onboarding and returns the result to the callback. */
-    void performOnboarding(String experimentIds, Bundle arguments, Callback<Boolean> callback);
-
-    /**
-     * Performs an AA action.
-     *
-     * <p>If this method returns {@code true}, a definition for the action was successfully started.
-     * It can still fail later, and the failure will be reported to the UI.
-     *
-     * @param name action name, might be empty to autostart
-     * @param experimentIds comma-separated set of experiment ids. Might be empty.
-     * @param arguments extra arguments to pass to the action. Might be empty.
-     * @param callback to report the result to
-     */
-    void performAction(
-            String name, String experimentIds, Bundle arguments, Callback<Boolean> callback);
-
-    /**
-     * Displays a generic error message to the user.
-     */
-    void showFatalError();
-
-    /**
-     * Check whether the user is supervised.
-     * @return supervised state
-     */
-    boolean isSupervisedUser();
-}
diff --git a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectAction.java b/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectAction.java
deleted file mode 100644
index b99d5b1..0000000
--- a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantDirectAction.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.autofill_assistant;
-
-import java.util.List;
-
-/**
- * Interface for direct action containers.
- */
-public interface AutofillAssistantDirectAction {
-    /** Returns a list of name and aliases for this direct action. */
-    List<String> getNames();
-
-    /** Returns the list of required argument names. */
-    List<String> getRequiredArguments();
-
-    /** Returns the list of optional argument names. */
-    List<String> getOptionalArguments();
-}
diff --git a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntry.java b/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntry.java
index 3118ca3..33af909 100644
--- a/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntry.java
+++ b/components/autofill_assistant/android/public/java/src/org/chromium/components/autofill_assistant/AutofillAssistantModuleEntry.java
@@ -4,11 +4,6 @@
 
 package org.chromium.components.autofill_assistant;
 
-import android.content.Context;
-import android.view.View;
-
-import org.chromium.base.supplier.Supplier;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.module_installer.builder.ModuleInterface;
 import org.chromium.content_public.browser.WebContents;
 
@@ -25,21 +20,4 @@
      */
     AssistantOnboardingHelper createOnboardingHelper(
             WebContents webContents, AssistantDependencies dependencies);
-
-    /**
-     * Returns a {@link AutofillAssistantActionHandler} instance tied to the activity owning the
-     * given bottom sheet, and scrim view.
-     *
-     * @param context activity context
-     * @param bottomSheetController bottom sheet controller instance of the activity
-     * @param browserControlsFactory factory for providing browser controls state
-     * @param rootView root view of the activity
-     * @param webContentsSupplier supplier of the current WebContents
-     * @param staticDependencies used to create platform-specific dependencies
-     */
-    AutofillAssistantActionHandler createActionHandler(Context context,
-            BottomSheetController bottomSheetController,
-            AssistantBrowserControlsFactory browserControlsFactory, View rootView,
-            Supplier<WebContents> webContentsSupplier,
-            AssistantStaticDependencies staticDependencies);
 }
diff --git a/components/autofill_assistant/browser/android/client_android.cc b/components/autofill_assistant/browser/android/client_android.cc
index d48fc0a..6552d14 100644
--- a/components/autofill_assistant/browser/android/client_android.cc
+++ b/components/autofill_assistant/browser/android/client_android.cc
@@ -20,7 +20,6 @@
 #include "base/time/default_tick_clock.h"
 #include "components/autofill_assistant/android/jni_headers/AssistantParseSingleTagXmlUtilWrapper_jni.h"
 #include "components/autofill_assistant/android/jni_headers/AutofillAssistantClient_jni.h"
-#include "components/autofill_assistant/android/jni_headers/AutofillAssistantDirectActionImpl_jni.h"
 #include "components/autofill_assistant/browser/android/ui_controller_android_utils.h"
 #include "components/autofill_assistant/browser/autofill_assistant_tts_controller.h"
 #include "components/autofill_assistant/browser/controller.h"
@@ -222,158 +221,6 @@
   }
 }
 
-void ClientAndroid::FetchWebsiteActions(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jcaller,
-    const base::android::JavaParamRef<jstring>& jexperiment_ids,
-    const base::android::JavaParamRef<jobjectArray>& jparameter_names,
-    const base::android::JavaParamRef<jobjectArray>& jparameter_values,
-    const base::android::JavaParamRef<jobject>& jcallback) {
-  if (!controller_) {
-    CreateController(ui_controller_android_utils::GetServiceToInject(env, this),
-                     /* trigger_script= */ absl::nullopt);
-  }
-
-  base::android::ScopedJavaGlobalRef<jobject> scoped_jcallback(env, jcallback);
-  controller_->Track(
-      ui_controller_android_utils::CreateTriggerContext(
-          env, GetWebContents(), jexperiment_ids, jparameter_names,
-          jparameter_values, /* jdevice_only_parameter_names= */
-          base::android::JavaParamRef<jobjectArray>(nullptr),
-          /* jdevice_only_parameter_values= */
-          base::android::JavaParamRef<jobjectArray>(nullptr),
-          /* onboarding_shown = */ false,
-          /* is_direct_action = */ true,
-          /* jinitial_url = */ nullptr,
-          /* is_custom_tab = */
-          dependencies_->GetPlatformDependencies()->IsCustomTab(
-              *GetWebContents())),
-      base::BindOnce(&ClientAndroid::OnFetchWebsiteActions,
-                     weak_ptr_factory_.GetWeakPtr(), scoped_jcallback));
-}
-
-bool ClientAndroid::HasRunFirstCheck(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jcaller) const {
-  return controller_ != nullptr && controller_->HasRunFirstCheck();
-}
-
-base::android::ScopedJavaLocalRef<jobjectArray>
-ClientAndroid::GetDirectActionsAsJavaArrayOfStrings(JNIEnv* env) const {
-  // Using a set here helps remove duplicates.
-  std::set<std::string> names;
-
-  if (!controller_) {
-    return base::android::ToJavaArrayOfStrings(
-        env, std::vector<std::string>(names.begin(), names.end()));
-  }
-
-  for (const ScriptHandle& script : controller_->GetDirectActionScripts()) {
-    for (const std::string& name : script.direct_action.names) {
-      names.insert(name);
-    }
-  }
-
-  return base::android::ToJavaArrayOfStrings(
-      env, std::vector<std::string>(names.begin(), names.end()));
-}
-
-base::android::ScopedJavaLocalRef<jobject>
-ClientAndroid::ToJavaAutofillAssistantDirectAction(
-    JNIEnv* env,
-    const DirectAction& direct_action) const {
-  std::set<std::string> names;
-  for (const std::string& name : direct_action.names)
-    names.insert(name);
-  auto jnames = base::android::ToJavaArrayOfStrings(
-      env, std::vector<std::string>(names.begin(), names.end()));
-
-  std::vector<std::string> required_arguments;
-  for (const std::string& arg : direct_action.required_arguments)
-    required_arguments.emplace_back(arg);
-  auto jrequired_arguments =
-      base::android::ToJavaArrayOfStrings(env, required_arguments);
-
-  std::vector<std::string> optional_arguments;
-  for (const std::string& arg : direct_action.optional_arguments)
-    optional_arguments.emplace_back(arg);
-  auto joptional_arguments =
-      base::android::ToJavaArrayOfStrings(env, std::move(optional_arguments));
-
-  return Java_AutofillAssistantDirectActionImpl_Constructor(
-      env, jnames, jrequired_arguments, joptional_arguments);
-}
-
-base::android::ScopedJavaLocalRef<jobjectArray> ClientAndroid::GetDirectActions(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jcaller) {
-  DCHECK(controller_ != nullptr);
-  // Prepare the java array to hold the direct actions.
-  base::android::ScopedJavaLocalRef<jclass> directaction_array_class =
-      base::android::GetClass(env,
-                              "org/chromium/components/autofill_assistant/"
-                              "AutofillAssistantDirectActionImpl",
-                              "autofill_assistant");
-
-  const std::vector<ScriptHandle>& direct_action_scripts =
-      controller_->GetDirectActionScripts();
-
-  jobjectArray joa = env->NewObjectArray(
-      direct_action_scripts.size(), directaction_array_class.obj(), nullptr);
-  jni_generator::CheckException(env);
-
-  for (size_t i = 0; i < direct_action_scripts.size(); i++) {
-    auto jdirect_action = ToJavaAutofillAssistantDirectAction(
-        env, direct_action_scripts.at(i).direct_action);
-    env->SetObjectArrayElement(joa, i, jdirect_action.obj());
-  }
-  return base::android::ScopedJavaLocalRef<jobjectArray>(env, joa);
-}
-
-void ClientAndroid::OnFetchWebsiteActions(
-    const base::android::JavaRef<jobject>& jcallback) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_AutofillAssistantClient_onFetchWebsiteActions(
-      env, java_object_, jcallback, controller_ != nullptr);
-}
-
-bool ClientAndroid::PerformDirectAction(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& jcaller,
-    const base::android::JavaParamRef<jstring>& jaction_name,
-    const base::android::JavaParamRef<jstring>& jexperiment_ids,
-    const base::android::JavaParamRef<jobjectArray>& jparameter_names,
-    const base::android::JavaParamRef<jobjectArray>& jparameter_values,
-    const base::android::JavaParamRef<jobject>& joverlay_coordinator) {
-  std::string action_name =
-      base::android::ConvertJavaStringToUTF8(env, jaction_name);
-
-  auto trigger_context = ui_controller_android_utils::CreateTriggerContext(
-      env, GetWebContents(), jexperiment_ids, jparameter_names,
-      jparameter_values, /* jdevice_only_parameter_names= */
-      base::android::JavaParamRef<jobjectArray>(nullptr),
-      /* jdevice_only_parameter_values= */
-      base::android::JavaParamRef<jobjectArray>(nullptr),
-      /* onboarding_shown = */ false,
-      /* is_direct_action = */ true,
-      /* jinitial_url = */
-      nullptr,
-      /* is_custom_tab = */
-      dependencies_->GetPlatformDependencies()->IsCustomTab(*GetWebContents()));
-
-  int action_index = FindDirectAction(action_name);
-  if (action_index == -1)
-    return false;
-
-  // If an overlay is already shown, then show the rest of the UI immediately.
-  if (joverlay_coordinator) {
-    AttachUI(joverlay_coordinator);
-  }
-
-  return controller_->PerformDirectAction(action_index,
-                                          std::move(trigger_context));
-}
-
 void ClientAndroid::ShowFatalError(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller) {
@@ -423,24 +270,6 @@
   return jdependencies_;
 }
 
-int ClientAndroid::FindDirectAction(const std::string& action_name) {
-  // It's too late to create a controller. This should have been done in
-  // FetchWebsiteActions.
-  if (!controller_)
-    return -1;
-
-  const std::vector<ScriptHandle>& direct_action_scripts =
-      controller_->GetDirectActionScripts();
-  for (size_t i = 0; i < direct_action_scripts.size(); i++) {
-    const base::flat_set<std::string>& action_names =
-        direct_action_scripts.at(i).direct_action.names;
-    if (action_names.count(action_name) != 0)
-      return i;
-  }
-
-  return -1;
-}
-
 void ClientAndroid::AttachUI() {
   AttachUI(nullptr);
 }
@@ -777,10 +606,6 @@
   started_ = false;
 }
 
-bool ClientAndroid::NeedsUI() {
-  return !ui_controller_android_ && controller_ && controller_->NeedsUI();
-}
-
 bool ClientAndroid::GetMakeSearchesAndBrowsingBetterEnabled() const {
   return dependencies_->GetCommonDependencies()
       ->GetMakeSearchesAndBrowsingBetterEnabled();
diff --git a/components/autofill_assistant/browser/android/client_android.h b/components/autofill_assistant/browser/android/client_android.h
index 0860add80..9ce2a02 100644
--- a/components/autofill_assistant/browser/android/client_android.h
+++ b/components/autofill_assistant/browser/android/client_android.h
@@ -79,31 +79,6 @@
       const base::android::JavaParamRef<jobject>& jcaller,
       const base::android::JavaParamRef<jbyteArray>& jclient_token);
 
-  void FetchWebsiteActions(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jcaller,
-      const base::android::JavaParamRef<jstring>& jexperiment_ids,
-      const base::android::JavaParamRef<jobjectArray>& jargument_names,
-      const base::android::JavaParamRef<jobjectArray>& jargument_values,
-      const base::android::JavaParamRef<jobject>& jcallback);
-
-  bool HasRunFirstCheck(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jcaller) const;
-
-  base::android::ScopedJavaLocalRef<jobjectArray> GetDirectActions(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jcaller);
-
-  bool PerformDirectAction(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jcaller,
-      const base::android::JavaParamRef<jstring>& jaction_id,
-      const base::android::JavaParamRef<jstring>& jexperiment_ids,
-      const base::android::JavaParamRef<jobjectArray>& jargument_names,
-      const base::android::JavaParamRef<jobjectArray>& jargument_values,
-      const base::android::JavaParamRef<jobject>& joverlay_coordinator);
-
   void ShowFatalError(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& jcaller);
 
@@ -176,21 +151,8 @@
       const absl::optional<TriggerScriptProto>& trigger_script);
   void DestroyController();
   void AttachUI(const base::android::JavaRef<jobject>& joverlay_coordinator);
-  bool NeedsUI();
-  void OnFetchWebsiteActions(const base::android::JavaRef<jobject>& jcallback);
   void SafeDestroyControllerAndUI(Metrics::DropOutReason reason);
 
-  base::android::ScopedJavaLocalRef<jobjectArray>
-  GetDirectActionsAsJavaArrayOfStrings(JNIEnv* env) const;
-
-  base::android::ScopedJavaLocalRef<jobject>
-  ToJavaAutofillAssistantDirectAction(JNIEnv* env,
-                                      const DirectAction& direct_action) const;
-
-  // Returns the index of a direct action with that name, to pass to
-  // UiDelegate::PerformUserAction() or -1 if not found.
-  int FindDirectAction(const std::string& action_name);
-
   void OnAnnotateDomModelFileAvailable(
       base::OnceCallback<void(absl::optional<int64_t>)> callback,
       bool available);
diff --git a/components/autofill_assistant/browser/android/ui_controller_android.cc b/components/autofill_assistant/browser/android/ui_controller_android.cc
index 201355b..bfb262dd 100644
--- a/components/autofill_assistant/browser/android/ui_controller_android.cc
+++ b/components/autofill_assistant/browser/android/ui_controller_android.cc
@@ -507,19 +507,6 @@
       ResetGenericUiControllers();
       return;
 
-    case AutofillAssistantState::TRACKING:
-      SetOverlayState(OverlayState::HIDDEN);
-      SetSpinPoodle(false);
-
-      if (!execution_delegate_->NeedsUI()) {
-        Java_AssistantModel_setVisible(AttachCurrentThread(), GetModel(),
-                                       false);
-        DestroySelf();
-      } else if (execution_delegate_->IsTabSelected()) {
-        ShowContentAndExpandBottomSheet();
-      }
-      return;
-
     case AutofillAssistantState::INACTIVE:
       // Wait for the state to change.
       return;
@@ -895,8 +882,7 @@
   // Special case: don't create a default cancel chip during shutdown.
   if (!has_close_or_cancel && !ui_delegate_->IsUiShuttingDown()) {
     base::android::ScopedJavaLocalRef<jobject> jcancel_chip;
-    if (execution_delegate_->GetState() == AutofillAssistantState::STOPPED ||
-        execution_delegate_->GetState() == AutofillAssistantState::TRACKING) {
+    if (execution_delegate_->GetState() == AutofillAssistantState::STOPPED) {
       jcancel_chip = Java_AutofillAssistantUiController_createCloseButton(
           env, java_object_, static_cast<int>(CLOSE_ACTION), ICON_CLEAR,
           ConvertUTF8ToJavaString(env, ""),
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index de59a77..d0284a1 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -170,10 +170,6 @@
   touchable_element_area()->SetFromProto(area);
 }
 
-const std::vector<ScriptHandle>& Controller::GetDirectActionScripts() const {
-  return direct_action_scripts_;
-}
-
 bool Controller::IsNavigatingToNewDocument() {
   return navigating_to_new_document_;
 }
@@ -260,24 +256,6 @@
   browse_domains_allowlist_ = std::move(domains);
 }
 
-bool Controller::PerformDirectAction(int index,
-                                     std::unique_ptr<TriggerContext> context) {
-  if (index < 0 ||
-      static_cast<size_t>(index) >= direct_action_scripts_.size()) {
-    NOTREACHED() << "Invalid direct action index: " << index;
-    return false;
-  }
-
-  ScriptHandle handle = direct_action_scripts_.at(index);
-  direct_action_scripts_.clear();
-  ExecuteScript(handle.path, handle.start_message, handle.needs_ui,
-                std::move(context),
-                state_ == AutofillAssistantState::TRACKING
-                    ? AutofillAssistantState::TRACKING
-                    : AutofillAssistantState::PROMPT);
-  return true;
-}
-
 void Controller::SetViewportMode(ViewportMode mode) {
   if (mode == viewport_mode_)
     return;
@@ -360,15 +338,10 @@
 }
 
 void Controller::ShutdownIfNecessary() {
-  if (!tracking_) {
-    // We expect the DropOutReason to be already reported when we reach this
-    // point and therefore the reason we pass here in the argument should be
-    // ignored.
-    Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY);
-  } else if (NeedsUI()) {
-    needs_ui_ = false;
-    client_->DestroyUISoon();
-  }
+  // We expect the DropOutReason to be already reported when we reach this
+  // point and therefore the reason we pass here in the argument should be
+  // ignored.
+  Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY);
 }
 
 void Controller::EnterBrowseModeForShutdown() {
@@ -404,10 +377,8 @@
 
   VLOG(2) << __func__ << ": " << state_ << " -> " << state;
 
-  // The only valid way of leaving the STOPPED state is to go back to tracking
-  // mode.
-  DCHECK(state_ != AutofillAssistantState::STOPPED ||
-         (state == AutofillAssistantState::TRACKING && tracking_));
+  // Leaving the STOPPED state is not allowed.
+  DCHECK(state_ != AutofillAssistantState::STOPPED);
   state_ = state;
 
   bool should_suppress_keyboard = ShouldSuppressKeyboard();
@@ -439,17 +410,12 @@
 }
 
 void Controller::OnUrlChange() {
-  if (state_ == AutofillAssistantState::STOPPED) {
-    PerformDelayedShutdownIfNecessary();
-    return;
-  }
   user_model_.SetCurrentURL(GetCurrentURL());
   GetOrCheckScripts();
 }
 
 bool Controller::ShouldCheckScripts() {
-  return state_ == AutofillAssistantState::TRACKING ||
-         state_ == AutofillAssistantState::STARTING ||
+  return state_ == AutofillAssistantState::STARTING ||
          ((state_ == AutofillAssistantState::PROMPT ||
            state_ == AutofillAssistantState::BROWSE) &&
           (!script_tracker_ || !script_tracker_->running()));
@@ -646,13 +612,6 @@
 
   if (scripts.empty()) {
     script_tracker()->SetScripts({});
-
-    if (state_ == AutofillAssistantState::TRACKING) {
-      OnFatalError(GetDisplayStringUTF8(ClientSettingsProto::DEFAULT_ERROR,
-                                        GetSettings()),
-                   Metrics::DropOutReason::NO_SCRIPTS);
-      return;
-    }
     OnNoRunnableScriptsForPage();
   }
 
@@ -667,19 +626,8 @@
                                AutofillAssistantState end_state) {
   DCHECK(!script_tracker()->running());
 
-  // To prevent state from persisting across direct actions, we need to
-  // explicitly clear it each time before we run a script (b/195417453). Note
-  // that for cases where a JITT script transitions into a regular script,
-  // preserving state is important, so we can't clear this indiscriminately.
-  if (context->GetDirectAction()) {
-    ResetState();
-  }
-
   if (needs_ui) {
     RequireUI();
-  } else if (needs_ui_ && state_ == AutofillAssistantState::TRACKING) {
-    needs_ui_ = false;
-    client_->DestroyUI();
   }
   EnterState(AutofillAssistantState::RUNNING);
 
@@ -691,7 +639,6 @@
   // Runnable scripts will be checked and reported if necessary after executing
   // the script.
   script_tracker_->ClearRunnableScripts();
-  direct_action_scripts_.clear();
 
   script_tracker()->ExecuteScript(
       script_path, &user_data_, std::move(context),
@@ -722,43 +669,21 @@
 
   switch (result.at_end) {
     case ScriptExecutor::SHUTDOWN:
-      if (!tracking_) {
-        Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
-        return;
-      }
-      needs_ui_ = false;
-      end_state = AutofillAssistantState::TRACKING;
-      break;
-
+      Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
+      return;
     case ScriptExecutor::SHUTDOWN_GRACEFULLY:
-      if (!tracking_) {
-        EnterStoppedState();
-        RecordDropOutOrShutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
-        return;
-      }
-      needs_ui_ = true;
-      SetStoppedUI();
-      end_state = AutofillAssistantState::TRACKING;
-      break;
-
+      EnterStoppedState();
+      RecordDropOutOrShutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
+      return;
     case ScriptExecutor::CLOSE_CUSTOM_TAB:
       for (ControllerObserver& observer : observers_) {
         observer.CloseCustomTab();
       }
-      if (!tracking_) {
-        Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED);
-        return;
-      }
-      needs_ui_ = false;
-      end_state = AutofillAssistantState::TRACKING;
+      Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED);
       return;
-
     case ScriptExecutor::CONTINUE:
-      if (end_state == AutofillAssistantState::TRACKING) {
-        needs_ui_ = false;
-      }
+      // Do nothing.
       break;
-
     default:
       VLOG(1) << "Unexpected value for at_end: " << result.at_end;
       break;
@@ -766,15 +691,6 @@
   EnterState(end_state);
 }
 
-void Controller::ResetState() {
-  viewport_mode_ = ViewportMode::NO_RESIZE;
-  overlay_behavior_ = ConfigureUiStateProto::DEFAULT;
-  touchable_element_area()->Clear();
-  for (ControllerObserver& observer : observers_) {
-    observer.OnResetState();
-  }
-}
-
 void Controller::MaybeAutostartScript(
     const std::vector<ScriptHandle>& runnable_scripts) {
   // We are still waiting for preconditions to match.
@@ -795,7 +711,6 @@
   }
 
   if (autostart_index == -1) {
-    SetDirectActionScripts(runnable_scripts);
     return;
   }
 
@@ -862,36 +777,9 @@
       trigger_context_->GetScriptParameters().GetDisableRpcSigning());
 }
 
-void Controller::Track(std::unique_ptr<TriggerContext> trigger_context,
-                       base::OnceCallback<void()> on_first_check_done) {
-  tracking_ = true;
-
-  if (state_ == AutofillAssistantState::INACTIVE) {
-    trigger_context_ = std::move(trigger_context);
-    InitFromParameters();
-    for (ControllerObserver& observer : observers_) {
-      observer.OnStart(*GetTriggerContext());
-    }
-    EnterState(AutofillAssistantState::TRACKING);
-  }
-
-  if (on_first_check_done) {
-    if (has_run_first_check_) {
-      std::move(on_first_check_done).Run();
-    } else {
-      on_has_run_first_check_.emplace_back(std::move(on_first_check_done));
-    }
-  }
-}
-
-bool Controller::HasRunFirstCheck() const {
-  return tracking_ && has_run_first_check_;
-}
-
 bool Controller::Start(const GURL& deeplink_url,
                        std::unique_ptr<TriggerContext> trigger_context) {
-  if (state_ != AutofillAssistantState::INACTIVE &&
-      state_ != AutofillAssistantState::TRACKING) {
+  if (state_ != AutofillAssistantState::INACTIVE) {
     return false;
   }
 
@@ -904,10 +792,6 @@
     return false;
   }
 
-  // Force a re-evaluation of the script, to get a chance to autostart.
-  if (state_ == AutofillAssistantState::TRACKING)
-    script_tracker_->ClearRunnableScripts();
-
   if (IsNavigatingToNewDocument()) {
     start_after_navigation_ = base::BindOnce(
         &Controller::ShowFirstMessageAndStart, weak_ptr_factory_.GetWeakPtr());
@@ -950,7 +834,6 @@
     case AutofillAssistantState::BROWSE:
     case AutofillAssistantState::MODAL_DIALOG:
     case AutofillAssistantState::STOPPED:
-    case AutofillAssistantState::TRACKING:
     case AutofillAssistantState::INACTIVE:
       return false;
   }
@@ -1000,11 +883,6 @@
   }
   EnterStoppedState();
 
-  if (tracking_) {
-    EnterState(AutofillAssistantState::TRACKING);
-    return;
-  }
-
   RecordDropOutOrShutdown(reason);
 }
 
@@ -1021,18 +899,6 @@
   }
   EnterStoppedState();
 
-  // If we haven't managed to check the set of scripts yet at this point, we
-  // never will.
-  MaybeReportFirstCheckDone();
-
-  if (tracking_ && script_url_.host() == GetCurrentURL().host()) {
-    // When tracking the controller should stays until the browser has navigated
-    // away from the last domain that was checked to be able to tell callers
-    // that the set of user actions is empty.
-    delayed_shutdown_reason_ = reason;
-    return;
-  }
-
   RecordDropOutOrShutdown(reason);
 }
 
@@ -1049,28 +915,6 @@
   }
 }
 
-void Controller::PerformDelayedShutdownIfNecessary() {
-  if (delayed_shutdown_reason_ &&
-      script_url_.host() != GetCurrentURL().host()) {
-    Metrics::DropOutReason reason = delayed_shutdown_reason_.value();
-    delayed_shutdown_reason_ = absl::nullopt;
-    tracking_ = false;
-    Shutdown(reason);
-  }
-}
-
-void Controller::MaybeReportFirstCheckDone() {
-  if (has_run_first_check_)
-    return;
-
-  has_run_first_check_ = true;
-
-  while (!on_has_run_first_check_.empty()) {
-    std::move(on_has_run_first_check_.back()).Run();
-    on_has_run_first_check_.pop_back();
-  }
-}
-
 void Controller::OnNoRunnableScriptsForPage() {
   if (script_tracker()->running())
     return;
@@ -1101,17 +945,6 @@
   }
 }
 
-void Controller::SetDirectActionScripts(
-    const std::vector<ScriptHandle>& runnable_scripts) {
-  direct_action_scripts_.clear();
-  for (const auto& script : runnable_scripts) {
-    if (script.direct_action.empty())
-      continue;
-
-    direct_action_scripts_.push_back(script);
-  }
-}
-
 void Controller::SetSemanticSelectorPolicy(SemanticSelectorPolicy policy) {
   DCHECK(annotate_dom_model_service_);
   if (!annotate_dom_model_service_->SetOverridesPolicy(std::move(policy))) {
@@ -1121,32 +954,15 @@
 
 void Controller::OnRunnableScriptsChanged(
     const std::vector<ScriptHandle>& runnable_scripts) {
-  base::ScopedClosureRunner report_first_check;
-  if (!has_run_first_check_) {
-    // Only report first check done once we're done processing the given set of
-    // scripts - whatever the outcome - so callers can see that outcome in the
-    // state of the controller.
-    report_first_check.ReplaceClosure(
-        base::BindOnce(&Controller::MaybeReportFirstCheckDone,
-                       weak_ptr_factory_.GetWeakPtr()));
-  }
-
   // Script selection is disabled when a script is already running. We will
   // check again and maybe update when the current script has finished.
   if (script_tracker()->running())
     return;
 
-  switch (state_) {
-    case AutofillAssistantState::STARTING:
-      MaybeAutostartScript(runnable_scripts);
-      return;
-    case AutofillAssistantState::TRACKING:
-      SetDirectActionScripts(runnable_scripts);
-      return;
-    default:
-      // In other states we ignore the script update.
-      break;
+  if (state_ == AutofillAssistantState::STARTING) {
+    MaybeAutostartScript(runnable_scripts);
   }
+  // In other states we ignore the script update.
 }
 
 void Controller::DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -1239,15 +1055,6 @@
     return;
   }
 
-  // When in TRACKING state all navigation is allowed, but user-initiated
-  // navigation will close the UI if any.
-  if (state_ == AutofillAssistantState::TRACKING &&
-      is_user_initiated_or_back_forward &&
-      !navigation_handle->WasServerRedirect()) {
-    ShutdownIfNecessary();
-    return;
-  }
-
   // Note that BROWSE state end conditions are in DidFinishNavigation, in order
   // to be able to properly evaluate the committed url.
 }
@@ -1270,7 +1077,6 @@
         return;
       }
       break;
-    case AutofillAssistantState::TRACKING:
     case AutofillAssistantState::STOPPED:
     case AutofillAssistantState::INACTIVE:
       break;
@@ -1407,7 +1213,6 @@
       return true;
 
     case AutofillAssistantState::INACTIVE:
-    case AutofillAssistantState::TRACKING:
     case AutofillAssistantState::STOPPED:
     case AutofillAssistantState::RUNNING:
       return false;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index e879208..a20d044 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -79,23 +79,6 @@
 
   ~Controller() override;
 
-  // Let the controller know it should keep tracking script availability for the
-  // current domain, to be ready to report any scripts as action.
-  //
-  // Activates the controller, if needed and runs it in the background, without
-  // showing any UI until a script is started or Start() is called.
-  //
-  // Only the context of the first call to Track() is taken into account.
-  //
-  // If non-null |on_first_check_done| is called once the result of the first
-  // check of script availability are in - whether they're positive or negative.
-  void Track(std::unique_ptr<TriggerContext> trigger_context,
-             base::OnceCallback<void()> on_first_check_done);
-
-  // Returns true if we are in tracking mode and the first round of script
-  // checks has been completed.
-  bool HasRunFirstCheck() const;
-
   // Called when autofill assistant should start.
   //
   // This shows a UI, containing a progress bar, and executes the first
@@ -103,13 +86,9 @@
   //
   // Start() does nothing if called more than once or if a script is already
   // running.
-  //
-  // Start() will overwrite any context previously set by Track().
   bool Start(const GURL& deeplink_url,
              std::unique_ptr<TriggerContext> trigger_context);
 
-  const std::vector<ScriptHandle>& GetDirectActionScripts() const;
-  bool PerformDirectAction(int index, std::unique_ptr<TriggerContext> context);
   base::Value GetDebugContext();
 
   // Overrides ScriptExecutorDelegate:
@@ -176,7 +155,6 @@
                                    Metrics::DropOutReason reason);
 
   // Overrides ExecutionDelegate:
-  bool NeedsUI() const override;
   void GetVisualViewport(RectF* visual_viewport) const override;
   ViewportMode GetViewportMode() override;
   bool IsTabSelected() override;
@@ -241,8 +219,6 @@
   void StopPeriodicScriptChecks();
   void OnPeriodicScriptCheck();
 
-  void MaybeReportFirstCheckDone();
-
   // Runs autostart scripts from |runnable_scripts|, if the conditions are
   // right. Nothing happens if an empty vector is passed.
   // If none of the scripts is autostartable or too many are, it stops the
@@ -302,14 +278,11 @@
   bool allow_autostart() { return state_ == AutofillAssistantState::STARTING; }
 
   void RecordDropOutOrShutdown(Metrics::DropOutReason reason);
-  void PerformDelayedShutdownIfNecessary();
 
   bool StateNeedsUI(AutofillAssistantState state);
 
   // Resets the controller to the initial state.
   void ResetState();
-  void SetDirectActionScripts(
-      const std::vector<ScriptHandle>& direct_action_scripts);
 
   // Records flow metrics. This may be invoked multiple times per flow, but will
   // only record the first impression for each flow.
@@ -324,6 +297,8 @@
       absl::optional<int64_t> model_version);
   void GetScriptsForUrl(const GURL& url);
 
+  bool NeedsUI() const;
+
   ClientSettings settings_;
   const raw_ptr<Client> client_;
   const raw_ptr<const base::TickClock> tick_clock_;
@@ -373,9 +348,6 @@
   // Lazily instantiate in touchable_element_area().
   std::unique_ptr<ElementArea> touchable_element_area_;
 
-  // Current set of direct actions.
-  std::vector<ScriptHandle> direct_action_scripts_;
-
   // Current viewport mode.
   ViewportMode viewport_mode_ = ViewportMode::NO_RESIZE;
 
@@ -411,41 +383,16 @@
 
   base::ObserverList<ControllerObserver> observers_;
 
-  // If true, the controller is supposed to stay up and running in the
-  // background even without UI, keeping track of scripts.
-  //
-  // This has two main effects:
-  // - the controllers stays alive even after a fatal error, just so it can
-  // immediately report that no actions are available on that website.
-  // - scripts error are not considered fatal errors. The controller reverts
-  // to TRACKING mode.
-  //
-  // This is set by Track().
-  bool tracking_ = false;
-
   // Whether the controller is in a state in which a UI should be shown.
   bool needs_ui_ = false;
 
   // Whether UI is shown.
   bool ui_shown_ = false;
 
-  // True once the controller has run the first set of scripts and have either
-  // declared it invalid - and entered stopped state - or have processed its
-  // result - and updated the state and set of available actions.
-  bool has_run_first_check_ = false;
-
   // Whether the overlay should be set according to state or always hidden.
   ConfigureUiStateProto::OverlayBehavior overlay_behavior_ =
       ConfigureUiStateProto::DEFAULT;
 
-  // Callbacks to call when |has_run_first_check_| becomes true.
-  std::vector<base::OnceCallback<void()>> on_has_run_first_check_;
-
-  // If set, the controller entered the STOPPED state but shutdown was delayed
-  // until the browser has left the |script_url_.host()| for which the decision
-  // was taken.
-  absl::optional<Metrics::DropOutReason> delayed_shutdown_reason_;
-
   UserModel user_model_;
 
   std::vector<std::string> browse_domains_allowlist_;
diff --git a/components/autofill_assistant/browser/controller_observer.h b/components/autofill_assistant/browser/controller_observer.h
index 7aa71127..d3aede0 100644
--- a/components/autofill_assistant/browser/controller_observer.h
+++ b/components/autofill_assistant/browser/controller_observer.h
@@ -92,9 +92,6 @@
   // Called when the flow is stopped.
   virtual void OnStop() = 0;
 
-  // Called when the state needs to be reset.
-  virtual void OnResetState() = 0;
-
   // Called whenever the UI is shown or hidden.
   virtual void OnUiShownChanged(bool shown) = 0;
 };
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index c8a23903..074ec0b 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -171,14 +171,10 @@
  protected:
   static SupportedScriptProto* AddRunnableScript(
       SupportsScriptResponseProto* response,
-      const std::string& name_and_path,
-      bool direct_action = true) {
+      const std::string& name_and_path) {
     SupportedScriptProto* script = response->add_scripts();
     script->set_path(name_and_path);
-    if (direct_action) {
-      script->mutable_presentation()->mutable_direct_action()->add_names(
-          name_and_path);
-    }
+    script->mutable_presentation()->set_autostart(true);
     return script;
   }
 
@@ -218,11 +214,6 @@
     controller_->Start(url, std::move(trigger_context));
   }
 
-  void Track() {
-    SetLastCommittedUrl(GURL("http://initialurl.com"));
-    controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  }
-
   void SetLastCommittedUrl(const GURL& url) {
     content::WebContentsTester::For(web_contents())->SetLastCommittedURL(url);
   }
@@ -330,76 +321,6 @@
   events.emplace_back(state);
 }
 
-TEST_F(ControllerTest, ReportDirectActions) {
-  SupportsScriptResponseProto script_response;
-
-  AddRunnableScript(&script_response, "action");
-
-  SetNextScriptResponse(script_response);
-
-  testing::InSequence seq;
-
-  Track();
-
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(),
-              UnorderedElementsAre(AllOf(
-                  Field(&ScriptHandle::direct_action,
-                        Field(&DirectAction::names, ElementsAre("action"))))));
-}
-
-TEST_F(ControllerTest, RunDirectActionWithArguments) {
-  SupportsScriptResponseProto script_response;
-
-  // script is available as a direct action.
-  auto* script1 = AddRunnableScript(&script_response, "action");
-  auto* action = script1->mutable_presentation()->mutable_direct_action();
-  action->add_required_arguments("required");
-  action->add_optional_arguments("arg0");
-  action->add_optional_arguments("arg1");
-
-  SetNextScriptResponse(script_response);
-
-  testing::InSequence seq;
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(),
-              ElementsAre(Field(
-                  &ScriptHandle::direct_action,
-                  AllOf(Field(&DirectAction::names, ElementsAre("action")),
-                        Field(&DirectAction::required_arguments,
-                              ElementsAre("required")),
-                        Field(&DirectAction::optional_arguments,
-                              ElementsAre("arg0", "arg1"))))));
-
-  EXPECT_CALL(*mock_service_, GetActions("action", _, _, _, _, _))
-      .WillOnce([](const std::string& script_path, const GURL& url,
-                   const TriggerContext& trigger_context,
-                   const std::string& global_payload,
-                   const std::string& script_payload,
-                   ServiceRequestSender::ResponseCallback callback) {
-        EXPECT_THAT(trigger_context.GetScriptParameters().ToProto(),
-                    testing::UnorderedElementsAreArray(
-                        base::flat_map<std::string, std::string>(
-                            {{"required", "value"}, {"arg0", "value0"}})));
-        EXPECT_TRUE(trigger_context.GetDirectAction());
-
-        std::move(callback).Run(true, "", ServiceRequestSender::ResponseInfo{});
-      });
-
-  TriggerContext::Options options;
-  options.is_direct_action = true;
-  EXPECT_TRUE(controller_->PerformDirectAction(
-      0, std::make_unique<TriggerContext>(
-             /* parameters = */ std::make_unique<ScriptParameters>(
-                 base::flat_map<std::string, std::string>{{"required", "value"},
-                                                          {"arg0", "value0"}}),
-             options)));
-}
-
 TEST_F(ControllerTest, NoScripts) {
   SupportsScriptResponseProto empty;
   SetNextScriptResponse(empty);
@@ -437,28 +358,6 @@
   EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
 }
 
-TEST_F(ControllerTest, ClearDirectActionsWhenRunning) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "script1");
-  AddRunnableScript(&script_response, "script2");
-
-  ActionsResponseProto runnable_script;
-  auto* prompt_action = runnable_script.add_actions()->mutable_prompt();
-  prompt_action->add_choices()->mutable_chip()->set_text("continue");
-
-  SetupActionsForScript("script1", runnable_script);
-  SetNextScriptResponse(script_response);
-
-  Track();
-  // We initially have 2 direct action scripts available.
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(2));
-  // We execute one of them.
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  // There are no direct actions available once the script is running.
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(0));
-}
-
 TEST_F(ControllerTest, ScriptStartMessage) {
   SupportsScriptResponseProto script_response;
   auto* script = AddRunnableScript(&script_response, "script");
@@ -468,11 +367,8 @@
   ActionsResponseProto script_actions;
   SetupActionsForScript("script", script_actions);
 
-  Start("http://a.example.com/path");
-
   EXPECT_CALL(mock_observer_, OnExecuteScript("Starting Script..."));
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+  Start("http://a.example.com/path");
 }
 
 TEST_F(ControllerTest, UpdateClientSettings) {
@@ -554,15 +450,10 @@
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
-  Start();
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-  // Non-gracefuls shutdowns don't call |OnStop|, we just shut down directly.
   EXPECT_CALL(mock_observer_, OnStop()).Times(0);
-
   testing::InSequence seq;
   EXPECT_CALL(mock_client_, Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+  Start();
 }
 
 TEST_F(ControllerTest, ShutdownGracefully) {
@@ -578,15 +469,10 @@
   EXPECT_CALL(*mock_service_, GetActions(StrEq("stop"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
-
-  Start();
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
   EXPECT_CALL(mock_observer_, OnStop());
-
   EXPECT_CALL(mock_client_,
               RecordDropOut(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+  Start();
 }
 
 TEST_F(ControllerTest, CloseCustomTab) {
@@ -602,15 +488,11 @@
       .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str,
                                    ServiceRequestSender::ResponseInfo{}));
 
-  Start();
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
   EXPECT_CALL(mock_observer_, CloseCustomTab());
-
   testing::InSequence seq;
   EXPECT_CALL(mock_client_,
               Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED));
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+  Start();
 }
 
 TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
@@ -636,10 +518,11 @@
 
 TEST_F(ControllerTest, Autostart) {
   SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  AddRunnableScript(&script_response, "autostart")
+  AddRunnableScript(&script_response, "runnable")
       ->mutable_presentation()
-      ->set_autostart(true);
+      ->set_autostart(false);
+  AddRunnableScript(&script_response, "autostart");
+
   SetNextScriptResponse(script_response);
 
   ActionsResponseProto autostart_script;
@@ -660,10 +543,10 @@
 
 TEST_F(ControllerTest, AutostartWithoutKeyboardSuppression) {
   SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  AddRunnableScript(&script_response, "autostart")
+  AddRunnableScript(&script_response, "runnable")
       ->mutable_presentation()
-      ->set_autostart(true);
+      ->set_autostart(false);
+  AddRunnableScript(&script_response, "autostart");
   SetNextScriptResponse(script_response);
 
   ActionsResponseProto autostart_script;
@@ -721,34 +604,6 @@
   SimulateWebContentsFocused();  // must call AttachUI
 }
 
-TEST_F(ControllerTest, KeepCheckingForElement) {
-  SupportsScriptResponseProto script_response;
-  *AddRunnableScript(&script_response, "no_match_yet")
-       ->mutable_presentation()
-       ->mutable_precondition()
-       ->mutable_element_condition()
-       ->mutable_match() = ToSelectorProto("#element");
-  SetNextScriptResponse(script_response);
-
-  Track();
-  // No scripts yet; the element doesn't exit.
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(0));
-
-  for (int i = 0; i < 3; i++) {
-    task_environment()->FastForwardBy(base::Seconds(1));
-    EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(0));
-  }
-
-  EXPECT_CALL(*mock_web_controller_, FindElement(_, _, _))
-      .WillRepeatedly(WithArgs<2>([](auto&& callback) {
-        std::move(callback).Run(OkClientStatus(),
-                                std::make_unique<ElementFinderResult>());
-      }));
-  task_environment()->FastForwardBy(base::Seconds(1));
-
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-}
-
 TEST_F(ControllerTest, ScriptTimeoutError) {
   // Wait for #element to show up for will_never_match. After 25s, execute the
   // script on_timeout_error.
@@ -1004,12 +859,6 @@
                                    ServiceRequestSender::ResponseInfo{})));
 
   Start("http://a.example.com/path");
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Start script, which waits for some navigation event to happen after the
-  // expect_navigation action has run..
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
 
   // No navigation event happened within the action timeout and the script ends.
   EXPECT_THAT(processed_actions_capture, SizeIs(0));
@@ -1040,12 +889,6 @@
                                    ServiceRequestSender::ResponseInfo{})));
 
   Start("http://a.example.com/path");
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Start script, which waits for some navigation event to happen after the
-  // expect_navigation action has run..
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
 
   // Navigation starts, but does not end, within the timeout.
   EXPECT_THAT(processed_actions_capture, SizeIs(0));
@@ -1080,7 +923,6 @@
       .WillOnce(SaveArg<0>(&script_store_config));
 
   Start("http://a.example.com/path");
-  controller_->GetDirectActionScripts();
 
   EXPECT_THAT(script_store_config.bundle_path(), Eq("bundle/path"));
   EXPECT_THAT(script_store_config.bundle_version(), Eq(12));
@@ -1098,414 +940,6 @@
   EXPECT_THAT(controller_->GetCurrentURL().spec(), navigate_url);
 }
 
-TEST_F(ControllerTest, Track) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  std::string response_str;
-  script_response.SerializeToString(&response_str);
-  EXPECT_CALL(*mock_service_,
-              GetScriptsForUrl(GURL("http://example.com/"), _, _))
-      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
-                                   ServiceRequestSender::ResponseInfo{}));
-
-  EXPECT_CALL(*mock_service_,
-              GetScriptsForUrl(GURL("http://b.example.com/"), _, _))
-      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "",
-                                   ServiceRequestSender::ResponseInfo{}));
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Execute the script, which requires showing the UI, then go back to tracking
-  // mode
-  EXPECT_CALL(mock_client_, AttachUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Move to a domain for which there are no scripts. This causes the controller
-  // to stop.
-  SimulateNavigateToUrl(GURL("http://b.example.com/"));
-  EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::STOPPED));
-  EXPECT_THAT(keyboard_states_, ElementsAre(false, true, false, false));
-
-  // Shutdown once we've moved from domain b.example.com, for which we know
-  // there are no scripts, to c.example.com, which we don't want to check.
-  EXPECT_CALL(mock_client_, Shutdown(Metrics::DropOutReason::NO_SCRIPTS));
-  SimulateNavigateToUrl(GURL("http://c.example.com/"));
-}
-
-TEST_F(ControllerTest, TrackScriptWithNoUI) {
-  // The UI is never shown during this test.
-  EXPECT_CALL(mock_client_, AttachUI()).Times(0);
-
-  SupportsScriptResponseProto script_response;
-  auto* script = AddRunnableScript(&script_response, "runnable");
-  script->mutable_presentation()->set_needs_ui(false);
-  SetupScripts(script_response);
-
-  // Script does nothing
-  ActionsResponseProto runnable_script;
-  auto* hidden_tell = runnable_script.add_actions()->mutable_tell();
-  hidden_tell->set_message("optional message");
-  hidden_tell->set_needs_ui(false);
-  runnable_script.add_actions()->mutable_stop();
-  SetupActionsForScript("runnable", runnable_script);
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, TrackScriptShowUIOnTell) {
-  SupportsScriptResponseProto script_response;
-  auto* script = AddRunnableScript(&script_response, "runnable");
-  script->mutable_presentation()->set_needs_ui(true);
-  SetupScripts(script_response);
-
-  ActionsResponseProto runnable_script;
-  runnable_script.add_actions()->mutable_tell()->set_message("error");
-  runnable_script.add_actions()->mutable_stop();
-  SetupActionsForScript("runnable", runnable_script);
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_FALSE(controller_->NeedsUI());
-  EXPECT_CALL(mock_client_, AttachUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // The last tell message should still be shown to the user.
-  EXPECT_TRUE(controller_->NeedsUI());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, RunDirectActionWhileTrackingWithUi) {
-  SupportsScriptResponseProto script_response;
-  auto* script_needs_ui = AddRunnableScript(&script_response, "needs_ui");
-  script_needs_ui->mutable_presentation()->set_needs_ui(true);
-
-  auto* script_no_ui = AddRunnableScript(&script_response, "no_ui");
-  script_no_ui->mutable_presentation()->set_needs_ui(false);
-  SetupScripts(script_response);
-
-  ActionsResponseProto needs_ui_script;
-  needs_ui_script.add_actions()->mutable_tell()->set_message("error");
-  needs_ui_script.add_actions()->mutable_stop();
-  SetupActionsForScript("needs_ui", needs_ui_script);
-
-  ActionsResponseProto no_ui_script;
-  no_ui_script.add_actions()->mutable_stop();
-  SetupActionsForScript("no_ui", no_ui_script);
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(2));
-  EXPECT_EQ(controller_->GetDirectActionScripts()[0].path, "needs_ui");
-
-  EXPECT_FALSE(controller_->NeedsUI());
-  EXPECT_CALL(mock_client_, AttachUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // The last tell message should still be shown to the user.
-  EXPECT_TRUE(controller_->NeedsUI());
-
-  EXPECT_CALL(mock_client_, DestroyUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(1, std::make_unique<TriggerContext>()));
-
-  // UI should have been cleared
-  EXPECT_FALSE(controller_->NeedsUI());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, TrackScriptClosesUI) {
-  SupportsScriptResponseProto script_response;
-  auto* script = AddRunnableScript(&script_response, "runnable");
-  script->mutable_presentation()->set_needs_ui(false);
-  SetupScripts(script_response);
-
-  ActionsResponseProto runnable_script;
-  runnable_script.add_actions()->mutable_tell()->set_message("hi");
-  runnable_script.add_actions()
-      ->mutable_wait_for_dom()
-      ->mutable_wait_condition();
-  runnable_script.add_actions()->mutable_stop();
-
-  SetupActionsForScript("runnable", runnable_script);
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_FALSE(controller_->NeedsUI());
-  EXPECT_CALL(mock_client_, AttachUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // The tell action wasn't the last one before close, so UI should close when
-  // the script is finished.
-  EXPECT_FALSE(controller_->NeedsUI());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, TrackScriptShowUIOnError) {
-  SupportsScriptResponseProto script_response;
-  auto* script = AddRunnableScript(&script_response, "runnable");
-  script->mutable_presentation()->set_needs_ui(false);
-  SetupScripts(script_response);
-
-  // Running the script fails, due to a backend issue. The error message should
-  // be shown.
-  EXPECT_CALL(*mock_service_, GetActions)
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
-                                   ServiceRequestSender::ResponseInfo{}));
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_FALSE(controller_->NeedsUI());
-  EXPECT_CALL(mock_client_, AttachUI());
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // UI must remain visible for the user to see the error message.
-  EXPECT_TRUE(controller_->NeedsUI());
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::STOPPED,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, TrackContinuesAfterScriptError) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  std::string response_str;
-  script_response.SerializeToString(&response_str);
-  EXPECT_CALL(*mock_service_,
-              GetScriptsForUrl(GURL("http://example.com/"), _, _))
-      .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str,
-                                   ServiceRequestSender::ResponseInfo{}));
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_CALL(*mock_service_, GetActions(StrEq("runnable"), _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, "",
-                                   ServiceRequestSender::ResponseInfo{}));
-
-  // When the script fails, the controller transitions to STOPPED state, then
-  // right away back to TRACKING state.
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Check the full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::STOPPED,
-                                   AutofillAssistantState::TRACKING));
-}
-
-TEST_F(ControllerTest, TrackReportsFirstSetOfScripts) {
-  ServiceRequestSender::ResponseCallback get_scripts_callback;
-  EXPECT_CALL(*mock_service_, GetScriptsForUrl(_, _, _))
-      .WillOnce([&get_scripts_callback](
-                    const GURL& url, const TriggerContext& trigger_context,
-                    ServiceRequestSender::ResponseCallback callback) {
-        get_scripts_callback = std::move(callback);
-      });
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  bool first_check_done = false;
-  controller_->Track(std::make_unique<TriggerContext>(),
-                     base::BindOnce(
-                         [](Controller* controller, bool* is_done) {
-                           // User actions must have been set when this is
-                           // called
-                           EXPECT_THAT(controller->GetDirectActionScripts(),
-                                       SizeIs(1));
-                           *is_done = true;
-                         },
-                         base::Unretained(controller_.get()),
-                         base::Unretained(&first_check_done)));
-  EXPECT_FALSE(first_check_done);
-  EXPECT_FALSE(controller_->HasRunFirstCheck());
-
-  ASSERT_TRUE(get_scripts_callback);
-
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  std::string response_str;
-  script_response.SerializeToString(&response_str);
-  std::move(get_scripts_callback)
-      .Run(net::HTTP_OK, response_str, ServiceRequestSender::ResponseInfo{});
-
-  EXPECT_TRUE(first_check_done);
-  EXPECT_TRUE(controller_->HasRunFirstCheck());
-}
-
-TEST_F(ControllerTest, TrackReportsNoScripts) {
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  base::MockCallback<base::OnceCallback<void()>> callback;
-
-  EXPECT_CALL(callback, Run());
-  controller_->Track(std::make_unique<TriggerContext>(), callback.Get());
-  EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
-}
-
-TEST_F(ControllerTest, TrackReportsNoScriptsForNow) {
-  SupportsScriptResponseProto script_response;
-  *AddRunnableScript(&script_response, "no_match_yet")
-       ->mutable_presentation()
-       ->mutable_precondition()
-       ->mutable_element_condition()
-       ->mutable_match() = ToSelectorProto("#element");
-  SetNextScriptResponse(script_response);
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  base::MockCallback<base::OnceCallback<void()>> callback;
-
-  EXPECT_CALL(callback, Run());
-  controller_->Track(std::make_unique<TriggerContext>(), callback.Get());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-}
-
-TEST_F(ControllerTest, TrackReportsNoScriptsForThePage) {
-  // Having scripts for the domain but not for the current page is fatal in
-  // STARTING or PROMPT mode, but not in TRACKING mode.
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "no_match_yet")
-      ->mutable_presentation()
-      ->mutable_precondition()
-      ->add_path_pattern("/otherpage.html");
-  SetNextScriptResponse(script_response);
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  base::MockCallback<base::OnceCallback<void()>> callback;
-
-  EXPECT_CALL(callback, Run());
-  controller_->Track(std::make_unique<TriggerContext>(), callback.Get());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-}
-
-TEST_F(ControllerTest, TrackReportsAlreadyDone) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  SetNextScriptResponse(script_response);
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  base::MockCallback<base::OnceCallback<void()>> callback;
-  EXPECT_CALL(callback, Run());
-  controller_->Track(std::make_unique<TriggerContext>(), callback.Get());
-}
-
-TEST_F(ControllerTest, TrackThenAutostart) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  AddRunnableScript(&script_response, "autostart", /*direct_action=*/false)
-      ->mutable_presentation()
-      ->set_autostart(true);
-  SetNextScriptResponse(script_response);
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  ActionsResponseProto autostart_script;
-  autostart_script.add_actions()->mutable_tell()->set_message("autostart");
-  autostart_script.add_actions()->mutable_stop();
-  SetupActionsForScript("autostart", autostart_script);
-
-  ActionsResponseProto runnable_script;
-  runnable_script.add_actions()->mutable_tell()->set_message("runnable");
-  runnable_script.add_actions()->mutable_stop();
-  SetupActionsForScript("runnable", runnable_script);
-
-  EXPECT_CALL(mock_client_, AttachUI());
-  Start("http://example.com/");
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  // Run "runnable", which then calls stop and ends. The controller should then
-  // go back to TRACKING mode.
-  controller_->PerformDirectAction(0, std::make_unique<TriggerContext>());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-
-  // Full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::STARTING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-  EXPECT_THAT(keyboard_states_,
-              ElementsAre(false, true, true, false, true, false));
-}
-
 TEST_F(ControllerTest, BrowseStateStopsOnDifferentDomain) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable")
@@ -1709,64 +1143,6 @@
       ->Commit();
 }
 
-TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction_Tracking) {
-  SupportsScriptResponseProto script_response;
-  AddRunnableScript(&script_response, "runnable");
-  SetNextScriptResponse(script_response);
-
-  ActionsResponseProto runnable_script;
-  runnable_script.add_actions()
-      ->mutable_prompt()
-      ->add_choices()
-      ->mutable_chip()
-      ->set_text("continue");
-  runnable_script.add_actions()
-      ->mutable_configure_bottom_sheet()
-      ->set_viewport_resizing(
-          ConfigureBottomSheetProto::RESIZE_LAYOUT_VIEWPORT);
-  SetupActionsForScript("runnable", runnable_script);
-
-  SetLastCommittedUrl(GURL("http://example.com/"));
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-  EXPECT_EQ(controller_->GetDirectActionScripts()[0].direct_action.names.count(
-                "runnable"),
-            1u);
-
-  // Start the script, which should show a prompt with the continue chip.
-  controller_->PerformDirectAction(0, std::make_unique<TriggerContext>());
-  EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
-  ASSERT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(), SizeIs(1));
-  EXPECT_EQ(
-      fake_script_executor_ui_delegate_.GetUserActions()->at(0).chip().text,
-      "continue");
-
-  // Browser (not document) initiated navigation while in prompt mode (such as
-  // go back): The controller stops the scripts, shows an error, then goes back
-  // to tracking mode.
-  //
-  // The ConfigureBottomSheet action which follows the prompt should never be
-  // executed.
-  EXPECT_CALL(mock_observer_, OnViewportModeChanged(_)).Times(0);
-
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://example.com/otherpage"));
-
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-  EXPECT_EQ(controller_->GetDirectActionScripts()[0].direct_action.names.count(
-                "runnable"),
-            1u);
-
-  // Full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::PROMPT,
-                                   AutofillAssistantState::STOPPED,
-                                   AutofillAssistantState::TRACKING));
-}
-
 TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "autostart")
@@ -1920,41 +1296,6 @@
                                    AutofillAssistantState::STOPPED));
 }
 
-TEST_F(ControllerTest, NavigationWhileTrackingWithUi) {
-  SupportsScriptResponseProto script_response;
-  auto* script = AddRunnableScript(&script_response, "runnable");
-  script->mutable_presentation()->set_needs_ui(true);
-  SetupScripts(script_response);
-
-  ActionsResponseProto runnable_script;
-  runnable_script.add_actions()->mutable_tell()->set_message("error");
-  runnable_script.add_actions()->mutable_stop();
-  SetupActionsForScript("runnable", runnable_script);
-
-  // Start tracking at example.com, with one script matching
-  SetLastCommittedUrl(GURL("http://example.com/"));
-
-  controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
-  ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
-
-  EXPECT_TRUE(
-      controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_TRUE(controller_->NeedsUI());
-
-  // Browser navigation will destroy the UI.
-  EXPECT_CALL(mock_client_, DestroyUISoon());
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(
-      web_contents(), GURL("http://a.example.com/page"));
-  EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
-  EXPECT_FALSE(controller_->NeedsUI());
-
-  // Full history of state transitions.
-  EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
-                                   AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::TRACKING));
-}
-
 TEST_F(ControllerTest, NavigationToGooglePropertyShutsDownDestroyingUI) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "autostart")
@@ -2638,7 +1979,11 @@
   script_response.mutable_semantic_selector_policy()
       ->mutable_bag_of_words()
       ->add_data_point_map();
-  AddRunnableScript(&script_response, "runnable");
+  *AddRunnableScript(&script_response, "runnable")
+       ->mutable_presentation()
+       ->mutable_precondition()
+       ->mutable_element_condition()
+       ->mutable_match() = ToSelectorProto("#element");
   SetNextScriptResponse(script_response);
 
   EXPECT_CALL(mock_client_, AttachUI());
diff --git a/components/autofill_assistant/browser/empty_controller_observer.h b/components/autofill_assistant/browser/empty_controller_observer.h
index 5ebe62fd..4f8fcda5 100644
--- a/components/autofill_assistant/browser/empty_controller_observer.h
+++ b/components/autofill_assistant/browser/empty_controller_observer.h
@@ -34,7 +34,6 @@
   void OnExecuteScript(const std::string& start_message) override {}
   void OnStart(const TriggerContext& trigger_context) override {}
   void OnStop() override {}
-  void OnResetState() override {}
   void OnUiShownChanged(bool shown) override {}
 };
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/execution_delegate.h b/components/autofill_assistant/browser/execution_delegate.h
index 9176fb3..4a6826ce 100644
--- a/components/autofill_assistant/browser/execution_delegate.h
+++ b/components/autofill_assistant/browser/execution_delegate.h
@@ -115,9 +115,6 @@
   // Remove a previously registered observer.
   virtual void RemoveObserver(const ControllerObserver* observer) = 0;
 
-  // Returns true if the controller is in a state where UI is necessary.
-  virtual bool NeedsUI() const = 0;
-
  protected:
   ExecutionDelegate() = default;
 };
diff --git a/components/autofill_assistant/browser/script_tracker.cc b/components/autofill_assistant/browser/script_tracker.cc
index 773b2bb2..3def224 100644
--- a/components/autofill_assistant/browser/script_tracker.cc
+++ b/components/autofill_assistant/browser/script_tracker.cc
@@ -89,6 +89,8 @@
   GURL url = delegate_->GetCurrentURL();
   batch_element_checker_ = std::make_unique<BatchElementChecker>();
   for (const std::unique_ptr<Script>& script : available_scripts_) {
+    // Direct actions are not supported anymore, but might still be served by
+    // the server.
     if (script->handle.direct_action.empty() && !script->handle.autostart)
       continue;
 
@@ -167,24 +169,6 @@
     available_scripts_js.Append(script->handle.path);
   dict.Set("available-scripts", std::move(available_scripts_js));
 
-  base::Value::List runnable_scripts_js;
-  for (const auto& entry : runnable_scripts_) {
-    base::Value::Dict script_js;
-    script_js.Set("path", entry.path);
-    script_js.Set("autostart", entry.autostart);
-
-    base::Value::Dict direct_action_js;
-    direct_action_js.Set("names", ToValueList(entry.direct_action.names));
-    direct_action_js.Set("required_arguments",
-                         ToValueList(entry.direct_action.required_arguments));
-    direct_action_js.Set("optional_arguments",
-                         ToValueList(entry.direct_action.optional_arguments));
-    script_js.Set("direct_action", std::move(direct_action_js));
-
-    runnable_scripts_js.Append(std::move(script_js));
-  }
-  dict.Set("runnable-scripts", std::move(runnable_scripts_js));
-
   return base::Value(std::move(dict));
 }
 
diff --git a/components/autofill_assistant/browser/state.h b/components/autofill_assistant/browser/state.h
index 9c117c7..b2cadf6 100644
--- a/components/autofill_assistant/browser/state.h
+++ b/components/autofill_assistant/browser/state.h
@@ -17,32 +17,14 @@
 //
 // INACTIVE -> STARTING -> RUNNING -> PROMPT -> RUNNING -> .. -> STOPPED
 //
-// A typical run, when started from a direct action, goes into tracking mode,
-// execute a script, the goes back to tracking mode:
-//
-// INACTIVE -> TRACKING -> RUNNING -> TRACKING -> ... -> STOPPED
-//
 // See the individual state for possible state transitions.
 enum class AutofillAssistantState {
   // Autofill assistant is not doing or showing anything.
   //
   // Initial state.
-  // Next states: STARTING, TRACKING, STOPPED
+  // Next states: STARTING, STOPPED
   INACTIVE = 0,
 
-  // Autofill assistant is keeping track of script availability.
-  //
-  // UI will only be shown if the previous state was RUNNING and if the script
-  // finished with tell + stop.
-  //
-  // In this mode, scripts are not autostarted. User actions might be available.
-  //
-  // Note that it is possible to go from TRACKING to STARTING to trigger
-  // whatever autostartable scripts is defined for a page.
-  //
-  // Next states: STARTING, RUNNING, STOPPED
-  TRACKING,
-
   // Autofill assistant is waiting for an autostart script.
   //
   // Status message, progress and details are initialized to useful values.
@@ -55,7 +37,7 @@
   // Status message, progress and details kept up-to-date by the running
   // script.
   //
-  // Next states: PROMPT, MODAL_DIALOG, TRACKING, STARTING, STOPPED
+  // Next states: PROMPT, MODAL_DIALOG, STARTING, STOPPED
   RUNNING,
 
   // Autofill assistant is waiting for the user to make a choice.
@@ -64,7 +46,7 @@
   // empty. A touchable area must be configured. The user might be filling in
   // the data for a payment request.
   //
-  // Next states: RUNNING, TRACKING, STOPPED
+  // Next states: RUNNING, STOPPED
   PROMPT,
 
   // Autofill assistant is expecting a modal dialog, such as the one asking for
@@ -81,7 +63,7 @@
   // In that scenario, the status message at the time of transition to STOPPED
   // is supposed to contain the final message.
   //
-  // Next states: TRACKING
+  // Next states: none.
   STOPPED,
 
   // Autofill assistant is waiting for the user to browse the website until one
@@ -96,7 +78,7 @@
   // are not a reason to shutdown autofill assistant. Navigating away from the
   // original domain will however shut down autofill assistant.
   //
-  // Next states: RUNNING, TRACKING, STOPPED
+  // Next states: RUNNING, STOPPED
   BROWSE,
 };
 
@@ -112,9 +94,6 @@
     case AutofillAssistantState::INACTIVE:
       out << "INACTIVE";
       break;
-    case AutofillAssistantState::TRACKING:
-      out << "TRACKING";
-      break;
     case AutofillAssistantState::STARTING:
       out << "STARTING";
       break;
diff --git a/components/autofill_assistant/browser/ui_controller.cc b/components/autofill_assistant/browser/ui_controller.cc
index 51d3ec6..58ecd81 100644
--- a/components/autofill_assistant/browser/ui_controller.cc
+++ b/components/autofill_assistant/browser/ui_controller.cc
@@ -1228,23 +1228,6 @@
   SetForm(nullptr, base::DoNothing(), base::DoNothing());
 }
 
-void UiController::OnResetState() {
-  // TODO(b/204963552): this list is incomplete. It would be much better if,
-  // instead of selectively clearing fields, we'd solve this in a more holistic
-  // way.
-  bubble_message_.clear();
-  tts_message_.clear();
-  status_message_.clear();
-  details_.clear();
-  info_box_.reset();
-  progress_visible_ = true;
-  progress_bar_error_state_ = false;
-  progress_active_step_ = 0;
-  step_progress_bar_configuration_ =
-      ShowProgressBarProto::StepProgressBarConfiguration();
-  peek_mode_ = ConfigureBottomSheetProto::HANDLE;
-}
-
 void UiController::OnUiShownChanged(bool shown) {
   // Stop any ongoing TTS if UI is hidden.
   if (!shown && tts_button_state_ == TtsButtonState::PLAYING) {
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index 23efd5b2..10c3e2f 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -210,7 +210,6 @@
   void OnExecuteScript(const std::string& start_message) override;
   void OnStart(const TriggerContext& trigger_context) override;
   void OnStop() override;
-  void OnResetState() override;
   void OnUiShownChanged(bool shown) override;
 
   // Overrides AutofillAssistantTtsController::TtsEventDelegate
diff --git a/components/browser_ui/site_settings/android/BUILD.gn b/components/browser_ui/site_settings/android/BUILD.gn
index e7f5cfc..9bb808b 100644
--- a/components/browser_ui/site_settings/android/BUILD.gn
+++ b/components/browser_ui/site_settings/android/BUILD.gn
@@ -147,6 +147,7 @@
   sources = [
     "junit/src/org/chromium/components/browser_ui/site_settings/AddExceptionPreferenceUnitTest.java",
     "junit/src/org/chromium/components/browser_ui/site_settings/DesktopSiteMetricsUnitTest.java",
+    "junit/src/org/chromium/components/browser_ui/site_settings/SiteDataCleanerUnitTest.java",
   ]
 
   deps = [
@@ -155,6 +156,7 @@
     "//base:base_java_test_support",
     "//base:base_junit_test_support",
     "//components/content_settings/android:content_settings_enums_java",
+    "//content/public/android:content_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
   ]
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java
index 90f7b94..8802314 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java
@@ -7,8 +7,11 @@
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.content_public.browser.BrowserContextHandle;
 
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
- * Encapsulates clearing the data of {@link Website}s.
+ * Encapsulates clearing the data of {@link Website}s and {@link WebsiteGroup}s.
  * Requires native library to be initialized.
  */
 public class SiteDataCleaner {
@@ -26,6 +29,25 @@
     }
 
     /**
+     * Clears the data for each of the sites in a given group.
+     * @param finishCallback is called when the entire operation is finished.
+     */
+    public void clearData(
+            BrowserContextHandle contextHandle, WebsiteGroup group, Runnable finishCallback) {
+        final AtomicInteger callbacksReceived = new AtomicInteger(0);
+        List<Website> sites = group.getWebsites();
+        final int websitesCount = sites.size();
+        final Runnable singleWebsiteCallback = () -> {
+            if (callbacksReceived.incrementAndGet() >= websitesCount) {
+                finishCallback.run();
+            }
+        };
+        for (Website site : sites) {
+            clearData(contextHandle, site, singleWebsiteCallback);
+        }
+    }
+
+    /**
      * Resets the permissions of the specified site.
      */
     public void resetPermissions(BrowserContextHandle browserContextHandle, Website site) {
@@ -43,4 +65,13 @@
             info.revoke(browserContextHandle);
         }
     }
+
+    /**
+     * Resets the permissions for each of the sites in a given group.
+     */
+    public void resetPermissions(BrowserContextHandle browserContextHandle, WebsiteGroup group) {
+        for (Website site : group.getWebsites()) {
+            resetPermissions(browserContextHandle, site);
+        }
+    }
 }
diff --git a/components/browser_ui/site_settings/android/junit/src/org/chromium/components/browser_ui/site_settings/SiteDataCleanerUnitTest.java b/components/browser_ui/site_settings/android/junit/src/org/chromium/components/browser_ui/site_settings/SiteDataCleanerUnitTest.java
new file mode 100644
index 0000000..f19d98f6
--- /dev/null
+++ b/components/browser_ui/site_settings/android/junit/src/org/chromium/components/browser_ui/site_settings/SiteDataCleanerUnitTest.java
@@ -0,0 +1,72 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.browser_ui.site_settings;
+
+import static org.mockito.Mockito.verify;
+
+import org.junit.Assert;
+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.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
+import org.chromium.content_public.browser.BrowserContextHandle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unit tests for {@link SiteDataCleaner}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SiteDataCleanerUnitTest {
+    @Rule
+    public JniMocker mJniMocker = new JniMocker();
+
+    @Mock
+    private WebsitePreferenceBridge.Natives mBridgeMock;
+
+    @Mock
+    private BrowserContextHandle mContextHandle;
+
+    private SiteDataCleaner mSiteDataCleaner;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mJniMocker.mock(WebsitePreferenceBridgeJni.TEST_HOOKS, mBridgeMock);
+        mSiteDataCleaner = new SiteDataCleaner();
+    }
+
+    @Test
+    public void testClearData() {
+        Website origin1 = new Website(WebsiteAddress.create("https://google.com"), null);
+        Website origin2 = new Website(WebsiteAddress.create("mail.google.com"), null);
+        Website origin3 = new Website(WebsiteAddress.create("https://docs.google.com"), null);
+        WebsiteGroup group = new WebsiteGroup(
+                "google.com", new ArrayList<>(Arrays.asList(origin1, origin2, origin3)));
+        final AtomicInteger callbacksReceived = new AtomicInteger(0);
+        final Runnable callback = () -> {
+            callbacksReceived.incrementAndGet();
+        };
+        mSiteDataCleaner.clearData(mContextHandle, group, callback);
+        // Check that the callback was invoked only once.
+        Assert.assertEquals(1, callbacksReceived.get());
+        // Verify that the bridge is called for each of the websites.
+        for (Website website : group.getWebsites()) {
+            verify(mBridgeMock).clearCookieData(mContextHandle, website.getAddress().getOrigin());
+            verify(mBridgeMock).clearBannerData(mContextHandle, website.getAddress().getOrigin());
+            verify(mBridgeMock)
+                    .clearMediaLicenses(mContextHandle, website.getAddress().getOrigin());
+        }
+    }
+}
diff --git a/components/gcm_driver/resources/gcm_internals.js b/components/gcm_driver/resources/gcm_internals.js
index f42e5c8..2ff874c09 100644
--- a/components/gcm_driver/resources/gcm_internals.js
+++ b/components/gcm_driver/resources/gcm_internals.js
@@ -7,7 +7,7 @@
 // </if>
 
 import './strings.m.js';
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 let isRecording = false;
@@ -142,7 +142,7 @@
 }
 
 function initialize() {
-  addWebUIListener('set-gcm-internals-info', setGcmInternalsInfo);
+  addWebUiListener('set-gcm-internals-info', setGcmInternalsInfo);
   $('recording').disabled = true;
   $('refresh').onclick = refreshAll;
   $('recording').onclick = setRecording;
diff --git a/components/net_log/resources/net_export.js b/components/net_log/resources/net_export.js
index 475ec07..671ed4e 100644
--- a/components/net_log/resources/net_export.js
+++ b/components/net_log/resources/net_export.js
@@ -7,7 +7,7 @@
 import 'chrome://resources/js/ios/web_ui.js';
 // </if>
 
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 /**
diff --git a/components/ntp_tiles/webui/resources/ntp_tiles_internals.js b/components/ntp_tiles/webui/resources/ntp_tiles_internals.js
index 74e4d4e..2735f1b 100644
--- a/components/ntp_tiles/webui/resources/ntp_tiles_internals.js
+++ b/components/ntp_tiles/webui/resources/ntp_tiles_internals.js
@@ -7,7 +7,7 @@
 // </if>
 
 import 'chrome://resources/js/jstemplate_compiled.js';
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 const initialize = function() {
@@ -32,10 +32,10 @@
     }
   });
 
-  addWebUIListener('receive-source-info', state => {
+  addWebUiListener('receive-source-info', state => {
     jstProcess(new JsEvalContext(state), $('sources'));
   });
-  addWebUIListener('receive-sites', sites => {
+  addWebUiListener('receive-sites', sites => {
     jstProcess(new JsEvalContext(sites), $('sites'));
   });
   chrome.send('registerForEvents');
diff --git a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
index 5a50e48..ab7ce778 100644
--- a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
+++ b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
@@ -144,6 +144,11 @@
   return page_input_timing_;
 }
 
+const absl::optional<mojom::SubresourceLoadMetrics>&
+FakePageLoadMetricsObserverDelegate::GetSubresourceLoadMetrics() const {
+  return subresource_load_metrics_;
+}
+
 const PageRenderData&
 FakePageLoadMetricsObserverDelegate::GetMainFrameRenderData() const {
   return main_frame_render_data_;
diff --git a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
index a5c5bee..bee300c 100644
--- a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
+++ b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
@@ -63,6 +63,8 @@
   const NormalizedResponsivenessMetrics& GetNormalizedResponsivenessMetrics()
       const override;
   const mojom::InputTiming& GetPageInputTiming() const override;
+  const absl::optional<mojom::SubresourceLoadMetrics>&
+  GetSubresourceLoadMetrics() const override;
   const PageRenderData& GetMainFrameRenderData() const override;
   const ui::ScopedVisibilityTracker& GetVisibilityTracker() const override;
   const ResourceTracker& GetResourceTracker() const override;
@@ -94,6 +96,7 @@
   NormalizedCLSData normalized_cls_data_;
   NormalizedResponsivenessMetrics normalized_responsiveness_metrics_;
   mojom::InputTiming page_input_timing_;
+  absl::optional<mojom::SubresourceLoadMetrics> subresource_load_metrics_;
   PageRenderData main_frame_render_data_;
   ui::ScopedVisibilityTracker visibility_tracker_;
   ResourceTracker resource_tracker_;
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index b9192f6c..228a48f 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -1047,6 +1047,7 @@
     mojom::FrameRenderDataUpdatePtr render_data,
     mojom::CpuTimingPtr cpu_timing,
     mojom::InputTimingPtr input_timing_delta,
+    mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
     uint32_t soft_navigation_count) {
   // Replacing this call by GetPageLoadTracker breaks some tests.
   //
@@ -1073,11 +1074,11 @@
   }
 
   if (tracker) {
-    tracker->UpdateMetrics(render_frame_host, std::move(timing),
-                           std::move(metadata), std::move(new_features),
-                           resources, std::move(render_data),
-                           std::move(cpu_timing), std::move(input_timing_delta),
-                           soft_navigation_count);
+    tracker->UpdateMetrics(
+        render_frame_host, std::move(timing), std::move(metadata),
+        std::move(new_features), resources, std::move(render_data),
+        std::move(cpu_timing), std::move(input_timing_delta),
+        std::move(subresource_load_metrics), soft_navigation_count);
   }
 }
 
@@ -1106,13 +1107,14 @@
     mojom::FrameRenderDataUpdatePtr render_data,
     mojom::CpuTimingPtr cpu_timing,
     mojom::InputTimingPtr input_timing_delta,
+    mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
     uint32_t soft_navigation_count) {
   content::RenderFrameHost* render_frame_host =
       page_load_metrics_receivers_.GetCurrentTargetFrame();
   OnTimingUpdated(render_frame_host, std::move(timing), std::move(metadata),
                   new_features, resources, std::move(render_data),
                   std::move(cpu_timing), std::move(input_timing_delta),
-                  soft_navigation_count);
+                  std::move(subresource_load_metrics), soft_navigation_count);
 }
 
 void MetricsWebContentsObserver::SetUpSharedMemoryForSmoothness(
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index e3c1cd0..71b6ea3 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -151,6 +151,7 @@
       mojom::FrameRenderDataUpdatePtr render_data,
       mojom::CpuTimingPtr cpu_timing,
       mojom::InputTimingPtr input_timing_delta,
+      mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
       uint32_t soft_navigation_count);
 
   // Informs the observers of the currently committed primary page load that
@@ -205,14 +206,16 @@
       content::NavigationHandle* navigation_handle);
 
   // page_load_metrics::mojom::PageLoadMetrics implementation.
-  void UpdateTiming(mojom::PageLoadTimingPtr timing,
-                    mojom::FrameMetadataPtr metadata,
-                    const std::vector<blink::UseCounterFeature>& new_features,
-                    std::vector<mojom::ResourceDataUpdatePtr> resources,
-                    mojom::FrameRenderDataUpdatePtr render_data,
-                    mojom::CpuTimingPtr cpu_timing,
-                    mojom::InputTimingPtr input_timing,
-                    uint32_t soft_navigation_count) override;
+  void UpdateTiming(
+      mojom::PageLoadTimingPtr timing,
+      mojom::FrameMetadataPtr metadata,
+      const std::vector<blink::UseCounterFeature>& new_features,
+      std::vector<mojom::ResourceDataUpdatePtr> resources,
+      mojom::FrameRenderDataUpdatePtr render_data,
+      mojom::CpuTimingPtr cpu_timing,
+      mojom::InputTimingPtr input_timing,
+      const mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
+      uint32_t soft_navigation_count) override;
 
   void SetUpSharedMemoryForSmoothness(
       base::ReadOnlySharedMemoryRegion shared_memory) override;
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index cb6eb67..6fd821cf 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -118,13 +118,14 @@
 
   void SimulateCpuTimingUpdate(const mojom::CpuTiming& timing,
                                content::RenderFrameHost* render_frame_host) {
-    observer()->OnTimingUpdated(render_frame_host, previous_timing_->Clone(),
-                                mojom::FrameMetadataPtr(absl::in_place),
-                                std::vector<blink::UseCounterFeature>(),
-                                std::vector<mojom::ResourceDataUpdatePtr>(),
-                                mojom::FrameRenderDataUpdatePtr(absl::in_place),
-                                timing.Clone(),
-                                mojom::InputTimingPtr(absl::in_place), 0);
+    observer()->OnTimingUpdated(
+        render_frame_host, previous_timing_->Clone(),
+        mojom::FrameMetadataPtr(absl::in_place),
+        std::vector<blink::UseCounterFeature>(),
+        std::vector<mojom::ResourceDataUpdatePtr>(),
+        mojom::FrameRenderDataUpdatePtr(absl::in_place), timing.Clone(),
+        mojom::InputTimingPtr(absl::in_place),
+        mojom::SubresourceLoadMetricsPtr(absl::in_place), 0);
   }
 
   void SimulateTimingUpdate(const mojom::PageLoadTiming& timing,
@@ -142,13 +143,15 @@
       const mojom::PageLoadTiming& timing,
       content::RenderFrameHost* render_frame_host) {
     previous_timing_ = timing.Clone();
-    observer()->OnTimingUpdated(render_frame_host, timing.Clone(),
-                                mojom::FrameMetadataPtr(absl::in_place),
-                                std::vector<blink::UseCounterFeature>(),
-                                std::vector<mojom::ResourceDataUpdatePtr>(),
-                                mojom::FrameRenderDataUpdatePtr(absl::in_place),
-                                mojom::CpuTimingPtr(absl::in_place),
-                                mojom::InputTimingPtr(absl::in_place), 0);
+    observer()->OnTimingUpdated(
+        render_frame_host, timing.Clone(),
+        mojom::FrameMetadataPtr(absl::in_place),
+        std::vector<blink::UseCounterFeature>(),
+        std::vector<mojom::ResourceDataUpdatePtr>(),
+        mojom::FrameRenderDataUpdatePtr(absl::in_place),
+        mojom::CpuTimingPtr(absl::in_place),
+        mojom::InputTimingPtr(absl::in_place),
+        mojom::SubresourceLoadMetricsPtr(absl::in_place), 0);
   }
 
   virtual std::unique_ptr<TestMetricsWebContentsObserverEmbedder>
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index 0f7e94f..1d37a29f 100644
--- a/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -211,7 +211,8 @@
         std::vector<blink::UseCounterFeature>(), resources,
         mojom::FrameRenderDataUpdatePtr(absl::in_place),
         mojom::CpuTimingPtr(absl::in_place),
-        mojom::InputTimingPtr(absl::in_place), 0);
+        mojom::InputTimingPtr(absl::in_place),
+        mojom::SubresourceLoadMetricsPtr(absl::in_place), 0);
   }
 };
 
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
index 4a2e6b6d5..7ff1dc0 100644
--- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
+++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
@@ -130,10 +130,10 @@
 void PageLoadMetricsObserverTester::SimulateTimingUpdate(
     const mojom::PageLoadTiming& timing,
     content::RenderFrameHost* rfh) {
-  SimulatePageLoadTimingUpdate(timing, mojom::FrameMetadata(),
-                               /*new_features=*/{},
-                               mojom::FrameRenderDataUpdate(),
-                               mojom::CpuTiming(), mojom::InputTiming(), rfh);
+  SimulatePageLoadTimingUpdate(
+      timing, mojom::FrameMetadata(), /* new_features= */ {},
+      mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), mojom::InputTiming(),
+      mojom::SubresourceLoadMetrics(), rfh);
 }
 
 void PageLoadMetricsObserverTester::SimulateCpuTimingUpdate(
@@ -147,8 +147,9 @@
   auto timing = page_load_metrics::mojom::PageLoadTimingPtr(absl::in_place);
   page_load_metrics::InitPageLoadTimingForTest(timing.get());
   SimulatePageLoadTimingUpdate(
-      *timing, mojom::FrameMetadata(), /*new_features=*/{},
-      mojom::FrameRenderDataUpdate(), cpu_timing, mojom::InputTiming(), rfh);
+      *timing, mojom::FrameMetadata(), /* new_features= */ {},
+      mojom::FrameRenderDataUpdate(), cpu_timing, mojom::InputTiming(),
+      mojom::SubresourceLoadMetrics(), rfh);
 }
 
 void PageLoadMetricsObserverTester::SimulateInputTimingUpdate(
@@ -163,17 +164,18 @@
   auto timing = page_load_metrics::mojom::PageLoadTimingPtr(absl::in_place);
   page_load_metrics::InitPageLoadTimingForTest(timing.get());
   SimulatePageLoadTimingUpdate(
-      *timing, mojom::FrameMetadata(), /*new_features=*/{},
-      mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), input_timing, rfh);
+      *timing, mojom::FrameMetadata(), /* new_features= */ {},
+      mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), input_timing,
+      mojom::SubresourceLoadMetrics(), rfh);
 }
 
 void PageLoadMetricsObserverTester::SimulateTimingAndMetadataUpdate(
     const mojom::PageLoadTiming& timing,
     const mojom::FrameMetadata& metadata) {
-  SimulatePageLoadTimingUpdate(timing, metadata, /*new_features=*/{},
-                               mojom::FrameRenderDataUpdate(),
-                               mojom::CpuTiming(), mojom::InputTiming(),
-                               web_contents()->GetPrimaryMainFrame());
+  SimulatePageLoadTimingUpdate(
+      timing, metadata, /* new_features= */ {}, mojom::FrameRenderDataUpdate(),
+      mojom::CpuTiming(), mojom::InputTiming(), mojom::SubresourceLoadMetrics(),
+      web_contents()->GetPrimaryMainFrame());
 }
 
 void PageLoadMetricsObserverTester::SimulateMetadataUpdate(
@@ -181,17 +183,18 @@
     content::RenderFrameHost* rfh) {
   mojom::PageLoadTiming timing;
   InitPageLoadTimingForTest(&timing);
-  SimulatePageLoadTimingUpdate(timing, metadata, /*new_features=*/{},
+  SimulatePageLoadTimingUpdate(timing, metadata, /* new_features= */ {},
                                mojom::FrameRenderDataUpdate(),
-                               mojom::CpuTiming(), mojom::InputTiming(), rfh);
+                               mojom::CpuTiming(), mojom::InputTiming(),
+                               mojom::SubresourceLoadMetrics(), rfh);
 }
 
 void PageLoadMetricsObserverTester::SimulateFeaturesUpdate(
     const std::vector<blink::UseCounterFeature>& new_features) {
-  SimulatePageLoadTimingUpdate(mojom::PageLoadTiming(), mojom::FrameMetadata(),
-                               new_features, mojom::FrameRenderDataUpdate(),
-                               mojom::CpuTiming(), mojom::InputTiming(),
-                               web_contents()->GetPrimaryMainFrame());
+  SimulatePageLoadTimingUpdate(
+      mojom::PageLoadTiming(), mojom::FrameMetadata(), new_features,
+      mojom::FrameRenderDataUpdate(), mojom::CpuTiming(), mojom::InputTiming(),
+      mojom::SubresourceLoadMetrics(), web_contents()->GetPrimaryMainFrame());
 }
 
 void PageLoadMetricsObserverTester::SimulateRenderDataUpdate(
@@ -205,17 +208,18 @@
   mojom::PageLoadTiming timing;
   InitPageLoadTimingForTest(&timing);
   SimulatePageLoadTimingUpdate(timing, mojom::FrameMetadata(),
-                               /*new_features=*/{}, render_data,
-                               mojom::CpuTiming(), mojom::InputTiming(), rfh);
+                               /* new_features= */ {}, render_data,
+                               mojom::CpuTiming(), mojom::InputTiming(),
+                               mojom::SubresourceLoadMetrics(), rfh);
 }
 
 void PageLoadMetricsObserverTester::SimulateSoftNavigationCountUpdate(
     uint32_t soft_navigation_count) {
   SimulatePageLoadTimingUpdate(
       mojom::PageLoadTiming(), mojom::FrameMetadata(),
-      /*new_features=*/{}, mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
-      mojom::InputTiming(), web_contents()->GetPrimaryMainFrame(),
-      soft_navigation_count);
+      /* new_features= */ {}, mojom::FrameRenderDataUpdate(),
+      mojom::CpuTiming(), mojom::InputTiming(), mojom::SubresourceLoadMetrics(),
+      web_contents()->GetPrimaryMainFrame(), soft_navigation_count);
 }
 
 void PageLoadMetricsObserverTester::SimulatePageLoadTimingUpdate(
@@ -225,12 +229,14 @@
     const mojom::FrameRenderDataUpdate& render_data,
     const mojom::CpuTiming& cpu_timing,
     const mojom::InputTiming& input_timing,
+    const mojom::SubresourceLoadMetrics& subresource_load_metrics,
     content::RenderFrameHost* rfh,
     uint32_t soft_navigation_count) {
   metrics_web_contents_observer_->OnTimingUpdated(
       rfh, timing.Clone(), metadata.Clone(), new_features,
       std::vector<mojom::ResourceDataUpdatePtr>(), render_data.Clone(),
-      cpu_timing.Clone(), input_timing.Clone(), soft_navigation_count);
+      cpu_timing.Clone(), input_timing.Clone(),
+      subresource_load_metrics.Clone(), soft_navigation_count);
   // If sending the timing update caused the PageLoadMetricsUpdateDispatcher to
   // schedule a buffering timer, then fire it now so metrics are dispatched to
   // observers.
@@ -256,7 +262,8 @@
       std::vector<blink::UseCounterFeature>(), resources,
       mojom::FrameRenderDataUpdatePtr(absl::in_place),
       mojom::CpuTimingPtr(absl::in_place),
-      mojom::InputTimingPtr(absl::in_place), 0);
+      mojom::InputTimingPtr(absl::in_place),
+      mojom::SubresourceLoadMetricsPtr(absl::in_place), 0);
 }
 
 void PageLoadMetricsObserverTester::SimulateLoadedResource(
diff --git a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
index ca7b68f..db60315 100644
--- a/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
+++ b/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
@@ -172,6 +172,7 @@
       const mojom::FrameRenderDataUpdate& render_data,
       const mojom::CpuTiming& cpu_timing,
       const mojom::InputTiming& input_timing,
+      const mojom::SubresourceLoadMetrics& subresource_load_metrics,
       content::RenderFrameHost* rfh,
       uint32_t soft_navigation_count = 0);
 
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
index 3ae0df0..5809fc7 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
@@ -189,6 +189,8 @@
   virtual const PageRenderData& GetMainFrameRenderData() const = 0;
   virtual const ui::ScopedVisibilityTracker& GetVisibilityTracker() const = 0;
   virtual const ResourceTracker& GetResourceTracker() const = 0;
+  virtual const absl::optional<mojom::SubresourceLoadMetrics>&
+  GetSubresourceLoadMetrics() const = 0;
 
   // Returns a shared LargestContentfulPaintHandler for page load metrics.
   virtual const LargestContentfulPaintHandler&
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
index 5e0d77b..fd0b89c3 100644
--- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -475,6 +475,7 @@
     mojom::FrameRenderDataUpdatePtr render_data,
     mojom::CpuTimingPtr new_cpu_timing,
     mojom::InputTimingPtr input_timing_delta,
+    mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
     uint32_t soft_navigation_count) {
   if (embedder_interface_->IsExtensionUrl(
           render_frame_host->GetLastCommittedURL())) {
@@ -496,6 +497,9 @@
     UpdateMainFrameMetadata(render_frame_host, std::move(new_metadata));
     UpdateMainFrameTiming(std::move(new_timing));
     UpdateMainFrameRenderData(*render_data);
+    if (subresource_load_metrics) {
+      UpdateMainFrameSubresourceLoadMetrics(*subresource_load_metrics);
+    }
     UpdateSoftNavigationCount(soft_navigation_count);
   } else {
     UpdateSubFrameMetadata(render_frame_host, std::move(new_metadata));
@@ -635,6 +639,11 @@
   MaybeUpdateMainFrameIntersectionRect(render_frame_host, subframe_metadata);
 }
 
+void PageLoadMetricsUpdateDispatcher::UpdateMainFrameSubresourceLoadMetrics(
+    const mojom::SubresourceLoadMetrics& subresource_load_metrics) {
+  subresource_load_metrics_ = subresource_load_metrics;
+}
+
 void PageLoadMetricsUpdateDispatcher::UpdateSoftNavigationCount(
     uint32_t soft_navigation_count) {
   client_->OnSoftNavigationCountChanged(soft_navigation_count);
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
index e6925f9e..66f7386 100644
--- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
+++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
@@ -170,6 +170,7 @@
                      mojom::FrameRenderDataUpdatePtr render_data,
                      mojom::CpuTimingPtr new_cpu_timing,
                      mojom::InputTimingPtr input_timing_delta,
+                     mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
                      uint32_t soft_navigation_count);
 
   void SetUpSharedMemoryForSmoothness(
@@ -219,6 +220,10 @@
   const mojom::InputTiming& page_input_timing() const {
     return *page_input_timing_;
   }
+  const absl::optional<mojom::SubresourceLoadMetrics>&
+  subresource_load_metrics() const {
+    return subresource_load_metrics_;
+  }
   void UpdateResponsivenessMetricsNormalizationForBfcache() {
     responsiveness_metrics_normalization_.ClearAllUserInteractionLatencies();
   }
@@ -246,6 +251,9 @@
   void UpdateSubFrameMetadata(content::RenderFrameHost* render_frame_host,
                               mojom::FrameMetadataPtr subframe_metadata);
 
+  void UpdateMainFrameSubresourceLoadMetrics(
+      const mojom::SubresourceLoadMetrics& subresource_load_metrics);
+
   void UpdateSoftNavigationCount(uint32_t soft_navigation_count);
 
   void UpdatePageInputTiming(const mojom::InputTiming& input_timing_delta);
@@ -299,6 +307,9 @@
   // InputTiming data accumulated across all frames.
   mojom::InputTimingPtr page_input_timing_;
 
+  // SubresourceLoadMetrics for the main frame.
+  absl::optional<mojom::SubresourceLoadMetrics> subresource_load_metrics_;
+
   // True if this page load started in prerender.
   const bool is_prerendered_page_load_;
 
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 7e598dc..c279486e 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -1093,6 +1093,11 @@
   return metrics_update_dispatcher_.page_input_timing();
 }
 
+const absl::optional<mojom::SubresourceLoadMetrics>&
+PageLoadTracker::GetSubresourceLoadMetrics() const {
+  return metrics_update_dispatcher_.subresource_load_metrics();
+}
+
 const PageRenderData& PageLoadTracker::GetMainFrameRenderData() const {
   return metrics_update_dispatcher_.main_frame_render_data();
 }
@@ -1198,18 +1203,20 @@
     mojom::FrameRenderDataUpdatePtr render_data,
     mojom::CpuTimingPtr cpu_timing,
     mojom::InputTimingPtr input_timing_delta,
+    mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
     uint32_t soft_navigation_count) {
   if (parent_tracker_) {
     parent_tracker_->UpdateMetrics(
         render_frame_host, timing.Clone(), metadata.Clone(), features,
         resources, render_data.Clone(), cpu_timing.Clone(),
-        input_timing_delta.Clone(), soft_navigation_count);
+        input_timing_delta.Clone(), subresource_load_metrics.Clone(),
+        soft_navigation_count);
   }
   metrics_update_dispatcher_.UpdateMetrics(
       render_frame_host, std::move(timing), std::move(metadata),
       std::move(features), resources, std::move(render_data),
       std::move(cpu_timing), std::move(input_timing_delta),
-      soft_navigation_count);
+      std::move(subresource_load_metrics), soft_navigation_count);
 }
 
 void PageLoadTracker::SetPageMainFrame(content::RenderFrameHost* rfh) {
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h
index a0af84c..1b3d84e 100644
--- a/components/page_load_metrics/browser/page_load_tracker.h
+++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -259,6 +259,8 @@
   const NormalizedResponsivenessMetrics& GetNormalizedResponsivenessMetrics()
       const override;
   const mojom::InputTiming& GetPageInputTiming() const override;
+  const absl::optional<mojom::SubresourceLoadMetrics>&
+  GetSubresourceLoadMetrics() const override;
   const PageRenderData& GetMainFrameRenderData() const override;
   const ui::ScopedVisibilityTracker& GetVisibilityTracker() const override;
   const ResourceTracker& GetResourceTracker() const override;
@@ -414,6 +416,7 @@
                      mojom::FrameRenderDataUpdatePtr render_data,
                      mojom::CpuTimingPtr new_cpu_timing,
                      mojom::InputTimingPtr input_timing_delta,
+                     mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
                      uint32_t soft_navigation_count);
 
   // Set RenderFrameHost for the main frame of the page this tracker instance is
diff --git a/components/page_load_metrics/common/page_load_metrics.mojom b/components/page_load_metrics/common/page_load_metrics.mojom
index 836d6d4..56a5e57 100644
--- a/components/page_load_metrics/common/page_load_metrics.mojom
+++ b/components/page_load_metrics/common/page_load_metrics.mojom
@@ -214,6 +214,16 @@
   gfx.mojom.Rect? main_frame_viewport_rect;
 };
 
+struct SubresourceLoadMetrics {
+  // Number of subresources loads for the frame.
+  // Note that this include subresources where a service worker responded.
+  uint32 number_of_subresources_loaded;
+
+  // Number of subresources loads that is responded by the service worker.
+  // i.e. `respondWith` was called.
+  uint32 number_of_subresource_loads_handled_by_service_worker;
+};
+
 // Enumeration of distinct cache types.
 enum CacheType {
   kNotCached, // Resource came from network.
@@ -368,6 +378,8 @@
   // UpdateTiming calls are buffered, and contain all updates that have been
   // received in the last buffer window. Some of the update data may be empty.
   // Only called when at least one change has been observed within the frame.
+  // Note that counts in `subresource_load_metrics` are cumulative and not a
+  // delta.
   UpdateTiming(PageLoadTiming page_load_timing,
                FrameMetadata frame_metadata,
                // `new_features` will not contain any previously seen values.
@@ -376,6 +388,7 @@
                FrameRenderDataUpdate render_data,
                CpuTiming cpu_load_timing,
                InputTiming input_timing_delta,
+               SubresourceLoadMetrics? subresource_load_metrics,
                uint32 soft_navigation_count);
 
   // Set up a shared memory used to transfer smoothness data from the renderer
diff --git a/components/page_load_metrics/renderer/fake_page_timing_sender.cc b/components/page_load_metrics/renderer/fake_page_timing_sender.cc
index 6f258a0..533fd94 100644
--- a/components/page_load_metrics/renderer/fake_page_timing_sender.cc
+++ b/components/page_load_metrics/renderer/fake_page_timing_sender.cc
@@ -25,10 +25,11 @@
     const mojom::FrameRenderDataUpdate& render_data,
     const mojom::CpuTimingPtr& cpu_timing,
     const mojom::InputTimingPtr new_input_timing,
+    const mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
     uint32_t soft_navigation_count) {
   validator_->UpdateTiming(timing, metadata, new_features, resources,
                            render_data, cpu_timing, new_input_timing,
-                           soft_navigation_count);
+                           subresource_load_metrics, soft_navigation_count);
 }
 
 void FakePageTimingSender::SetUpSmoothnessReporting(
@@ -84,6 +85,18 @@
             actual_input_timing->total_adjusted_input_delay);
 }
 
+void FakePageTimingSender::PageTimingValidator::
+    UpdateExpectedSubresourceLoadMetrics(
+        const mojom::SubresourceLoadMetrics& subresource_load_metrics) {
+  expected_subresource_load_metrics_ = subresource_load_metrics.Clone();
+}
+
+void FakePageTimingSender::PageTimingValidator::
+    VerifyExpectedSubresourceLoadMetrics() const {
+  ASSERT_EQ(expected_subresource_load_metrics_,
+            actual_subresource_load_metrics_);
+}
+
 void FakePageTimingSender::PageTimingValidator::VerifyExpectedCpuTimings()
     const {
   ASSERT_EQ(actual_cpu_timings_.size(), expected_cpu_timings_.size());
@@ -132,6 +145,7 @@
     const mojom::FrameRenderDataUpdate& render_data,
     const mojom::CpuTimingPtr& cpu_timing,
     const mojom::InputTimingPtr& new_input_timing,
+    const mojom::SubresourceLoadMetricsPtr& subresource_load_metrics,
     uint32_t soft_navigation_count) {
   actual_timings_.push_back(timing.Clone());
   if (!cpu_timing->task_time.is_zero()) {
@@ -152,6 +166,7 @@
   actual_input_timing->total_input_delay += new_input_timing->total_input_delay;
   actual_input_timing->total_adjusted_input_delay +=
       new_input_timing->total_adjusted_input_delay;
+  actual_subresource_load_metrics_ = subresource_load_metrics.Clone();
 
   VerifyExpectedTimings();
   VerifyExpectedCpuTimings();
@@ -159,6 +174,7 @@
   VerifyExpectedRenderData();
   VerifyExpectedMainFrameIntersectionRect();
   VerifyExpectedMainFrameViewportRect();
+  VerifyExpectedSubresourceLoadMetrics();
   // TODO(yoav): Verify that soft nav count matches expectations.
 }
 
diff --git a/components/page_load_metrics/renderer/fake_page_timing_sender.h b/components/page_load_metrics/renderer/fake_page_timing_sender.h
index 123a8ac..1c2b2dd 100644
--- a/components/page_load_metrics/renderer/fake_page_timing_sender.h
+++ b/components/page_load_metrics/renderer/fake_page_timing_sender.h
@@ -62,6 +62,8 @@
 
     void VerifyExpectedInputTiming() const;
 
+    void VerifyExpectedSubresourceLoadMetrics() const;
+
     // PageLoad features that are expected to be sent through SendTiming()
     // should be passed via UpdateExpectedPageLoadFeatures.
     void UpdateExpectPageLoadFeatures(const blink::UseCounterFeature& feature);
@@ -73,6 +75,9 @@
 
     void UpdateExpectedInputTiming(const base::TimeDelta input_delay);
 
+    void UpdateExpectedSubresourceLoadMetrics(
+        const mojom::SubresourceLoadMetrics& subresource_load_metrics);
+
     void UpdateExpectedMainFrameIntersectionRect(
         const gfx::Rect& main_frame_intersection_rect) {
       expected_main_frame_intersection_rect_ = main_frame_intersection_rect;
@@ -105,6 +110,7 @@
         const mojom::FrameRenderDataUpdate& render_data,
         const mojom::CpuTimingPtr& cpu_timing,
         const mojom::InputTimingPtr& input_timing,
+        const mojom::SubresourceLoadMetricsPtr& subresource_load_metrics,
         uint32_t soft_navigation_count);
 
    private:
@@ -122,6 +128,8 @@
     absl::optional<gfx::Rect> actual_main_frame_viewport_rect_;
     mojom::InputTimingPtr expected_input_timing;
     mojom::InputTimingPtr actual_input_timing;
+    mojom::SubresourceLoadMetricsPtr expected_subresource_load_metrics_;
+    mojom::SubresourceLoadMetricsPtr actual_subresource_load_metrics_;
   };
 
   explicit FakePageTimingSender(PageTimingValidator* validator);
@@ -138,6 +146,7 @@
                   const mojom::FrameRenderDataUpdate& render_data,
                   const mojom::CpuTimingPtr& cpu_timing,
                   mojom::InputTimingPtr new_input_timing,
+                  mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
                   uint32_t soft_navigation_count) override;
 
   void SetUpSmoothnessReporting(
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
index 2b0d647..c8922f6 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -55,13 +55,14 @@
                   const mojom::FrameRenderDataUpdate& render_data,
                   const mojom::CpuTimingPtr& cpu_timing,
                   mojom::InputTimingPtr input_timing_delta,
+                  mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
                   uint32_t soft_navigation_count) override {
     DCHECK(page_load_metrics_);
     page_load_metrics_->UpdateTiming(
         limited_sending_mode_ ? CreatePageLoadTiming() : timing->Clone(),
         metadata->Clone(), new_features, std::move(resources),
         render_data.Clone(), cpu_timing->Clone(), std::move(input_timing_delta),
-        soft_navigation_count);
+        std::move(subresource_load_metrics), soft_navigation_count);
   }
 
   void SetUpSmoothnessReporting(
@@ -133,6 +134,15 @@
     page_timing_metrics_sender_->DidObserveLoadingBehavior(behavior);
 }
 
+void MetricsRenderFrameObserver::DidObserveSubresourceLoad(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  if (page_timing_metrics_sender_)
+    page_timing_metrics_sender_->DidObserveSubresourceLoad(
+        number_of_subresources_loaded,
+        number_of_subresource_loads_handled_by_service_worker);
+}
+
 void MetricsRenderFrameObserver::DidObserveNewFeatureUsage(
     const blink::UseCounterFeature& feature) {
   if (page_timing_metrics_sender_)
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/components/page_load_metrics/renderer/metrics_render_frame_observer.h
index 3d7ed3b..aaec2ba 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer.h
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.h
@@ -56,6 +56,9 @@
       blink::UserInteractionType interaction_type) override;
   void DidChangeCpuTiming(base::TimeDelta time) override;
   void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior) override;
+  void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) override;
   void DidObserveNewFeatureUsage(
       const blink::UseCounterFeature& feature) override;
   void DidObserveSoftNavigation(uint32_t count) override;
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index d3610bb..4809eb9 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -86,6 +86,27 @@
   EnsureSendTimer();
 }
 
+void PageTimingMetricsSender::DidObserveSubresourceLoad(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  if (!subresource_load_metrics_) {
+    subresource_load_metrics_ = mojom::SubresourceLoadMetrics::New();
+  }
+  if (subresource_load_metrics_->number_of_subresources_loaded ==
+          number_of_subresources_loaded &&
+      subresource_load_metrics_
+              ->number_of_subresource_loads_handled_by_service_worker ==
+          number_of_subresource_loads_handled_by_service_worker) {
+    return;
+  }
+  subresource_load_metrics_->number_of_subresources_loaded =
+      number_of_subresources_loaded;
+  subresource_load_metrics_
+      ->number_of_subresource_loads_handled_by_service_worker =
+      number_of_subresource_loads_handled_by_service_worker;
+  EnsureSendTimer();
+}
+
 void PageTimingMetricsSender::DidObserveNewFeatureUsage(
     const blink::UseCounterFeature& feature) {
   if (feature_tracker_.TestAndSet(feature))
@@ -317,9 +338,10 @@
       page_resource_data_use_.erase(resource->resource_id());
     }
   }
-  sender_->SendTiming(last_timing_, metadata_, std::move(new_features_),
-                      std::move(resources), render_data_, last_cpu_timing_,
-                      std::move(input_timing_delta_), soft_navigation_count_);
+  sender_->SendTiming(
+      last_timing_, metadata_, std::move(new_features_), std::move(resources),
+      render_data_, last_cpu_timing_, std::move(input_timing_delta_),
+      subresource_load_metrics_.Clone(), soft_navigation_count_);
   input_timing_delta_ = mojom::InputTiming::New();
   InitiateUserInteractionTiming();
   new_features_.clear();
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
index f7398e8..3de1e39 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -50,6 +50,9 @@
   ~PageTimingMetricsSender();
 
   void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior);
+  void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker);
   void DidObserveNewFeatureUsage(const blink::UseCounterFeature& feature);
   void DidObserveSoftNavigation(uint32_t count);
   void DidObserveLayoutShift(double score, bool after_input_or_scroll);
@@ -110,6 +113,7 @@
   mojom::PageLoadTimingPtr last_timing_;
   mojom::CpuTimingPtr last_cpu_timing_;
   mojom::InputTimingPtr input_timing_delta_;
+  mojom::SubresourceLoadMetricsPtr subresource_load_metrics_;
 
   // The the sender keep track of metadata as it comes in, because the sender is
   // scoped to a single committed load.
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
index 4db3f78e..a5f75b6f1 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -163,6 +163,24 @@
   validator_.VerifyExpectedInputTiming();
 }
 
+TEST_F(PageTimingMetricsSenderTest, SendSubresourceLoadMetrics) {
+  mojom::PageLoadTiming timing;
+  InitPageLoadTimingForTest(&timing);
+  metrics_sender_->Update(timing.Clone(),
+                          PageTimingMetadataRecorder::MonotonicTiming());
+  validator_.ExpectPageLoadTiming(timing);
+
+  metrics_sender_->DidObserveSubresourceLoad(5, 2);
+
+  mojom::SubresourceLoadMetricsPtr expected =
+      mojom::SubresourceLoadMetrics::New();
+  expected->number_of_subresources_loaded = 5;
+  expected->number_of_subresource_loads_handled_by_service_worker = 2;
+  validator_.UpdateExpectedSubresourceLoadMetrics(*expected);
+  metrics_sender_->mock_timer()->Fire();
+  validator_.VerifyExpectedSubresourceLoadMetrics();
+}
+
 TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) {
   mojom::PageLoadTiming timing;
   InitPageLoadTimingForTest(&timing);
diff --git a/components/page_load_metrics/renderer/page_timing_sender.h b/components/page_load_metrics/renderer/page_timing_sender.h
index 6c32be03..d4d3a68a0 100644
--- a/components/page_load_metrics/renderer/page_timing_sender.h
+++ b/components/page_load_metrics/renderer/page_timing_sender.h
@@ -22,6 +22,7 @@
       const mojom::FrameRenderDataUpdate& render_data,
       const mojom::CpuTimingPtr& cpu_timing,
       mojom::InputTimingPtr input_timing_delta,
+      mojom::SubresourceLoadMetricsPtr subresource_load_metrics,
       uint32_t soft_navigation_count) = 0;
   virtual void SetUpSmoothnessReporting(
       base::ReadOnlySharedMemoryRegion shared_memory) = 0;
diff --git a/components/password_manager/content/common/BUILD.gn b/components/password_manager/content/common/BUILD.gn
new file mode 100644
index 0000000..a083906d
--- /dev/null
+++ b/components/password_manager/content/common/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2022 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("common") {
+  sources = [
+    "web_ui_constants.cc",
+    "web_ui_constants.h",
+  ]
+}
diff --git a/components/password_manager/content/common/web_ui_constants.cc b/components/password_manager/content/common/web_ui_constants.cc
new file mode 100644
index 0000000..ba03df6
--- /dev/null
+++ b/components/password_manager/content/common/web_ui_constants.cc
@@ -0,0 +1,11 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/content/common/web_ui_constants.h"
+
+namespace password_manager {
+
+const char kChromeUIPasswordManagerHost[] = "password-manager";
+
+}  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/content/common/web_ui_constants.h b/components/password_manager/content/common/web_ui_constants.h
new file mode 100644
index 0000000..0fe611daf
--- /dev/null
+++ b/components/password_manager/content/common/web_ui_constants.h
@@ -0,0 +1,18 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Contains constants for WebUI UI/Host/SubPage constants. Anything else go in
+// chrome/common/url_constants.h.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_WEB_UI_CONSTANTS_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_WEB_UI_CONSTANTS_H_
+
+namespace password_manager {
+
+// WebUI constants for Password Manager that are needed for other components.
+extern const char kChromeUIPasswordManagerHost[];
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_WEB_UI_CONSTANTS_H_
diff --git a/components/policy/resources/templates/policy_definitions/ChromeFrameContentTypes/ChromeFrameContentTypes.yaml b/components/policy/resources/templates/policy_definitions/ChromeFrameContentTypes/ChromeFrameContentTypes.yaml
index 236eefb..7f7bcc88 100644
--- a/components/policy/resources/templates/policy_definitions/ChromeFrameContentTypes/ChromeFrameContentTypes.yaml
+++ b/components/policy/resources/templates/policy_definitions/ChromeFrameContentTypes/ChromeFrameContentTypes.yaml
@@ -11,7 +11,7 @@
 features:
   dynamic_refresh: false
 owners:
-- tommi@chromium.org
+- file://components/policy/OWNERS
 schema:
   items:
     type: string
diff --git a/components/policy/resources/templates/policy_definitions/ChromeFrameRendererSettings/ChromeFrameRendererSettings.yaml b/components/policy/resources/templates/policy_definitions/ChromeFrameRendererSettings/ChromeFrameRendererSettings.yaml
index d96d9238..cc8f30f 100644
--- a/components/policy/resources/templates/policy_definitions/ChromeFrameRendererSettings/ChromeFrameRendererSettings.yaml
+++ b/components/policy/resources/templates/policy_definitions/ChromeFrameRendererSettings/ChromeFrameRendererSettings.yaml
@@ -16,7 +16,7 @@
   name: RenderInChromeFrame
   value: 1
 owners:
-- tommi@chromium.org
+- file://components/policy/OWNERS
 schema:
   enum:
   - 0
diff --git a/components/policy/resources/webui/policy_base.js b/components/policy/resources/webui/policy_base.js
index 7487d68..72599b4 100644
--- a/components/policy/resources/webui/policy_base.js
+++ b/components/policy/resources/webui/policy_base.js
@@ -11,7 +11,7 @@
 import './status_box.js';
 import './policy_table.js';
 
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {$} from 'chrome://resources/js/util.js';
@@ -117,11 +117,11 @@
     };
 
     chrome.send('listenPoliciesUpdates');
-    addWebUIListener('status-updated', status => this.setStatus(status));
-    addWebUIListener(
+    addWebUiListener('status-updated', status => this.setStatus(status));
+    addWebUiListener(
         'policies-updated',
         (names, values) => this.onPoliciesReceived_(names, values));
-    addWebUIListener('download-json', json => this.downloadJson(json));
+    addWebUiListener('download-json', json => this.downloadJson(json));
   }
 
   /**
diff --git a/components/safe_browsing/content/browser/web_ui/resources/safe_browsing.js b/components/safe_browsing/content/browser/web_ui/resources/safe_browsing.js
index 5f505121..efb4e8f64 100644
--- a/components/safe_browsing/content/browser/web_ui/resources/safe_browsing.js
+++ b/components/safe_browsing/content/browser/web_ui/resources/safe_browsing.js
@@ -4,7 +4,7 @@
 
 import 'chrome://resources/cr_elements/cr_tab_box/cr_tab_box.js';
 
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 /**
@@ -32,7 +32,7 @@
       addDownloadUrlChecked(url_and_result);
     });
   });
-  addWebUIListener('download-url-checked-update', function(url_and_result) {
+  addWebUiListener('download-url-checked-update', function(url_and_result) {
     addDownloadUrlChecked(url_and_result);
   });
 
@@ -42,7 +42,7 @@
           addSentClientDownloadRequestsInfo(cdr);
         });
       });
-  addWebUIListener('sent-client-download-requests-update', function(result) {
+  addWebUiListener('sent-client-download-requests-update', function(result) {
     addSentClientDownloadRequestsInfo(result);
   });
 
@@ -52,7 +52,7 @@
           addReceivedClientDownloadResponseInfo(cdr);
         });
       });
-  addWebUIListener(
+  addWebUiListener(
       'received-client-download-responses-update', function(result) {
         addReceivedClientDownloadResponseInfo(result);
       });
@@ -63,7 +63,7 @@
           addSentClientPhishingRequestsInfo(cpr);
         });
       });
-  addWebUIListener('sent-client-phishing-requests-update', function(result) {
+  addWebUiListener('sent-client-phishing-requests-update', function(result) {
     addSentClientPhishingRequestsInfo(result);
   });
 
@@ -73,7 +73,7 @@
           addReceivedClientPhishingResponseInfo(cpr);
         });
       });
-  addWebUIListener(
+  addWebUiListener(
       'received-client-phishing-responses-update', function(result) {
         addReceivedClientPhishingResponseInfo(result);
       });
@@ -83,7 +83,7 @@
       addSentCSBRRsInfo(csbrr);
     });
   });
-  addWebUIListener('sent-csbrr-update', function(result) {
+  addWebUiListener('sent-csbrr-update', function(result) {
     addSentCSBRRsInfo(result);
   });
 
@@ -92,7 +92,7 @@
       addSentHitReportsInfo(hitReports);
     });
   });
-  addWebUIListener('sent-hit-report-list', function(result) {
+  addWebUiListener('sent-hit-report-list', function(result) {
     addSentHitReportsInfo(result);
   });
 
@@ -101,7 +101,7 @@
       addPGEvent(pgEvent);
     });
   });
-  addWebUIListener('sent-pg-event', function(result) {
+  addWebUiListener('sent-pg-event', function(result) {
     addPGEvent(result);
   });
 
@@ -110,7 +110,7 @@
       addSecurityEvent(securityEvent);
     });
   });
-  addWebUIListener('sent-security-event', function(result) {
+  addWebUiListener('sent-security-event', function(result) {
     addSecurityEvent(result);
   });
 
@@ -119,7 +119,7 @@
       addPGPing(pgPing);
     });
   });
-  addWebUIListener('pg-pings-update', function(result) {
+  addWebUiListener('pg-pings-update', function(result) {
     addPGPing(result);
   });
 
@@ -128,7 +128,7 @@
       addPGResponse(pgResponse);
     });
   });
-  addWebUIListener('pg-responses-update', function(result) {
+  addWebUiListener('pg-responses-update', function(result) {
     addPGResponse(result);
   });
 
@@ -137,7 +137,7 @@
       addRTLookupPing(rtLookupPing);
     });
   });
-  addWebUIListener('rt-lookup-pings-update', function(result) {
+  addWebUiListener('rt-lookup-pings-update', function(result) {
     addRTLookupPing(result);
   });
 
@@ -146,7 +146,7 @@
       addRTLookupResponse(rtLookupResponse);
     });
   });
-  addWebUIListener('rt-lookup-responses-update', function(result) {
+  addWebUiListener('rt-lookup-responses-update', function(result) {
     addRTLookupResponse(result);
   });
 
@@ -155,7 +155,7 @@
       addLogMessage(message);
     });
   });
-  addWebUIListener('log-messages-update', function(message) {
+  addWebUiListener('log-messages-update', function(message) {
     addLogMessage(message);
   });
 
@@ -164,7 +164,7 @@
       addReportingEvent(reportingEvent);
     });
   });
-  addWebUIListener('reporting-events-update', function(reportingEvent) {
+  addWebUiListener('reporting-events-update', function(reportingEvent) {
     addReportingEvent(reportingEvent);
   });
 
@@ -173,7 +173,7 @@
       addDeepScan(request);
     });
   });
-  addWebUIListener('deep-scan-request-update', function(result) {
+  addWebUiListener('deep-scan-request-update', function(result) {
     addDeepScan(result);
   });
 
diff --git a/components/services/storage/service_worker/service_worker_storage.cc b/components/services/storage/service_worker/service_worker_storage.cc
index 20e90d4c..dda0a9d 100644
--- a/components/services/storage/service_worker/service_worker_storage.cc
+++ b/components/services/storage/service_worker/service_worker_storage.cc
@@ -19,7 +19,6 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_runner_util.h"
 #include "base/task/thread_pool.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "components/services/storage/public/cpp/constants.h"
@@ -36,7 +35,8 @@
 namespace {
 
 void RunSoon(const base::Location& from_here, base::OnceClosure closure) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(closure));
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(from_here,
+                                                           std::move(closure));
 }
 
 const base::FilePath::CharType kDatabaseName[] = FILE_PATH_LITERAL("Database");
@@ -148,8 +148,8 @@
 
   database_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&FindForClientUrlInDB, database_.get(),
-                                base::ThreadTaskRunnerHandle::Get(), client_url,
-                                key, std::move(callback)));
+                                base::SequencedTaskRunner::GetCurrentDefault(),
+                                client_url, key, std::move(callback)));
 }
 
 void ServiceWorkerStorage::FindRegistrationForScope(
@@ -185,8 +185,8 @@
 
   database_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&FindForScopeInDB, database_.get(),
-                                base::ThreadTaskRunnerHandle::Get(), scope, key,
-                                std::move(callback)));
+                                base::SequencedTaskRunner::GetCurrentDefault(),
+                                scope, key, std::move(callback)));
 }
 
 void ServiceWorkerStorage::FindRegistrationForId(
@@ -221,7 +221,7 @@
 
   database_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&FindForIdInDB, database_.get(),
-                                base::ThreadTaskRunnerHandle::Get(),
+                                base::SequencedTaskRunner::GetCurrentDefault(),
                                 registration_id, key, std::move(callback)));
 }
 
@@ -247,7 +247,7 @@
 
   database_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&FindForIdOnlyInDB, database_.get(),
-                                base::ThreadTaskRunnerHandle::Get(),
+                                base::SequencedTaskRunner::GetCurrentDefault(),
                                 registration_id, std::move(callback)));
 }
 
@@ -312,7 +312,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerStorage::GetUsageForStorageKeyInDB,
-                     database_.get(), base::ThreadTaskRunnerHandle::Get(), key,
+                     database_.get(),
+                     base::SequencedTaskRunner::GetCurrentDefault(), key,
                      std::move(callback)));
 }
 
@@ -381,8 +382,8 @@
       FROM_HERE,
       base::BindOnce(
           &WriteRegistrationInDB, database_.get(),
-          base::ThreadTaskRunnerHandle::Get(), std::move(registration_data),
-          std::move(resources),
+          base::SequencedTaskRunner::GetCurrentDefault(),
+          std::move(registration_data), std::move(resources),
           base::BindOnce(&ServiceWorkerStorage::DidStoreRegistrationData,
                          weak_factory_.GetWeakPtr(), std::move(callback),
                          resources_total_size_bytes)));
@@ -564,7 +565,7 @@
       FROM_HERE,
       base::BindOnce(
           &DeleteRegistrationFromDB, database_.get(),
-          base::ThreadTaskRunnerHandle::Get(), registration_id, key,
+          base::SequencedTaskRunner::GetCurrentDefault(), registration_id, key,
           base::BindOnce(&ServiceWorkerStorage::DidDeleteRegistration,
                          weak_factory_.GetWeakPtr(), std::move(params))));
 }
@@ -820,8 +821,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerStorage::GetUserDataInDB, database_.get(),
-                     base::ThreadTaskRunnerHandle::Get(), registration_id, keys,
-                     std::move(callback)));
+                     base::SequencedTaskRunner::GetCurrentDefault(),
+                     registration_id, keys, std::move(callback)));
 }
 
 void ServiceWorkerStorage::GetUserDataByKeyPrefix(
@@ -859,7 +860,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerStorage::GetUserDataByKeyPrefixInDB,
-                     database_.get(), base::ThreadTaskRunnerHandle::Get(),
+                     database_.get(),
+                     base::SequencedTaskRunner::GetCurrentDefault(),
                      registration_id, key_prefix, std::move(callback)));
 }
 
@@ -898,7 +900,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerStorage::GetUserKeysAndDataByKeyPrefixInDB,
-                     database_.get(), base::ThreadTaskRunnerHandle::Get(),
+                     database_.get(),
+                     base::SequencedTaskRunner::GetCurrentDefault(),
                      registration_id, key_prefix, std::move(callback)));
 }
 
@@ -1025,7 +1028,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB,
-                     database_.get(), base::ThreadTaskRunnerHandle::Get(), key,
+                     database_.get(),
+                     base::SequencedTaskRunner::GetCurrentDefault(), key,
                      std::move(callback)));
 }
 
@@ -1062,8 +1066,8 @@
       FROM_HERE,
       base::BindOnce(
           &ServiceWorkerStorage::GetUserDataForAllRegistrationsByKeyPrefixInDB,
-          database_.get(), base::ThreadTaskRunnerHandle::Get(), key_prefix,
-          std::move(callback)));
+          database_.get(), base::SequencedTaskRunner::GetCurrentDefault(),
+          key_prefix, std::move(callback)));
 }
 
 void ServiceWorkerStorage::ClearUserDataForAllRegistrationsByKeyPrefix(
@@ -1292,9 +1296,9 @@
 void ServiceWorkerStorage::GetPurgeableResourceIdsForTest(
     ResourceIdsCallback callback) {
   database_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&GetPurgeableResourceIdsFromDB, database_.get(),
-                     base::ThreadTaskRunnerHandle::Get(), std::move(callback)));
+      FROM_HERE, base::BindOnce(&GetPurgeableResourceIdsFromDB, database_.get(),
+                                base::SequencedTaskRunner::GetCurrentDefault(),
+                                std::move(callback)));
 }
 
 void ServiceWorkerStorage::GetUncommittedResourceIdsForTest(
@@ -1302,7 +1306,8 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&GetUncommittedResourceIdsFromDB, database_.get(),
-                     base::ThreadTaskRunnerHandle::Get(), std::move(callback)));
+                     base::SequencedTaskRunner::GetCurrentDefault(),
+                     std::move(callback)));
 }
 
 void ServiceWorkerStorage::LazyInitialize(base::OnceClosure callback) {
@@ -1318,7 +1323,7 @@
   database_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ReadInitialDataFromDB, database_.get(),
-                     base::ThreadTaskRunnerHandle::Get(),
+                     base::SequencedTaskRunner::GetCurrentDefault(),
                      base::BindOnce(&ServiceWorkerStorage::DidReadInitialData,
                                     weak_factory_.GetWeakPtr())));
 }
@@ -1532,7 +1537,7 @@
       FROM_HERE,
       base::BindOnce(
           &ServiceWorkerStorage::CollectStaleResourcesFromDB, database_.get(),
-          base::ThreadTaskRunnerHandle::Get(),
+          base::SequencedTaskRunner::GetCurrentDefault(),
           base::BindOnce(&ServiceWorkerStorage::DidCollectStaleResources,
                          weak_factory_.GetWeakPtr())));
 }
diff --git a/components/services/storage/service_worker/service_worker_storage_control_impl.cc b/components/services/storage/service_worker/service_worker_storage_control_impl.cc
index 0453938..40d163b 100644
--- a/components/services/storage/service_worker/service_worker_storage_control_impl.cc
+++ b/components/services/storage/service_worker/service_worker_storage_control_impl.cc
@@ -80,6 +80,25 @@
   mojo::ReceiverSet<mojom::ServiceWorkerLiveVersionRef> receivers_;
 };
 
+// static
+mojo::SelfOwnedReceiverRef<mojom::ServiceWorkerStorageControl>
+ServiceWorkerStorageControlImpl::Create(
+    mojo::PendingReceiver<mojom::ServiceWorkerStorageControl> receiver,
+    const base::FilePath& user_data_directory,
+    scoped_refptr<base::SequencedTaskRunner> database_task_runner) {
+  return mojo::MakeSelfOwnedReceiver(
+      base::WrapUnique(new ServiceWorkerStorageControlImpl(
+          user_data_directory, std::move(database_task_runner))),
+      std::move(receiver));
+}
+
+ServiceWorkerStorageControlImpl::ServiceWorkerStorageControlImpl(
+    const base::FilePath& user_data_directory,
+    scoped_refptr<base::SequencedTaskRunner> database_task_runner)
+    : storage_(ServiceWorkerStorage::Create(user_data_directory,
+                                            std::move(database_task_runner))),
+      receiver_(this) {}
+
 ServiceWorkerStorageControlImpl::ServiceWorkerStorageControlImpl(
     const base::FilePath& user_data_directory,
     scoped_refptr<base::SequencedTaskRunner> database_task_runner,
diff --git a/components/services/storage/service_worker/service_worker_storage_control_impl.h b/components/services/storage/service_worker/service_worker_storage_control_impl.h
index 31574d8..5e552ce 100644
--- a/components/services/storage/service_worker/service_worker_storage_control_impl.h
+++ b/components/services/storage/service_worker/service_worker_storage_control_impl.h
@@ -15,6 +15,7 @@
 #include "components/services/storage/service_worker/service_worker_storage.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace blink {
 class StorageKey;
@@ -26,11 +27,24 @@
 
 // This class wraps ServiceWorkerStorage to implement mojo interface defined by
 // the storage service, i.e., ServiceWorkerStorageControl.
+// If kServiceWorkerStorageControlOnThreadPool is enabled,
+// ServiceWorkerStorageControlImpl is created on database_task_runner (thread
+// pool) and retained by mojo::SelfOwnedReceiver. If
+// kServiceWorkerStorageControlOnIOThread is enabled on Android,
+// ServiceWorkerStorageControlImpl is created on the IO thread and owned by
+// PartitionImpl. Otherwise, this is created on the UI thread and owned by
+// ServiceWorkerContextWrapper. In the near future,
+// kServiceWorkerStorageControlOnThreadPool will be the default for all
+// platforms.
 // TODO(crbug.com/1055677): Merge this implementation into ServiceWorkerStorage
 // and move the merged class to components/services/storage.
 class ServiceWorkerStorageControlImpl
     : public mojom::ServiceWorkerStorageControl {
  public:
+  static mojo::SelfOwnedReceiverRef<mojom::ServiceWorkerStorageControl> Create(
+      mojo::PendingReceiver<mojom::ServiceWorkerStorageControl> receiver,
+      const base::FilePath& user_data_directory,
+      scoped_refptr<base::SequencedTaskRunner> database_task_runner);
   ServiceWorkerStorageControlImpl(
       const base::FilePath& user_data_directory,
       scoped_refptr<base::SequencedTaskRunner> database_task_runner,
@@ -48,6 +62,9 @@
   void LazyInitializeForTest();
 
  private:
+  ServiceWorkerStorageControlImpl(
+      const base::FilePath& user_data_directory,
+      scoped_refptr<base::SequencedTaskRunner> database_task_runner);
   // mojom::ServiceWorkerStorageControl implementations:
   void Disable(DisableCallback callback) override;
   void Delete(DeleteCallback callback) override;
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 8011060c..bfa3907 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -214,6 +214,8 @@
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMiceTest,
                            AccountReconcilorStateScheduled);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceTest,
+                           ClearPrimaryAccountNotAllowed);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceTest,
                            DiceTokenServiceRegistration);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorDiceTest,
                            DiceReconcileWithoutSignin);
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 81d946c..0f89758 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -177,7 +177,7 @@
       case signin::AccountConsistencyMethod::kDice:
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
         return std::make_unique<signin::DiceAccountReconcilorDelegate>(
-            identity_manager);
+            identity_manager, client);
 #else
         NOTREACHED();
         return nullptr;
@@ -1084,6 +1084,32 @@
       delete;
 };
 
+TEST_F(AccountReconcilorDiceTest, ClearPrimaryAccountNotAllowed) {
+  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction()).Times(1);
+  EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(testing::_))
+      .Times(0);
+
+  test_signin_client()->set_is_clear_primary_account_allowed(
+      SigninClient::SignoutDecision::CLEAR_PRIMARY_ACCOUNT_DISALLOWED);
+  signin::SetListAccountsResponseOneAccount(kFakeEmail, kFakeGaiaId,
+                                            &test_url_loader_factory_);
+  identity_test_env()->MakePrimaryAccountAvailable(
+      kFakeEmail, signin::ConsentLevel::kSignin);
+  identity_test_env()->SetInvalidRefreshTokenForPrimaryAccount();
+  EXPECT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount(
+      signin::ConsentLevel::kSignin));
+
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  reconcilor->StartReconcile(AccountReconcilor::Trigger::kCookieChange);
+  ASSERT_TRUE(reconcilor->is_reconcile_started_);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(reconcilor->is_reconcile_started_);
+  testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
+
+  EXPECT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount(
+      signin::ConsentLevel::kSignin));
+}
+
 // Tests that the AccountReconcilor is always registered.
 TEST_F(AccountReconcilorDiceTest, DiceTokenServiceRegistration) {
   AccountReconcilor* reconcilor = GetMockReconcilor();
diff --git a/components/signin/core/browser/dice_account_reconcilor_delegate.cc b/components/signin/core/browser/dice_account_reconcilor_delegate.cc
index acba02fdc..6a74a8a 100644
--- a/components/signin/core/browser/dice_account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/dice_account_reconcilor_delegate.cc
@@ -11,22 +11,46 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/ranges/algorithm.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/public/base/consent_level.h"
 #include "components/signin/public/base/signin_client.h"
+#include "components/signin/public/base/signin_metrics.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/accounts_mutator.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/primary_account_mutator.h"
 
 namespace signin {
 
 // Revokes tokens for all accounts in chrome_accounts but the primary account.
 void RevokeAllSecondaryTokens(
     IdentityManager* identity_manager,
+    ConsentLevel consent_level,
     signin_metrics::SourceForRefreshTokenOperation source,
+    signin_metrics::ProfileSignout maybe_signout_source,
     bool revoke_only_if_in_error) {
+  // If |consent_level| is sync but there is only a primary account with Signin
+  // consent, it must be revoked.
+  bool should_revoke_primary_account =
+      consent_level == ConsentLevel::kSync &&
+      !identity_manager->HasPrimaryAccount(ConsentLevel::kSync) &&
+      identity_manager->HasPrimaryAccount(ConsentLevel::kSignin) &&
+      (!revoke_only_if_in_error ||
+       identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+           identity_manager->GetPrimaryAccountId(ConsentLevel::kSignin)));
+
+  if (should_revoke_primary_account) {
+    // The primary account should be revoked by calling |ClearPrimaryAccount|.
+    identity_manager->GetPrimaryAccountMutator()->ClearPrimaryAccount(
+        maybe_signout_source, signin_metrics::SignoutDelete::kIgnoreMetric);
+    DCHECK(identity_manager->GetAccountsWithRefreshTokens().empty());
+    return;
+  }
   // The sync account should not be removed but put in a paused state, therefore
-  // this function excludes only the primary account with sync consent.
+  // this function excludes the primary account with sync consent. In some
+  // cases, removing the primary account regardless of the consent level is not
+  // allowed (e.g. cloud-managed enterprise profiles).
   CoreAccountId primary_account =
-      identity_manager->GetPrimaryAccountId(ConsentLevel::kSync);
+      identity_manager->GetPrimaryAccountId(consent_level);
 
   auto* accounts_mutator = identity_manager->GetAccountsMutator();
   for (const CoreAccountInfo& account_info :
@@ -50,8 +74,9 @@
 }
 
 DiceAccountReconcilorDelegate::DiceAccountReconcilorDelegate(
-    IdentityManager* identity_manager)
-    : identity_manager_(identity_manager) {}
+    IdentityManager* identity_manager,
+    SigninClient* signin_client)
+    : identity_manager_(identity_manager), signin_client_(signin_client) {}
 DiceAccountReconcilorDelegate::~DiceAccountReconcilorDelegate() = default;
 
 bool DiceAccountReconcilorDelegate::IsReconcileEnabled() const {
@@ -155,19 +180,31 @@
     return false;
   }
 
-  RevokeAllSecondaryTokens(identity_manager_,
-                           signin_metrics::SourceForRefreshTokenOperation::
-                               kAccountReconcilor_Reconcile,
-                           /*revoke_only_if_in_error=*/false);
+  RevokeAllSecondaryTokens(
+      identity_manager_, GetConsentLevelForPrimaryAccount(),
+      signin_metrics::SourceForRefreshTokenOperation::
+          kAccountReconcilor_Reconcile,
+      signin_metrics::ProfileSignout::ACCOUNT_RECONCILOR_RECONCILE,
+      /*revoke_only_if_in_error=*/false);
   return true;
 }
 
+ConsentLevel DiceAccountReconcilorDelegate::GetConsentLevelForPrimaryAccount()
+    const {
+  // In some cases, clearing the primary account is not allowed regardless of
+  // the consent level (e.g. cloud-managed profiles). In these cases, the dice
+  // account reconcilor delegate should never remove the primary account
+  // regardless of the consent.
+  return signin_client_->IsClearPrimaryAccountAllowed() ? ConsentLevel::kSync
+                                                        : ConsentLevel::kSignin;
+}
+
 bool DiceAccountReconcilorDelegate::ShouldRevokeTokensBeforeMultilogin(
     const std::vector<CoreAccountId>& chrome_accounts,
     const std::vector<gaia::ListedAccount>& gaia_accounts,
     bool first_execution) const {
-  CoreAccountId primary_account =
-      identity_manager_->GetPrimaryAccountId(ConsentLevel::kSync);
+  CoreAccountId primary_account = identity_manager_->GetPrimaryAccountId(
+      GetConsentLevelForPrimaryAccount());
 
   bool primary_has_error =
       identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
@@ -179,8 +216,8 @@
     return false;
 
   // On first execution, it's generally OK to reorder accounts. Only logout if
-  // the Sync account needs to be removed from the first position in cookies (it
-  // would be unacceptable to swap another account there).
+  // the primary account needs to be removed from the first position in cookies
+  // (it would be unacceptable to swap another account there).
   if (first_execution) {
     return !primary_account.empty() && primary_has_error &&
            gaia_accounts[0].id == primary_account && gaia_accounts[0].valid;
@@ -265,39 +302,46 @@
 void DiceAccountReconcilorDelegate::
     RevokeSecondaryTokensBeforeReconcileIfNeeded() {
   RevokeAllSecondaryTokens(identity_manager_,
+                           GetConsentLevelForPrimaryAccount(),
                            signin_metrics::SourceForRefreshTokenOperation::
                                kAccountReconcilor_GaiaCookiesUpdated,
+                           signin_metrics::ProfileSignout::GAIA_COOKIE_UPDATED,
                            /*revoke_only_if_in_error=*/true);
 }
 
 void DiceAccountReconcilorDelegate::OnAccountsCookieDeletedByUserAction(
     bool synced_data_deletion_in_progress) {
+  ConsentLevel consent_level = GetConsentLevelForPrimaryAccount();
   // Revoke secondary tokens to avoid reconcilor rebuilding cookies.
-  RevokeAllSecondaryTokens(identity_manager_,
-                           signin_metrics::SourceForRefreshTokenOperation::
-                               kAccountReconcilor_GaiaCookiesDeletedByUser,
-                           /*revoke_only_if_in_error=*/false);
+  RevokeAllSecondaryTokens(
+      identity_manager_, consent_level,
+      signin_metrics::SourceForRefreshTokenOperation::
+          kAccountReconcilor_GaiaCookiesDeletedByUser,
+      signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES,
+      /*revoke_only_if_in_error=*/false);
 
-  if (!identity_manager_->HasPrimaryAccount(ConsentLevel::kSync))
+  if (!identity_manager_->HasPrimaryAccount(consent_level))
     return;
 
-  DCHECK_EQ(GetConsentLevelForPrimaryAccount(), ConsentLevel::kSync);
-  CoreAccountId primary_sync_account =
-      identity_manager_->GetPrimaryAccountId(ConsentLevel::kSync);
-
-  // Sync account should be paused if the account cookie is deleted by user
-  // action. If sync data deletion in progress, avoid invalidating the sync
-  // account unless it is already in a persistent error state. This is needed to
-  // ensure the data gets deleted from the google account.
-  if (!synced_data_deletion_in_progress ||
-      identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
-          primary_sync_account)) {
-    // Invalidate the primary token, but do not revoke it.
-    auto* accounts_mutator = identity_manager_->GetAccountsMutator();
-    accounts_mutator->InvalidateRefreshTokenForPrimaryAccount(
-        signin_metrics::SourceForRefreshTokenOperation::
-            kAccountReconcilor_GaiaCookiesDeletedByUser);
+  if (synced_data_deletion_in_progress &&
+      identity_manager_->HasPrimaryAccount(ConsentLevel::kSync)) {
+    // If sync data deletion in progress, avoid invalidating the sync
+    // account unless it is already in a persistent error state. This is needed
+    // to ensure the data gets deleted from the google account.
+    CoreAccountId primary_sync_account =
+        identity_manager_->GetPrimaryAccountId(ConsentLevel::kSync);
+    if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+            primary_sync_account)) {
+      return;
+    }
   }
+
+  // The primary account should be paused if the account cookie is deleted by
+  // user action.
+  auto* accounts_mutator = identity_manager_->GetAccountsMutator();
+  accounts_mutator->InvalidateRefreshTokenForPrimaryAccount(
+      signin_metrics::SourceForRefreshTokenOperation::
+          kAccountReconcilor_GaiaCookiesDeletedByUser);
 }
 
 void DiceAccountReconcilorDelegate::OnReconcileFinished(
diff --git a/components/signin/core/browser/dice_account_reconcilor_delegate.h b/components/signin/core/browser/dice_account_reconcilor_delegate.h
index 253d90c0..33ac57a 100644
--- a/components/signin/core/browser/dice_account_reconcilor_delegate.h
+++ b/components/signin/core/browser/dice_account_reconcilor_delegate.h
@@ -5,8 +5,10 @@
 #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_DICE_ACCOUNT_RECONCILOR_DELEGATE_H_
 #define COMPONENTS_SIGNIN_CORE_BROWSER_DICE_ACCOUNT_RECONCILOR_DELEGATE_H_
 
+#include "base/memory/raw_ptr.h"
 #include "components/signin/core/browser/account_reconcilor_delegate.h"
-#include "components/signin/public/base/account_consistency_method.h"
+#include "components/signin/public/base/consent_level.h"
+#include "components/signin/public/base/signin_client.h"
 
 namespace signin {
 
@@ -15,7 +17,8 @@
 // AccountReconcilorDelegate specialized for Dice.
 class DiceAccountReconcilorDelegate : public AccountReconcilorDelegate {
  public:
-  explicit DiceAccountReconcilorDelegate(IdentityManager* identity_manager);
+  DiceAccountReconcilorDelegate(IdentityManager* identity_manager,
+                                SigninClient* signin_client);
 
   DiceAccountReconcilorDelegate(const DiceAccountReconcilorDelegate&) = delete;
   DiceAccountReconcilorDelegate& operator=(
@@ -34,6 +37,7 @@
       const std::vector<CoreAccountId>& chrome_accounts,
       const std::vector<gaia::ListedAccount>& gaia_accounts,
       bool first_execution) override;
+  ConsentLevel GetConsentLevelForPrimaryAccount() const override;
 
  private:
   // Possible inconsistency reasons between tokens and gaia cookies.
@@ -110,6 +114,7 @@
       bool first_execution) const;
 
   const raw_ptr<IdentityManager> identity_manager_;
+  const raw_ptr<SigninClient> signin_client_;
 
   // Last known "first account". Used when cookies are lost as a best guess.
   CoreAccountId last_known_first_account_;
diff --git a/components/signin/core/browser/resources/signin_internals.js b/components/signin/core/browser/resources/signin_internals.js
index 0eba1fe..aafd1f3 100644
--- a/components/signin/core/browser/resources/signin_internals.js
+++ b/components/signin/core/browser/resources/signin_internals.js
@@ -8,7 +8,7 @@
 
 import 'chrome://resources/js/jstemplate_compiled.js';
 import './strings.m.js';
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 // TODO(vishwath): This function is identical to the one in sync_internals.js
@@ -80,8 +80,8 @@
 // On load, do an initial refresh and register refreshSigninInfo to be invoked
 // whenever we get new signin information from SigninInternalsUI.
 function onLoad() {
-  addWebUIListener('signin-info-changed', refreshSigninInfo);
-  addWebUIListener('update-cookie-accounts', updateCookieAccounts);
+  addWebUiListener('signin-info-changed', refreshSigninInfo);
+  addWebUiListener('update-cookie-accounts', updateCookieAccounts);
 
   sendWithPromise('getSigninInfo').then(refreshSigninInfo);
 }
diff --git a/components/signin/internal/identity_manager/accounts_mutator_impl.cc b/components/signin/internal/identity_manager/accounts_mutator_impl.cc
index d468f3d..1fd8a0ea 100644
--- a/components/signin/internal/identity_manager/accounts_mutator_impl.cc
+++ b/components/signin/internal/identity_manager/accounts_mutator_impl.cc
@@ -100,9 +100,9 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   NOTREACHED();
 #endif
-  DCHECK(primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync));
+  DCHECK(primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSignin));
   CoreAccountInfo primary_account_info =
-      primary_account_manager_->GetPrimaryAccountInfo(ConsentLevel::kSync);
+      primary_account_manager_->GetPrimaryAccountInfo(ConsentLevel::kSignin);
   AddOrUpdateAccount(primary_account_info.gaia, primary_account_info.email,
                      GaiaConstants::kInvalidRefreshToken,
                      primary_account_info.is_under_advanced_protection, source);
diff --git a/components/signin/public/base/signin_client.cc b/components/signin/public/base/signin_client.cc
index 337a161..50f9b3a 100644
--- a/components/signin/public/base/signin_client.cc
+++ b/components/signin/public/base/signin_client.cc
@@ -10,3 +10,7 @@
   // Allow sign out to continue.
   std::move(on_signout_decision_reached).Run(SignoutDecision::ALLOW);
 }
+
+bool SigninClient::IsClearPrimaryAccountAllowed() const {
+  return true;
+}
diff --git a/components/signin/public/base/signin_client.h b/components/signin/public/base/signin_client.h
index 9b9cb74..c694cc46 100644
--- a/components/signin/public/base/signin_client.h
+++ b/components/signin/public/base/signin_client.h
@@ -13,6 +13,7 @@
 #include "build/chromeos_buildflags.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/public/base/account_consistency_method.h"
+#include "components/signin/public/base/consent_level.h"
 #include "components/signin/public/base/signin_metrics.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
@@ -68,6 +69,10 @@
   // Returns the CookieManager for the client.
   virtual network::mojom::CookieManager* GetCookieManager() = 0;
 
+  // Returns true if clearing the primary account is allowed regardless of the
+  // consent level.
+  virtual bool IsClearPrimaryAccountAllowed() const;
+
   // Called before Google sign-out started. Implementers must run the
   // |on_signout_decision_reached|, passing a SignoutDecision to allow/disallow
   // sign-out to continue. When to disallow sign-out is implementation specific.
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index 19ed752..2dd330a 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -77,6 +77,10 @@
   ACCOUNT_EMAIL_UPDATED = 20,
   // User clicked on sign-out from the clear browsing data page.
   USER_CLICKED_SIGNOUT_FROM_CLEAR_BROWSING_DATA_PAGE = 21,
+  // Profile Signout during reconciliation triggered by a Gaia cookie update.
+  GAIA_COOKIE_UPDATED = 22,
+  // Profile Signout during reconciliation.
+  ACCOUNT_RECONCILOR_RECONCILE = 23,
   // Keep this as the last enum.
   NUM_PROFILE_SIGNOUT_METRICS,
 };
diff --git a/components/signin/public/base/test_signin_client.cc b/components/signin/public/base/test_signin_client.cc
index 3d2a12d..ffbec7f 100644
--- a/components/signin/public/base/test_signin_client.cc
+++ b/components/signin/public/base/test_signin_client.cc
@@ -34,6 +34,10 @@
   return pref_service_;
 }
 
+bool TestSigninClient::IsClearPrimaryAccountAllowed() const {
+  return is_clear_primary_account_allowed_ == SignoutDecision::ALLOW;
+}
+
 void TestSigninClient::PreSignOut(
     base::OnceCallback<void(SignoutDecision)> on_signout_decision_reached,
     signin_metrics::ProfileSignout signout_source_metric) {
diff --git a/components/signin/public/base/test_signin_client.h b/components/signin/public/base/test_signin_client.h
index b27b577..fab5da91 100644
--- a/components/signin/public/base/test_signin_client.h
+++ b/components/signin/public/base/test_signin_client.h
@@ -51,6 +51,10 @@
   // once there is a unit test that requires it.
   PrefService* GetPrefs() override;
 
+  // Returns true if clear primary account is allowed regardless of the consent
+  // level.
+  bool IsClearPrimaryAccountAllowed() const override;
+
   // Allow or disallow continuation of sign-out depending on value of
   // |is_clear_primary_account_allowed_|;
   void PreSignOut(
diff --git a/components/signin/public/identity_manager/identity_test_utils.cc b/components/signin/public/identity_manager/identity_test_utils.cc
index 385afe72..b03963b1 100644
--- a/components/signin/public/identity_manager/identity_test_utils.cc
+++ b/components/signin/public/identity_manager/identity_test_utils.cc
@@ -197,9 +197,9 @@
 
 void SetInvalidRefreshTokenForPrimaryAccount(
     IdentityManager* identity_manager) {
-  DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSync));
+  DCHECK(identity_manager->HasPrimaryAccount(ConsentLevel::kSignin));
   CoreAccountId account_id =
-      identity_manager->GetPrimaryAccountId(ConsentLevel::kSync);
+      identity_manager->GetPrimaryAccountId(ConsentLevel::kSignin);
 
   SetInvalidRefreshTokenForAccount(identity_manager, account_id);
 }
diff --git a/components/translate/translate_internals/translate_internals.js b/components/translate/translate_internals/translate_internals.js
index ff05ea4..9c248385 100644
--- a/components/translate/translate_internals/translate_internals.js
+++ b/components/translate/translate_internals/translate_internals.js
@@ -9,7 +9,7 @@
 import './strings.m.js';
 import 'chrome://resources/cr_elements/cr_tab_box/cr_tab_box.js';
 
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {$} from 'chrome://resources/js/util.js';
 
@@ -550,13 +550,13 @@
 }
 
 function addMessageHandlers() {
-  addWebUIListener('languageDetectionInfoAdded', onLanguageDetectionInfoAdded);
-  addWebUIListener('prefsUpdated', onPrefsUpdated);
-  addWebUIListener('supportedLanguagesUpdated', onSupportedLanguagesUpdated);
-  addWebUIListener('countryUpdated', onCountryUpdated);
-  addWebUIListener('translateErrorDetailsAdded', onTranslateErrorDetailsAdded);
-  addWebUIListener('translateEventDetailsAdded', onTranslateEventDetailsAdded);
-  addWebUIListener('translateInitDetailsAdded', onTranslateInitDetailsAdded);
+  addWebUiListener('languageDetectionInfoAdded', onLanguageDetectionInfoAdded);
+  addWebUiListener('prefsUpdated', onPrefsUpdated);
+  addWebUiListener('supportedLanguagesUpdated', onSupportedLanguagesUpdated);
+  addWebUiListener('countryUpdated', onCountryUpdated);
+  addWebUiListener('translateErrorDetailsAdded', onTranslateErrorDetailsAdded);
+  addWebUiListener('translateEventDetailsAdded', onTranslateEventDetailsAdded);
+  addWebUiListener('translateInitDetailsAdded', onTranslateInitDetailsAdded);
 }
 
 /**
diff --git a/components/user_actions_ui/resources/user_actions.js b/components/user_actions_ui/resources/user_actions.js
index 11089436e..3ae4537 100644
--- a/components/user_actions_ui/resources/user_actions.js
+++ b/components/user_actions_ui/resources/user_actions.js
@@ -12,7 +12,7 @@
  * callbacks from the C++ code saying that a new user action was seen.
  */
 
-import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 /**
@@ -33,7 +33,7 @@
 }
 
 document.addEventListener('DOMContentLoaded', function() {
-  addWebUIListener('user-action', observeUserAction);
+  addWebUiListener('user-action', observeUserAction);
   // <if expr="not is_ios">
   chrome.send('pageLoaded');
   // </if>
diff --git a/components/version_ui/resources/about_version.js b/components/version_ui/resources/about_version.js
index 8826aaa..5d7f315 100644
--- a/components/version_ui/resources/about_version.js
+++ b/components/version_ui/resources/about_version.js
@@ -11,7 +11,7 @@
 // </if>
 
 import './strings.m.js';
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 /**
diff --git a/components/webapps/browser/BUILD.gn b/components/webapps/browser/BUILD.gn
index b1229ca..9707614 100644
--- a/components/webapps/browser/BUILD.gn
+++ b/components/webapps/browser/BUILD.gn
@@ -46,6 +46,7 @@
     "//base",
     "//components/back_forward_cache",
     "//components/content_settings/core/browser",
+    "//components/password_manager/content/common",
     "//components/permissions",
     "//components/security_state/core",
     "//components/site_engagement/content",
diff --git a/components/webapps/browser/DEPS b/components/webapps/browser/DEPS
index 81d1c429..0cecda19 100644
--- a/components/webapps/browser/DEPS
+++ b/components/webapps/browser/DEPS
@@ -3,6 +3,7 @@
   "+components/content_settings",
   "+components/infobars",
   "+components/messages",
+  "+components/password_manager",
   "+components/permissions",
   "+components/prefs",
   "+components/security_state/core",
diff --git a/components/webapps/browser/banners/app_banner_manager.cc b/components/webapps/browser/banners/app_banner_manager.cc
index d6029d7b..91039e4 100644
--- a/components/webapps/browser/banners/app_banner_manager.cc
+++ b/components/webapps/browser/banners/app_banner_manager.cc
@@ -20,6 +20,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/back_forward_cache/back_forward_cache_disable.h"
+#include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/site_engagement/content/site_engagement_service.h"
 #include "components/webapps/browser/banners/app_banner_metrics.h"
 #include "components/webapps/browser/banners/app_banner_settings_helper.h"
@@ -263,9 +264,12 @@
   if (render_frame_host && !render_frame_host->IsInPrimaryMainFrame())
     return true;
 
-  // There is never a need to trigger a banner for a WebUI page.
-  if (content::HasWebUIScheme(url))
+  // There is never a need to trigger a banner for a WebUI page, except
+  // for PasswordManager WebUI.
+  if (content::HasWebUIScheme(url) &&
+      (url.host() != password_manager::kChromeUIPasswordManagerHost)) {
     return true;
+  }
 
   return false;
 }
@@ -381,6 +385,23 @@
   manifest_ = data.manifest->Clone();
   manifest_id_ = blink::GetIdFromManifest(manifest());
 
+  // Skip checks for PasswordManager WebUI page.
+  if (content::HasWebUIScheme(validated_url_) &&
+      (validated_url_.host() ==
+       password_manager::kChromeUIPasswordManagerHost)) {
+    if (IsWebAppConsideredInstalled()) {
+      TrackDisplayEvent(DISPLAY_EVENT_INSTALLED_PREVIOUSLY);
+      SetInstallableWebAppCheckResult(
+          InstallableWebAppCheckResult::kNo_AlreadyInstalled);
+      Stop(ALREADY_INSTALLED);
+    } else {
+      SetInstallableWebAppCheckResult(
+          InstallableWebAppCheckResult::kYes_ByUserRequest);
+      Stop(NO_ERROR_DETECTED);
+    }
+    return;
+  }
+
   PerformInstallableChecks();
 }
 
diff --git a/content/browser/cross_origin_opener_policy_browsertest.cc b/content/browser/cross_origin_opener_policy_browsertest.cc
index b2e80c32..efbdd0f 100644
--- a/content/browser/cross_origin_opener_policy_browsertest.cc
+++ b/content/browser/cross_origin_opener_policy_browsertest.cc
@@ -120,6 +120,30 @@
   return http_response;
 }
 
+std::unique_ptr<net::test_server::HttpResponse>
+RedirectToTargetOnSecondNavigation(
+    unsigned int& navigation_counter,
+    const net::test_server::HttpRequest& request) {
+  ++navigation_counter;
+  if (navigation_counter == 1) {
+    auto http_response =
+        std::make_unique<net::test_server::BasicHttpResponse>();
+    http_response->set_code(net::HttpStatusCode::HTTP_OK);
+    return http_response;
+  }
+
+  GURL request_url = request.GetURL();
+  std::string dest =
+      base::UnescapeBinaryURLComponent(request_url.query_piece());
+  net::test_server::RequestQuery query =
+      net::test_server::ParseQuery(request_url);
+
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
+  http_response->set_code(net::HttpStatusCode::HTTP_FOUND);
+  http_response->AddCustomHeader("Location", dest);
+  return http_response;
+}
+
 class CrossOriginOpenerPolicyBrowserTest
     : public ContentBrowserTest,
       public ::testing::WithParamInterface<std::tuple<std::string, bool>> {
@@ -184,6 +208,13 @@
         "/redirect-with-coop-coep-headers",
         base::BindRepeating(CrossOriginIsolatedCrossOriginRedirectHandler)));
 
+    unsigned int navigation_counter = 0;
+    https_server_.RegisterDefaultHandler(base::BindRepeating(
+        &net::test_server::HandlePrefixedRequest,
+        "/redirect-to-target-on-second-navigation",
+        base::BindRepeating(&RedirectToTargetOnSecondNavigation,
+                            base::OwnedRef(navigation_counter))));
+
     ASSERT_TRUE(https_server()->Start());
   }
 
@@ -3276,6 +3307,33 @@
   EXPECT_FALSE(WaitForLoadStop(web_contents()));
 }
 
+// Regression test for https://crbug.com/1374705.
+IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
+                       ReloadRedirectsToCoopPage) {
+  GURL coop_page(
+      https_server()->GetURL("a.test",
+                             "/set-header?"
+                             "Cross-Origin-Opener-Policy: same-origin"));
+  GURL redirect_page(https_server()->GetURL(
+      "a.test",
+      "/redirect-to-target-on-second-navigation?" + coop_page.spec()));
+
+  // Navigate to the redirect page. On the first navigation, this is a simple
+  // empty page with no headers.
+  EXPECT_TRUE(NavigateToURL(shell(), redirect_page));
+  scoped_refptr<SiteInstanceImpl> main_si =
+      current_frame_host()->GetSiteInstance();
+  EXPECT_EQ(current_frame_host()->GetLastCommittedURL(), redirect_page);
+
+  // Reload. This time we should be redirected to a COOP: same-origin page.
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  EXPECT_EQ(current_frame_host()->GetLastCommittedURL(), coop_page);
+
+  // We should have swapped BrowsingInstance.
+  EXPECT_FALSE(
+      main_si->IsRelatedSiteInstance(current_frame_host()->GetSiteInstance()));
+}
+
 IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
                        CrossOriginRedirectHasProperCrossOriginIsolatedState) {
   GURL non_isolated_page(
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index 61c67e9..f20b649a 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -1654,25 +1654,6 @@
   if (is_same_document)
     return ShouldSwapBrowsingInstance::kNo_SameDocumentNavigation;
 
-  // If new_entry already has a SiteInstance, assume it is correct.  We only
-  // need to force a swap if it is in a different BrowsingInstance.
-  if (destination_instance) {
-    // If we are doing an history navigation/reload and end up failing, it might
-    // not be suitable to host the error page in the original SiteInstance.
-    // Error pages have a Cross-Origin-Opener-Policy of 'unsafe-none' and might
-    // end up in a different BrowsingInstance.
-    if (is_failure && cross_origin_opener_policy_mismatch)
-      return ShouldSwapBrowsingInstance::kYes_ForceSwap;
-
-    bool should_swap = !destination_instance->IsRelatedSiteInstance(
-        render_frame_host_->GetSiteInstance());
-    if (should_swap) {
-      return ShouldSwapBrowsingInstance::kYes_ForceSwap;
-    } else {
-      return ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance;
-    }
-  }
-
   // Check for reasons to swap processes even if we are in a process model that
   // doesn't usually swap (e.g., process-per-tab).  Any time we return true,
   // the new URL will be rendered in a new SiteInstance AND BrowsingInstance.
@@ -1771,26 +1752,6 @@
     return ShouldSwapBrowsingInstance::kYes_ForceSwap;
   }
 
-  // If this is a cross-site navigation, we may be able to force a
-  // BrowsingInstance swap to avoid unneeded process sharing. This is done for
-  // certain main frame browser-initiated navigations where we can't use
-  // |source_instance| and we don't need to preserve scripting
-  // relationship for it (for isolated error pages).
-  // See https://crbug.com/803367.
-  bool is_for_isolated_error_page =
-      is_failure && frame_tree_node_->IsErrorPageIsolationEnabled();
-
-  if (current_instance->HasSite() &&
-      !render_frame_host_->IsNavigationSameSite(destination_url_info) &&
-      !CanUseSourceSiteInstance(destination_url_info, source_instance,
-                                was_server_redirect, is_failure) &&
-      !is_for_isolated_error_page &&
-      IsBrowsingInstanceSwapAllowedForPageTransition(transition,
-                                                     destination_url) &&
-      render_frame_host_->has_committed_any_navigation()) {
-    return ShouldSwapBrowsingInstance::kYes_ForceSwap;
-  }
-
   // If the navigation should end up in a different StoragePartition, create a
   // new BrowsingInstance, as we can only have one StoragePartition per
   // BrowsingInstance.
@@ -1807,6 +1768,53 @@
     return ShouldSwapBrowsingInstance::kYes_ForceSwap;
   }
 
+  // When doing a history navigation, we cannot assume that the page will behave
+  // in the same way as it did previously. It could change headers, lead to an
+  // error page, etc. We only check the destination_instance once we're done
+  // verifying that up-to-date security reasons do not require a
+  // BrowsingInstance swap. On the other hand we should use the
+  // destination_instance if suitable instead of swapping to a new
+  // BrowsingInstance. This is why this block is after security checks, but
+  // before proactive BrowsingInstance swap.
+  if (destination_instance) {
+    // TODO(ahemery): We should not have to specify here if we are going to swap
+    // BrowsingInstance. DetermineSiteInstanceForURL will reuse the
+    // destination_instance unless it is unfit because of a security concern
+    // flagged by above blocks. This is only used by BackForwardCache metrics to
+    // know if we have swapped BrowsingInstance, and it would be more
+    // appropriate to get this information in DetermineSiteInstanceForURL.
+    bool should_swap =
+        !destination_instance->IsRelatedSiteInstance(current_instance);
+    if (should_swap) {
+      return ShouldSwapBrowsingInstance::kYes_ForceSwap;
+    } else {
+      return ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance;
+    }
+  }
+
+  // If this is a cross-site navigation, we may be able to force a
+  // BrowsingInstance swap to avoid unneeded process sharing. This is done for
+  // certain main frame browser-initiated navigations where we can't use
+  // |source_instance| and we don't need to preserve scripting
+  // relationship for it (for isolated error pages).
+  // See https://crbug.com/803367.
+  // TODO(https://crbug.com/1366827): This should probably be considered a
+  // a speculative BrowsingInstance swap. It is not required for security and
+  // needs to be treated after the history navigation block
+  bool is_for_isolated_error_page =
+      is_failure && frame_tree_node_->IsErrorPageIsolationEnabled();
+
+  if (current_instance->HasSite() &&
+      !render_frame_host_->IsNavigationSameSite(destination_url_info) &&
+      !CanUseSourceSiteInstance(destination_url_info, source_instance,
+                                was_server_redirect, is_failure) &&
+      !is_for_isolated_error_page &&
+      IsBrowsingInstanceSwapAllowedForPageTransition(transition,
+                                                     destination_url) &&
+      render_frame_host_->has_committed_any_navigation()) {
+    return ShouldSwapBrowsingInstance::kYes_ForceSwap;
+  }
+
   // Experimental mode to swap BrowsingInstances on most navigations when there
   // are no other windows in the BrowsingInstance.
   return ShouldProactivelySwapBrowsingInstance(destination_url_info, is_reload,
@@ -2246,35 +2254,42 @@
   // If the entry has an instance already we should usually use it, unless it is
   // no longer suitable.
   if (dest_instance) {
-    // Note: The later call to IsSuitableForUrlInfo does not have context about
-    // error page navigations, so we cannot rely on it to return correct value
-    // when error pages are involved.
-    if (IsSiteInstanceCompatibleWithErrorIsolation(
-            dest_instance, *frame_tree_node_, is_failure)) {
-      if (IsSiteInstanceCompatibleWithWebExposedIsolation(
-              dest_instance, dest_url_info.web_exposed_isolation_info)) {
-        // TODO(nasko,creis): The check whether data: or about: URLs are allowed
-        // to commit in the current process should be in IsSuitableForUrlInfo.
-        // However, making this change has further implications and needs more
-        // investigation of what behavior changes. For now, use a conservative
-        // approach and explicitly check before calling IsSuitableForUrlInfo.
-        SiteInstanceImpl* dest_instance_impl =
-            static_cast<SiteInstanceImpl*>(dest_instance);
-        // Make sure that if the destination frame is sandboxed that we don't
-        // skip the IsSuitableForUrlInfo() check. Note that it's impossible to
-        // have a sandboxed parent but unsandboxed child.
-        bool is_data_or_about_and_not_sandboxed =
-            IsDataOrAbout(dest_url_info.url) && !dest_url_info.is_sandboxed;
-        if (is_data_or_about_and_not_sandboxed ||
-            dest_instance_impl->IsSuitableForUrlInfo(dest_url_info)) {
-          // If we are forcing a swap, this should be in a different
-          // BrowsingInstance.
-          if (force_browsing_instance_swap) {
-            CHECK(!dest_instance->IsRelatedSiteInstance(
-                render_frame_host_->GetSiteInstance()));
+    // If we've decided that the target SiteInstance cannot be in the same
+    // BrowsingInstance, and that the dest_instance is, we should not reuse it.
+    if (!force_browsing_instance_swap ||
+        !dest_instance->IsRelatedSiteInstance(current_instance)) {
+      // Note: The later call to IsSuitableForUrlInfo does not have context
+      // about error page navigations, so we cannot rely on it to return correct
+      // value when error pages are involved.
+      if (IsSiteInstanceCompatibleWithErrorIsolation(
+              dest_instance, *frame_tree_node_, is_failure)) {
+        if (IsSiteInstanceCompatibleWithWebExposedIsolation(
+                dest_instance, dest_url_info.web_exposed_isolation_info)) {
+          // TODO(nasko,creis): The check whether data: or about: URLs are
+          // allowed to commit in the current process should be in
+          // IsSuitableForUrlInfo. However, making this change has further
+          // implications and needs more investigation of what behavior changes.
+          // For now, use a conservative approach and explicitly check before
+          // calling IsSuitableForUrlInfo.
+          SiteInstanceImpl* dest_instance_impl =
+              static_cast<SiteInstanceImpl*>(dest_instance);
+          // Make sure that if the destination frame is sandboxed that we don't
+          // skip the IsSuitableForUrlInfo() check. Note that it's impossible to
+          // have a sandboxed parent but unsandboxed child.
+          bool is_data_or_about_and_not_sandboxed =
+              IsDataOrAbout(dest_url_info.url) && !dest_url_info.is_sandboxed;
+          if (is_data_or_about_and_not_sandboxed ||
+              dest_instance_impl->IsSuitableForUrlInfo(dest_url_info)) {
+            // If we are forcing a swap, this should be in a different
+            // BrowsingInstance.
+            if (force_browsing_instance_swap) {
+              CHECK(!dest_instance->IsRelatedSiteInstance(
+                  render_frame_host_->GetSiteInstance()));
+            }
+            AppendReason(reason,
+                         "DetermineSiteInstanceForURL => dest_instance");
+            return SiteInstanceDescriptor(dest_instance);
           }
-          AppendReason(reason, "DetermineSiteInstanceForURL => dest_instance");
-          return SiteInstanceDescriptor(dest_instance);
         }
       }
     }
diff --git a/content/browser/resources/service_worker/serviceworker_internals.js b/content/browser/resources/service_worker/serviceworker_internals.js
index d44d5e0..2b4b1cb 100644
--- a/content/browser/resources/service_worker/serviceworker_internals.js
+++ b/content/browser/resources/service_worker/serviceworker_internals.js
@@ -4,17 +4,17 @@
 
 import 'chrome://resources/js/jstemplate_compiled.js';
 
-import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 function initialize() {
-  addWebUIListener('partition-data', onPartitionData);
-  addWebUIListener('running-state-changed', onRunningStateChanged);
-  addWebUIListener('error-reported', onErrorReported);
-  addWebUIListener('console-message-reported', onConsoleMessageReported);
-  addWebUIListener('version-state-changed', onVersionStateChanged);
-  addWebUIListener('registration-completed', onRegistrationCompleted);
-  addWebUIListener('registration-deleted', onRegistrationDeleted);
+  addWebUiListener('partition-data', onPartitionData);
+  addWebUiListener('running-state-changed', onRunningStateChanged);
+  addWebUiListener('error-reported', onErrorReported);
+  addWebUiListener('console-message-reported', onConsoleMessageReported);
+  addWebUiListener('version-state-changed', onVersionStateChanged);
+  addWebUiListener('registration-completed', onRegistrationCompleted);
+  addWebUiListener('registration-deleted', onRegistrationDeleted);
   update();
 }
 
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 4a5e2f20..1d4d5a1 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -394,12 +394,7 @@
 
   void SetUpOnMainThread() override {
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
-    StoragePartition* partition = shell()
-                                      ->web_contents()
-                                      ->GetBrowserContext()
-                                      ->GetDefaultStoragePartition();
-    wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
-        partition->GetServiceWorkerContext());
+    SetServiceWorkerContextWrapper();
     ShellContentBrowserClient::Get()
         ->browser_context()
         ->set_client_hints_controller_delegate(
@@ -417,6 +412,15 @@
     wrapper_ = nullptr;
   }
 
+  void SetServiceWorkerContextWrapper() {
+    StoragePartition* partition = shell()
+                                      ->web_contents()
+                                      ->GetBrowserContext()
+                                      ->GetDefaultStoragePartition();
+    wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
+        partition->GetServiceWorkerContext());
+  }
+
   // Starts the test server and navigates the renderer to an empty page. Call
   // this after adding all request handlers to the test server. Adding handlers
   // after the test server has started is not allowed.
@@ -4235,4 +4239,119 @@
       static_cast<int>(blink::ServiceWorkerStatusCode::kOk), 1);
 }
 
+enum class ServiceWorkerBypassFetchHandlerBypassedOriginType {
+  kBypassed,
+  kNotBypassed
+};
+
+class ServiceWorkerBypassFetchHandlerTest
+    : public ServiceWorkerBrowserTest,
+      public testing::WithParamInterface<
+          ServiceWorkerBypassFetchHandlerBypassedOriginType> {
+ public:
+  ServiceWorkerBypassFetchHandlerTest() {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{features::kServiceWorkerBypassFetchHandler,
+          {{"origins_to_bypass", "https://a.test"}}}},
+        {});
+  }
+  ~ServiceWorkerBypassFetchHandlerTest() override = default;
+
+  void SetUpOnMainThread() override {
+    SetServiceWorkerContextWrapper();
+    host_resolver()->AddRule("*", "127.0.0.1");
+    https_server_.ServeFilesFromSourceDirectory(GetTestDataFilePath());
+    https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+    net::test_server::RegisterDefaultHandlers(&https_server_);
+    ASSERT_TRUE(https_server()->Start());
+  }
+
+  net::EmbeddedTestServer* https_server() { return &https_server_; }
+
+  WebContents* web_contents() const { return shell()->web_contents(); }
+
+  RenderFrameHost* GetPrimaryMainFrame() {
+    return web_contents()->GetPrimaryMainFrame();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    ServiceWorkerBypassFetchHandlerTest,
+    testing::Values(
+        ServiceWorkerBypassFetchHandlerBypassedOriginType::kBypassed,
+        ServiceWorkerBypassFetchHandlerBypassedOriginType::kNotBypassed));
+
+IN_PROC_BROWSER_TEST_P(ServiceWorkerBypassFetchHandlerTest, UrlInAllowList) {
+  std::string origin;
+  switch (GetParam()) {
+    case ServiceWorkerBypassFetchHandlerBypassedOriginType::kBypassed:
+      origin = "a.test";
+      break;
+    case ServiceWorkerBypassFetchHandlerBypassedOriginType::kNotBypassed:
+      origin = "b.test";
+      break;
+  }
+
+  const GURL create_service_worker_url(https_server()->GetURL(
+      origin, "/service_worker/create_service_worker.html"));
+  const GURL out_scope_url(https_server()->GetURL(origin, "/empty.html"));
+  const GURL in_scope_url(
+      https_server()->GetURL(origin, "/service_worker/empty.html"));
+
+  // Register a service worker.
+  WorkerRunningStatusObserver observer1(public_context());
+  EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url));
+  EXPECT_EQ("DONE",
+            EvalJs(GetPrimaryMainFrame(),
+                   "register('/service_worker/fetch_event_pass_through.js')"));
+  observer1.WaitUntilRunning();
+  scoped_refptr<ServiceWorkerVersion> version =
+      wrapper()->GetLiveVersion(observer1.version_id());
+  EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
+
+  // Stop the current running service worker.
+  StopServiceWorker(version.get());
+  EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
+
+  // Navigate away from the service worker's scope.
+  EXPECT_TRUE(NavigateToURL(shell(), out_scope_url));
+  EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
+
+  // This script asks the service worker what fetch events it saw.
+  const std::string script = R"(
+      (async () => {
+        const saw_message = new Promise(resolve => {
+          navigator.serviceWorker.onmessage = event => {
+            resolve(event.data);
+          };
+        });
+        const registration = await navigator.serviceWorker.ready;
+        registration.active.postMessage('');
+        const message = await saw_message;
+        return message.length;
+      })();
+  )";
+
+  // Navigate to the service worker's scope.
+  EXPECT_TRUE(NavigateToURL(shell(), in_scope_url));
+
+  switch (GetParam()) {
+    case ServiceWorkerBypassFetchHandlerBypassedOriginType::kBypassed:
+      // If bypassing is allowed, the service worker was bypassed and the
+      // navigation request shouldn't be handled by the fetch handler.
+      EXPECT_EQ(0, EvalJs(GetPrimaryMainFrame(), script));
+      break;
+    case ServiceWorkerBypassFetchHandlerBypassedOriginType::kNotBypassed:
+      // If bypassing is not allowed, the navigation request should be handled
+      // by the fetch handler.
+      EXPECT_EQ(1, EvalJs(GetPrimaryMainFrame(), script));
+      break;
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index ebaf9405..9b05133 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -81,6 +81,10 @@
              base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
+BASE_FEATURE(kServiceWorkerStorageControlOnThreadPool,
+             "ServiceWorkerStorageControlOnThreadPool",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 void DidFindRegistrationForStartActiveWorker(
     ServiceWorkerContextWrapper::StatusCallback callback,
     blink::ServiceWorkerStatusCode status,
@@ -1554,6 +1558,24 @@
 
   if (storage_control_binder_for_test_) {
     storage_control_binder_for_test_.Run(std::move(receiver));
+  } else if (base::FeatureList::IsEnabled(
+                 kServiceWorkerStorageControlOnThreadPool)) {
+    // The database task runner is BLOCK_SHUTDOWN in order to support
+    // ClearSessionOnlyOrigins() (called due to the "clear on browser exit"
+    // content setting).
+    // The ServiceWorkerStorageControl receiver runs on thread pool by using
+    // |database_task_runner| SequencedTaskRunner.
+    // TODO(falken): Only block shutdown for that particular task, when someday
+    // task runners support mixing task shutdown behaviors.
+    scoped_refptr<base::SequencedTaskRunner> database_task_runner =
+        base::ThreadPool::CreateSequencedTaskRunner(
+            {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+    database_task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(base::IgnoreResult(
+                           &storage::ServiceWorkerStorageControlImpl::Create),
+                       std::move(receiver), user_data_directory_,
+                       database_task_runner));
   } else if (run_storage_control_on_ui_thread) {
     // TODO(crbug.com/1055677): Use storage_partition() to bind the control when
     // ServiceWorkerStorageControl is sandboxed in the Storage Service.
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index a2e9bba..16dd466 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
 #include "base/strings/string_split.h"
 #include "base/trace_event/trace_event.h"
 #include "components/offline_pages/buildflags/buildflags.h"
@@ -84,12 +85,11 @@
   }
 }
 
-// Returns the list of origins in which fetch handlers are allowed to be
-// bypassed.
-const std::vector<url::Origin> BypassingFetchHandlerAllowedOrigins() {
+// Returns the list of origins in which fetch handlers are bypassed.
+const std::vector<url::Origin> FetchHandlerBypassedOrigins() {
   std::vector<url::Origin> origins;
   std::vector<std::string> parsed_params = base::SplitString(
-      features::kServiceWorkerBypassFetchHandlerAllowedOrigins.Get(), ",",
+      features::kServiceWorkerBypassFetchHandlerBypassedOrigins.Get(), ",",
       base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
   for (const auto& it : parsed_params) {
     const GURL url = GURL(it);
@@ -110,12 +110,13 @@
           features::ServiceWorkerBypassFetchHandlerTarget::kMainResource) {
     // When the url is in the allowlist, fetch handlers for the main resource
     // are bypassed.
-    // TODO(crbug.com/1371756) Consider using `static`. Since having `static`
-    // led some test failures, we tentatively removed it.
-    const std::vector<url::Origin> allowed_origins(
-        BypassingFetchHandlerAllowedOrigins());
-    for (const auto& it : allowed_origins) {
-      if (it.IsSameOriginWith(stripped_url))
+    const static base::NoDestructor<std::vector<url::Origin>> bypassed_origins(
+        FetchHandlerBypassedOrigins());
+    for (const auto& it : *bypassed_origins) {
+      // Skip comparing port numbers because some tests run the mock HTTP server
+      // with a random port number.
+      if (it.scheme() == stripped_url.scheme() &&
+          it.host() == stripped_url.host())
         return true;
     }
   }
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 32c1d0c5..269df27 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -715,111 +715,6 @@
   test_resources.ResetHandler();
 }
 
-class ServiceWorkerBypassMainResourceWithAllowListTest
-    : public ServiceWorkerControlleeRequestHandlerTest {
- public:
-  ServiceWorkerBypassMainResourceWithAllowListTest() {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{features::kServiceWorkerBypassFetchHandler,
-          {{"allowed_origins", "https://host"}}}},
-        {});
-  }
-  ~ServiceWorkerBypassMainResourceWithAllowListTest() override = default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(ServiceWorkerBypassMainResourceWithAllowListTest, UrlInAllowList) {
-  // Store an activated worker.
-  version_->set_fetch_handler_type(
-      ServiceWorkerVersion::FetchHandlerType::kNotSkippable);
-  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
-  registration_->SetActiveVersion(version_);
-  base::RunLoop loop;
-  context()->registry()->StoreRegistration(
-      registration_.get(), version_.get(),
-      base::BindLambdaForTesting(
-          [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); }));
-  loop.Run();
-
-  // Conduct a main resource load.
-  ServiceWorkerRequestTestResources test_resources(
-      this, GURL("https://host/scope/doc"),
-      network::mojom::RequestDestination::kDocument);
-  test_resources.MaybeCreateLoader();
-
-  EXPECT_FALSE(test_resources.loader());
-  EXPECT_FALSE(version_->HasControllee());
-
-  test_resources.WaitLoader();
-
-  // If the url is in the allowlist, ServiceWorker the interceptor doesn't
-  // handle the main resource request.
-  EXPECT_FALSE(test_resources.loader());
-  EXPECT_TRUE(version_->HasControllee());
-
-  // Use RunUntilIdle() to wait for the ServiceWorker to start.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(version_->running_status(), EmbeddedWorkerStatus::RUNNING);
-
-  test_resources.ResetHandler();
-}
-
-class ServiceWorkerBypassMainResourceWithAnotherAllowListTest
-    : public ServiceWorkerControlleeRequestHandlerTest {
- public:
-  ServiceWorkerBypassMainResourceWithAnotherAllowListTest() {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{features::kServiceWorkerBypassFetchHandler,
-          {{"allowed_origins", "https://another-host"}}}},
-        {});
-  }
-  ~ServiceWorkerBypassMainResourceWithAnotherAllowListTest() override = default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(ServiceWorkerBypassMainResourceWithAnotherAllowListTest,
-       UrlNotInAllowList) {
-  // Prepare a valid version and registration.
-  version_->set_fetch_handler_type(
-      ServiceWorkerVersion::FetchHandlerType::kNotSkippable);
-  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
-  registration_->SetActiveVersion(version_);
-  {
-    base::RunLoop loop;
-    context()->registry()->StoreRegistration(
-        registration_.get(), version_.get(),
-        base::BindOnce(
-            [](base::OnceClosure closure,
-               blink::ServiceWorkerStatusCode status) {
-              ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
-              std::move(closure).Run();
-            },
-            loop.QuitClosure()));
-    loop.Run();
-  }
-
-  // Conduct a main resource load.
-  ServiceWorkerRequestTestResources test_resources(
-      this, GURL("https://host/scope/doc"),
-      network::mojom::RequestDestination::kDocument);
-  test_resources.MaybeCreateLoader();
-
-  EXPECT_FALSE(test_resources.loader());
-  EXPECT_FALSE(version_->HasControllee());
-
-  test_resources.WaitLoader();
-
-  // If the url is not in the allowlist, ServiceWorker handles fetch handler.
-  EXPECT_TRUE(test_resources.loader());
-  EXPECT_TRUE(version_->HasControllee());
-
-  test_resources.ResetHandler();
-}
-
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithOfflineHeader) {
   version_->set_fetch_handler_type(
diff --git a/content/browser/webrtc/resources/candidate_grid.js b/content/browser/webrtc/resources/candidate_grid.js
index ca51edb..68c108e 100644
--- a/content/browser/webrtc/resources/candidate_grid.js
+++ b/content/browser/webrtc/resources/candidate_grid.js
@@ -137,9 +137,12 @@
       localRow.children[index].innerText = localCandidate[stat];
     }
   });
-  // Network type is only for the local candidate
-  // so put it into the pair row above the address.
+  // Network type is only for the local candidate so put it into the pair
+  // row above the address. Also highlight VPN adapters.
   pairRow.children[2].innerText = localCandidate.networkType;
+  if (localCandidate['vpn*'] === true) {
+    pairRow.children[2].innerText += ' (VPN)';
+  }
   // protocol must always be the same for the pair
   // so put it into the pair row above the candidate type.
   // Add tcpType for local candidates.
diff --git a/content/browser/webrtc/resources/webrtc_internals.js b/content/browser/webrtc/resources/webrtc_internals.js
index 1b81d895..6c1988a 100644
--- a/content/browser/webrtc/resources/webrtc_internals.js
+++ b/content/browser/webrtc/resources/webrtc_internals.js
@@ -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 {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js';
 import {$} from 'chrome://resources/js/util.js';
 
 import {MAX_STATS_DATA_POINT_BUFFER_SIZE} from './data_series.js';
@@ -115,20 +115,20 @@
   statsTable = new StatsTable(ssrcInfoManager);
 
   // Add listeners for all the updates that get sent from webrtc_internals.cc.
-  addWebUIListener('add-peer-connection', addPeerConnection);
-  addWebUIListener('update-peer-connection', updatePeerConnection);
-  addWebUIListener('update-all-peer-connections', updateAllPeerConnections);
-  addWebUIListener('remove-peer-connection', removePeerConnection);
-  addWebUIListener('add-standard-stats', addStandardStats);
-  addWebUIListener('add-legacy-stats', addLegacyStats);
-  addWebUIListener('add-get-user-media', addGetUserMedia);
-  addWebUIListener('update-get-user-media', updateGetUserMedia);
-  addWebUIListener(
+  addWebUiListener('add-peer-connection', addPeerConnection);
+  addWebUiListener('update-peer-connection', updatePeerConnection);
+  addWebUiListener('update-all-peer-connections', updateAllPeerConnections);
+  addWebUiListener('remove-peer-connection', removePeerConnection);
+  addWebUiListener('add-standard-stats', addStandardStats);
+  addWebUiListener('add-legacy-stats', addLegacyStats);
+  addWebUiListener('add-get-user-media', addGetUserMedia);
+  addWebUiListener('update-get-user-media', updateGetUserMedia);
+  addWebUiListener(
       'remove-get-user-media-for-renderer', removeGetUserMediaForRenderer);
-  addWebUIListener(
+  addWebUiListener(
       'event-log-recordings-file-selection-cancelled',
       eventLogRecordingsFileSelectionCancelled);
-  addWebUIListener(
+  addWebUiListener(
       'audio-debug-recordings-file-selection-cancelled',
       audioDebugRecordingsFileSelectionCancelled);
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 8aa38ed..4eaab73 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -897,12 +897,11 @@
         ServiceWorkerBypassFetchHandlerTarget::kMainResource,
         &service_worker_bypass_fetch_handler_target_options};
 
-// Define the allowed websites to bypass ServiceWorker. Allowed origins are
-// expected to be passed as a comma separated string.
-// e.g. https://example1.test,https://example2.test
+// Define origins to bypass ServiceWorker. Origins are expected to be passed as
+// a comma separated string. e.g. https://example1.test,https://example2.test
 const base::FeatureParam<std::string>
-    kServiceWorkerBypassFetchHandlerAllowedOrigins{
-        &kServiceWorkerBypassFetchHandler, "allowed_origins", ""};
+    kServiceWorkerBypassFetchHandlerBypassedOrigins{
+        &kServiceWorkerBypassFetchHandler, "origins_to_bypass", ""};
 
 // Enables skipping the service worker fetch handler if the fetch handler is
 // identified as ignorable.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index d8d6ee8..8879148e 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -220,7 +220,7 @@
     ServiceWorkerBypassFetchHandlerTarget>
     kServiceWorkerBypassFetchHandlerTarget;
 CONTENT_EXPORT extern const base::FeatureParam<std::string>
-    kServiceWorkerBypassFetchHandlerAllowedOrigins;
+    kServiceWorkerBypassFetchHandlerBypassedOrigins;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerSkipIgnorableFetchHandler);
 CONTENT_EXPORT extern const base::FeatureParam<bool> kSkipEmptyFetchHandler;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaCaptureOnFocus);
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index 0af40eb..7308301 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -212,6 +212,13 @@
   // load. This is used for metrics collection.
   virtual void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior) {}
 
+  // Notification when the renderer uses subresources.
+  // It is called when there is a subresouce load. The reported values via
+  // arguments are cumulative. They are NOT a difference from the previous call.
+  virtual void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) {}
+
   // Notification when the renderer observes a new use counter usage during a
   // page load. This is used for UseCounter metrics.
   virtual void DidObserveNewFeatureUsage(
diff --git a/content/public/test/browser_task_environment_unittest.cc b/content/public/test/browser_task_environment_unittest.cc
index b860e067..acc230c 100644
--- a/content/public/test/browser_task_environment_unittest.cc
+++ b/content/public/test/browser_task_environment_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/task/current_thread.h"
 #include "base/task/thread_pool.h"
 #include "base/test/bind.h"
+#include "base/test/gtest_util.h"
 #include "build/build_config.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -32,13 +33,7 @@
 constexpr int kNumHops = 13;
 constexpr int kNumTasks = 8;
 
-#if DCHECK_IS_ON() && !BUILDFLAG(IS_ANDROID)
-// Expect that in builds with working DCHECK messages the failure message
-// includes a hint towards using the BrowserTaskEnvironment class.
 const char kDeathMatcher[] = "Check failed:.*\n*.*BrowserTaskEnvironment";
-#else
-const char kDeathMatcher[] = "";
-#endif
 
 void PostTaskToUIThread(int iteration, base::subtle::Atomic32* tasks_run);
 
@@ -121,12 +116,10 @@
 }
 
 TEST(BrowserTaskEnvironmentTest, MessageLoopTypeMismatch) {
-  testing::FLAGS_gtest_death_test_style = "threadsafe";
-
   base::test::TaskEnvironment task_environment(
       base::test::TaskEnvironment::MainThreadType::UI);
 
-  EXPECT_DEATH_IF_SUPPORTED(
+  BASE_EXPECT_DEATH(
       {
         BrowserTaskEnvironment second_task_environment(
             BrowserTaskEnvironment::IO_MAINLOOP);
@@ -135,9 +128,7 @@
 }
 
 TEST(BrowserTaskEnvironmentTest, MultipleBrowserTaskEnvironment) {
-  testing::FLAGS_gtest_death_test_style = "threadsafe";
-
-  EXPECT_DEATH_IF_SUPPORTED(
+  BASE_EXPECT_DEATH(
       {
         BrowserTaskEnvironment task_environment;
         BrowserTaskEnvironment other_task_environment;
@@ -192,30 +183,28 @@
 // Verify that posting tasks to the UI thread without having the
 // BrowserTaskEnvironment instance cause a crash.
 TEST(BrowserTaskEnvironmentTest, NotInitializedUIThread) {
-  testing::FLAGS_gtest_death_test_style = "threadsafe";
   base::test::TaskEnvironment task_environment(
       base::test::TaskEnvironment::MainThreadType::UI);
 
-  EXPECT_DEATH_IF_SUPPORTED(
-      { GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()); },
+  EXPECT_DCHECK_DEATH_WITH(
+      GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()),
       kDeathMatcher);
-  EXPECT_DEATH_IF_SUPPORTED(
-      { GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()); },
+  EXPECT_DCHECK_DEATH_WITH(
+      GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()),
       kDeathMatcher);
 }
 
 // Verify that posting tasks to the IO thread without having the
 // BrowserTaskEnvironment instance cause a crash.
 TEST(BrowserTaskEnvironmentTest, NotInitializedIOThread) {
-  testing::FLAGS_gtest_death_test_style = "threadsafe";
   base::test::TaskEnvironment task_environment(
       base::test::TaskEnvironment::MainThreadType::IO);
 
-  EXPECT_DEATH_IF_SUPPORTED(
-      { GetIOThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()); },
+  EXPECT_DCHECK_DEATH_WITH(
+      GetIOThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()),
       kDeathMatcher);
-  EXPECT_DEATH_IF_SUPPORTED(
-      { GetIOThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()); },
+  EXPECT_DCHECK_DEATH_WITH(
+      GetIOThreadTaskRunner({})->PostTask(FROM_HERE, base::DoNothing()),
       kDeathMatcher);
 }
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 36bfded..e8ba73bd 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4319,6 +4319,15 @@
     observer.DidObserveLoadingBehavior(behavior);
 }
 
+void RenderFrameImpl::DidObserveSubresourceLoad(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  for (auto& observer : observers_)
+    observer.DidObserveSubresourceLoad(
+        number_of_subresources_loaded,
+        number_of_subresource_loads_handled_by_service_worker);
+}
+
 void RenderFrameImpl::DidObserveNewFeatureUsage(
     const blink::UseCounterFeature& feature) {
   for (auto& observer : observers_)
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 33dea08e..15f67fb 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -591,6 +591,9 @@
       blink::UserInteractionType interaction_type) override;
   void DidChangeCpuTiming(base::TimeDelta time) override;
   void DidObserveLoadingBehavior(blink::LoadingBehaviorFlag behavior) override;
+  void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) override;
   void DidObserveNewFeatureUsage(
       const blink::UseCounterFeature& feature) override;
   void DidObserveSoftNavigation(uint32_t count) override;
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
index 0cf731c3..d73a206 100644
--- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -157,7 +157,6 @@
 # Failing on android N5
 
 # Flaking on Linux FYI Release
-crbug.com/1340081 [ linux release amd-0x7340 ] ContextLost_WorkerWebGLRAFAfterGPUCrash [ RetryOnFailure ]
 
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 725cbe85..d633872 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -325,7 +325,6 @@
 crbug.com/1288134 [ win10 amd-0x7340 renderer-skia-gl ] Pixel_DirectComposition_Video_VP9_YUY2 [ Failure ]
 
 # Pixel 4 Flaky Failures - Passthrough, WebView and Validating
-crbug.com/1273033 [ android android-pixel-4 ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ Failure ]
 
 # Pixel 4 Flaky Failures - Passthrough and Validating on Chromium
 
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
index 41cee7c..cf906d4b 100644
--- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -229,7 +229,6 @@
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_Canvas2DRedBox [ RetryOnFailure ]
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_ScissorTestWithPreserveDrawingBuffer [ RetryOnFailure ]
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_Video_MP4_FourColors_Aspect_4x3 [ RetryOnFailure ]
-crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_Video_MP4_Rounded_Corner [ RetryOnFailure ]
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_WebGLGreenTriangle_* [ RetryOnFailure ]
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_WebGLPreservedAfterTabSwitch [ RetryOnFailure ]
 crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLAlphaCanvas [ RetryOnFailure ]
diff --git a/docs/webui_build_configuration.md b/docs/webui_build_configuration.md
index e24a1558..28cb586 100644
--- a/docs/webui_build_configuration.md
+++ b/docs/webui_build_configuration.md
@@ -244,7 +244,7 @@
       targets generating shared resources that are expected to be bundled in
       the UI, e.g. //ui/webui/resources:preprocess.
 excludes: Paths of files that are not bundled. Often used for large mojo files
-          that would otherwise be in many bundles, and for cr.m.js which relies
+          that would otherwise be in many bundles, and for cr.js which relies
           on global variables.
 ```
 
@@ -269,7 +269,7 @@
       "//ui/webui/resources:preprocess",
     ]
     excludes = [
-      "chrome://resources/js/cr.m.js",
+      "chrome://resources/js/cr.js",
       "chrome://resources/mojo/mojo/public/js/bindings.js",
     ]
   }
diff --git a/docs/webui_explainer.md b/docs/webui_explainer.md
index 64c6f4d..aa52588 100644
--- a/docs/webui_explainer.md
+++ b/docs/webui_explainer.md
@@ -513,7 +513,7 @@
 * [`FireWebUIListener()`](#FireWebUIListener) allows easily notifying the page
   when an event occurs in C++ and is more loosely coupled (nothing blows up if
   the event dispatch is ignored). JS subscribes to notifications via
-  [`addWebUIListener`](#addWebUIListener).
+  [`addWebUiListener`](#addWebUiListener).
 * [`ResolveJavascriptCallback`](#ResolveJavascriptCallback) and
   [`RejectJavascriptCallback`](#RejectJavascriptCallback) are useful
   when Javascript requires a response to an inquiry about C++-canonical state
@@ -529,7 +529,7 @@
 Here's some example to detect a change to Chrome's theme:
 
 ```js
-addWebUIListener("theme-changed", refreshThemeStyles);
+addWebUiListener("theme-changed", refreshThemeStyles);
 ```
 
 This Javascript event listener can be triggered in C++ via:
@@ -734,23 +734,23 @@
 message_callbacks_.find(message)->second.Run(&args);
 ```
 
-### addWebUIListener()
+### addWebUiListener()
 
 WebUI listeners are a convenient way for C++ to inform JavaScript of events.
 
 Older WebUI code exposed public methods for event notification, similar to how
 responses to [chrome.send()](#chrome_send) used to work. They both
 resulted in global namespace pollution, but it was additionally hard to stop
-listening for events in some cases. **cr.addWebUIListener** is preferred in new
+listening for events in some cases. **addWebUiListener** is preferred in new
 code.
 
 Adding WebUI listeners creates and inserts a unique ID into a map in JavaScript,
 just like [sendWithPromise()](#sendWithPromise).
 
-addWebUIListener can be imported from 'chrome://resources/js/cr.m.js'.
+addWebUiListener can be imported from 'chrome://resources/js/cr.m.js'.
 
 ```js
-// addWebUIListener():
+// addWebUiListener():
 webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
 webUIListenerMap[eventName][createUid()] = callback;
 ```
@@ -780,7 +780,7 @@
 
 ```js
 let donutsReady: number = 0;
-addWebUIListener('donuts-baked', function(numFreshlyBakedDonuts: number) {
+addWebUiListener('donuts-baked', function(numFreshlyBakedDonuts: number) {
   donutsReady += numFreshlyBakedDonuts;
 });
 ```
@@ -806,7 +806,7 @@
 });
 ```
 
-Note that sendWithPromise can be imported from 'chrome://resources/js/cr.m.js';
+Note that sendWithPromise can be imported from 'chrome://resources/js/cr.js';
 
 On the C++ side, the message registration is similar to
 [`chrome.send()`](#chrome_send) except that the first argument in the
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index ac9d414b..f6988f3 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -601,6 +601,11 @@
       "allowlist": ["B44D08FD98F1523ED5837D78D0A606EA9D6206E5"]  // Web Store
     },
     {
+      "channel": "stable",
+      "extension_types": ["extension"],
+      "allowlist": ["DD87C93131FF8D3DE4E483DC1EB298D73C7223A6"]  // http://crbug.com/1328114
+    },
+    {
       "channel": "dev",
       "extension_types": ["extension"]
     }
diff --git a/infra/config/generated/builders/try/win-swangle-try-x86/properties.json b/infra/config/generated/builders/try/win-swangle-try-x86/properties.json
index f394223..e984210 100644
--- a/infra/config/generated/builders/try/win-swangle-try-x86/properties.json
+++ b/infra/config/generated/builders/try/win-swangle-try-x86/properties.json
@@ -39,11 +39,6 @@
       "retry_failed_shards": false
     }
   },
-  "$build/goma": {
-    "enable_ats": false,
-    "rpc_extra_params": "?prod",
-    "server_host": "goma.chromium.org"
-  },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
     "jobs": 150,
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050M Nexus5X\051/properties.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050M Nexus5X\051/properties.json"
deleted file mode 100644
index 7883bfd5..0000000
--- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050M Nexus5X\051/properties.json"
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "chromium.webrtc.fyi",
-  "recipe": "chromium"
-}
\ No newline at end of file
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050N Nexus5X\051/properties.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050N Nexus5X\051/properties.json"
deleted file mode 100644
index 7883bfd5..0000000
--- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051 \050N Nexus5X\051/properties.json"
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "chromium.webrtc.fyi",
-  "recipe": "chromium"
-}
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 7013297..0838cc62 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -90086,12 +90086,6 @@
         '      "retry_failed_shards": false'
         '    }'
         '  },'
-        '  "$build/goma": {'
-        '    "enable_ats": false,'
-        '    "jobs": 150,'
-        '    "rpc_extra_params": "?prod",'
-        '    "server_host": "goma.chromium.org"'
-        '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
         '    "jobs": 300,'
@@ -94861,108 +94855,6 @@
       }
     }
     builders {
-      name: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.webrtc.fyi"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "chromium.webrtc.fyi",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
-        '}'
-      execution_timeout_secs: 7200
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "luci.buildbucket.omit_python2"
-        value: 100
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-      }
-    }
-    builders {
-      name: "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.webrtc.fyi"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "chromium.webrtc.fyi",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
-        '}'
-      execution_timeout_secs: 7200
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "luci.buildbucket.omit_python2"
-        value: 100
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-      }
-    }
-    builders {
       name: "WebRTC Chromium FYI Android Tests ARM64 (dbg)"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "cpu:x86-64"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 742841d8..a4d9c2a 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -14697,24 +14697,14 @@
     short_name: "64"
   }
   builders {
-    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)"
-    category: "android|debug|tester"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)"
-    category: "android|debug|tester"
-    short_name: "N"
-  }
-  builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg)"
     category: "android|debug|tester"
-    short_name: "P"
+    short_name: "32"
   }
   builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 (dbg)"
     category: "android|debug|tester"
-    short_name: "P"
+    short_name: "64"
   }
   builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Android Builder"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index 2c91e4b..c09d7b8cc 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -2792,24 +2792,6 @@
   }
 }
 job {
-  id: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)"
-  realm: "webrtc.fyi"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "webrtc.fyi"
-    builder: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)"
-  }
-}
-job {
-  id: "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)"
-  realm: "webrtc.fyi"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "webrtc.fyi"
-    builder: "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)"
-  }
-}
-job {
   id: "WebRTC Chromium FYI Android Tests ARM64 (dbg)"
   realm: "webrtc.fyi"
   buildbucket {
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg
index cc90fa36..c62f970b1e 100644
--- a/infra/config/generated/luci/realms.cfg
+++ b/infra/config/generated/luci/realms.cfg
@@ -607,8 +607,6 @@
       restrict {
         attribute: "scheduler.job.name"
         values: "WebRTC Chromium FYI Android Tests (dbg)"
-        values: "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)"
-        values: "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)"
         values: "WebRTC Chromium FYI Android Tests ARM64 (dbg)"
         values: "WebRTC Chromium FYI Linux Tester"
         values: "WebRTC Chromium FYI Mac Tester"
diff --git a/infra/config/subprojects/chromium/swangle.try.star b/infra/config/subprojects/chromium/swangle.try.star
index 86df446..d998b5f2 100644
--- a/infra/config/subprojects/chromium/swangle.try.star
+++ b/infra/config/subprojects/chromium/swangle.try.star
@@ -162,4 +162,5 @@
     try_settings = builder_config.try_settings(
         retry_failed_shards = False,
     ),
+    goma_backend = None,
 )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
index 902ba0d0..7b00f99 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
@@ -93,6 +93,7 @@
     try_settings = builder_config.try_settings(
         retry_failed_shards = False,
     ),
+    goma_backend = None,
 )
 
 try_.builder(
diff --git a/infra/config/subprojects/webrtc/consoles/chromium.webrtc.fyi.star b/infra/config/subprojects/webrtc/consoles/chromium.webrtc.fyi.star
index 2795e12..7febc59 100644
--- a/infra/config/subprojects/webrtc/consoles/chromium.webrtc.fyi.star
+++ b/infra/config/subprojects/webrtc/consoles/chromium.webrtc.fyi.star
@@ -21,24 +21,14 @@
             short_name = "64",
         ),
         luci.console_view_entry(
-            builder = "webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)",
-            category = "android|debug|tester",
-            short_name = "M",
-        ),
-        luci.console_view_entry(
-            builder = "webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)",
-            category = "android|debug|tester",
-            short_name = "N",
-        ),
-        luci.console_view_entry(
             builder = "webrtc.fyi/WebRTC Chromium FYI Android Tests (dbg)",
             category = "android|debug|tester",
-            short_name = "P",
+            short_name = "32",
         ),
         luci.console_view_entry(
             builder = "webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 (dbg)",
             category = "android|debug|tester",
-            short_name = "P",
+            short_name = "64",
         ),
         luci.console_view_entry(
             builder = "webrtc.fyi/WebRTC Chromium FYI Android Builder",
diff --git a/infra/config/subprojects/webrtc/webrtc.fyi.star b/infra/config/subprojects/webrtc/webrtc.fyi.star
index 06ff617..074e565 100644
--- a/infra/config/subprojects/webrtc/webrtc.fyi.star
+++ b/infra/config/subprojects/webrtc/webrtc.fyi.star
@@ -63,16 +63,6 @@
 )
 
 builder(
-    name = "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)",
-    triggered_by = ["WebRTC Chromium FYI Android Builder ARM64 (dbg)"],
-)
-
-builder(
-    name = "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)",
-    triggered_by = ["WebRTC Chromium FYI Android Builder (dbg)"],
-)
-
-builder(
     name = "WebRTC Chromium FYI Android Tests (dbg)",
     triggered_by = ["WebRTC Chromium FYI Android Builder (dbg)"],
 )
diff --git a/ios/chrome/browser/ui/page_info/BUILD.gn b/ios/chrome/browser/ui/page_info/BUILD.gn
index f958bbd..be98654 100644
--- a/ios/chrome/browser/ui/page_info/BUILD.gn
+++ b/ios/chrome/browser/ui/page_info/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/fancy_ui",
     "//ios/chrome/browser/ui/icons:symbols",
+    "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/page_info/requirements",
     "//ios/chrome/browser/ui/permissions",
     "//ios/chrome/browser/ui/permissions:constants",
diff --git a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
index b6900cb..2ffbbe55 100644
--- a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
+++ b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
@@ -5,11 +5,14 @@
 #import "ios/chrome/browser/ui/page_info/page_info_view_controller.h"
 
 #import "base/mac/foundation_util.h"
+#import "base/metrics/user_metrics.h"
+#import "base/metrics/user_metrics_action.h"
 #import "base/notreached.h"
 #import "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/net/crurl.h"
 #import "ios/chrome/browser/ui/commands/page_info_commands.h"
 #import "ios/chrome/browser/ui/icons/symbols.h"
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/page_info/page_info_constants.h"
 #import "ios/chrome/browser/ui/permissions/permission_info.h"
 #import "ios/chrome/browser/ui/permissions/permissions_constants.h"
@@ -257,6 +260,23 @@
   [self.pageInfoCommandsHandler hidePageInfo];
 }
 
+#pragma mark - UIResponder
+
+// To always be able to register key commands via -keyCommands, the VC must be
+// able to become first responder.
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
+- (NSArray*)keyCommands {
+  return @[ UIKeyCommand.cr_close ];
+}
+
+- (void)keyCommand_close {
+  base::RecordAction(base::UserMetricsAction("MobileKeyCommandClose"));
+  [self.pageInfoCommandsHandler hidePageInfo];
+}
+
 #pragma mark - Private
 
 // Returns the navigationItem titleView for `siteURL`.
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index 9f3a621..ee9712e 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/drag_and_drop/table_view_url_drag_drop_handler.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/list_model/list_item+Controller.h"
 #import "ios/chrome/browser/ui/list_model/list_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_constants.h"
@@ -345,6 +346,23 @@
   }
 }
 
+#pragma mark - UIResponder
+
+// To always be able to register key commands via -keyCommands, the VC must be
+// able to become first responder.
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
+- (NSArray*)keyCommands {
+  return @[ UIKeyCommand.cr_close ];
+}
+
+- (void)keyCommand_close {
+  base::RecordAction(base::UserMetricsAction("MobileKeyCommandClose"));
+  [self.delegate dismissReadingListListViewController:self];
+}
+
 #pragma mark - ReadingListDataSink
 
 - (void)dataSourceReady:(id<ReadingListDataSource>)dataSource {
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions.h b/ios/chrome/browser/ui/recent_tabs/synced_sessions.h
index 5a32e19d..0b778e39 100644
--- a/ios/chrome/browser/ui/recent_tabs/synced_sessions.h
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions.h
@@ -84,7 +84,6 @@
   std::string tag;
   std::string name;
   base::Time modified_time;
-  sync_pb::SyncEnums::DeviceType device_type;
   std::vector<std::unique_ptr<DistantTab>> tabs;
 };
 
diff --git a/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm b/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
index da393df80..07e1753b 100644
--- a/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
@@ -98,7 +98,6 @@
   tag = synced_session->session_tag;
   name = synced_session->session_name;
   modified_time = synced_session->modified_time;
-  device_type = synced_session->device_type;
 
   std::vector<const sessions::SessionTab*> open_tabs;
   open_tabs_delegate->GetForeignSessionTabs(tag, &open_tabs);
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn b/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
index 71873cd..b8f80b75a 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
@@ -56,6 +56,7 @@
     "//ios/chrome/browser/ui/elements:elements_internal",
     "//ios/chrome/browser/ui/icons",
     "//ios/chrome/browser/ui/icons:symbols",
+    "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/list_model",
     "//ios/chrome/browser/ui/resources:legacy_password_key",
     "//ios/chrome/browser/ui/resources:password_key",
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index 68b4859..3a88245 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -27,6 +27,7 @@
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browsing_data_commands.h"
 #import "ios/chrome/browser/ui/elements/chrome_activity_overlay_coordinator.h"
+#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h"
 #import "ios/chrome/browser/ui/settings/cells/table_view_clear_browsing_data_item.h"
 #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_consumer.h"
@@ -326,6 +327,23 @@
   [self updateToolbarButtons];
 }
 
+#pragma mark - UIResponder
+
+// To always be able to register key commands via -keyCommands, the VC must be
+// able to become first responder.
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
+- (NSArray*)keyCommands {
+  return @[ UIKeyCommand.cr_close ];
+}
+
+- (void)keyCommand_close {
+  base::RecordAction(base::UserMetricsAction("MobileKeyCommandClose"));
+  [self dismiss];
+}
+
 #pragma mark - TableViewLinkHeaderFooterItemDelegate
 
 - (void)view:(TableViewLinkHeaderFooterView*)view didTapLinkURL:(CrURL*)url {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
index a61743c..4d8a3d4 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_page_control.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/icons/symbols.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
 
@@ -34,7 +35,8 @@
 // This control is built out of several views. From the (z-axis) bottom up, they
 // are:
 //
-//  * The background view, a grey roundrect with vertical transparent bars.
+//  * The background view, a grey roundrect.
+//  * The separators between the segment.
 //  * The background image views.
 //  * The numeric label on the regular tab icon.
 //  * The hover views, which allow for pointer interactions.
@@ -63,32 +65,52 @@
 
 // Height and width of the slider.
 const CGFloat kSliderHeight = 40.0;
-const CGFloat kSliderWidth = 78.0;
+const CGFloat kLegacySliderWidth = 78.0;
+const CGFloat kSliderWidth = 65.0;
 
 // Height and width of each segment.
-const CGFloat kSegmentHeight = 36.0;
-const CGFloat kSegmentWidth = 64.0;
+const CGFloat kLegacySegmentHeight = 36.0;
+const CGFloat kLegacySegmentWidth = 64.0;
+const CGFloat kSegmentHeight = 44.0;
+const CGFloat kSegmentWidth = 65.0;
 
 // Points that the slider overhangs a segment on each side, or 0 if the slider
 // is narrower than a segment.
-const CGFloat kSliderOverhang =
-    std::max((kSliderWidth - kSegmentWidth) / 2.0, 0.0);
+const CGFloat kLegacySliderOverhang =
+    std::max((kLegacySliderWidth - kLegacySegmentWidth) / 2.0, 0.0);
+// Margin between the slider and the leading/trailing segments.
+const CGFloat kSliderMargin = 2.0;
 
-// Width of the separator bars between segments.
+// Vertical margin between the slider and the segment on each side.
+const CGFloat kSliderVerticalMargin =
+    std::max((kSegmentHeight - kSliderHeight) / 2.0, 0.0);
+
+// Width and height of the separator bars between segments.
 const CGFloat kSeparatorWidth = 1.0;
+const CGFloat kSeparatorHeight = 22.0;
 
 // Width of the background -- three segments plus two separators.
-const CGFloat kBackgroundWidth = 3 * kSegmentWidth + 2 * kSeparatorWidth;
+const CGFloat kLegacyBackgroundWidth =
+    3 * kLegacySegmentWidth + 2 * kSeparatorWidth;
 
 // Overall height of the control -- the larger of the slider and segment
 // heights.
+const CGFloat kLegacyOverallHeight =
+    std::max(kSliderHeight, kLegacySegmentHeight);
 const CGFloat kOverallHeight = std::max(kSliderHeight, kSegmentHeight);
 // Overall width of the control -- the background width plus twice the slider
 // overhang.
-const CGFloat kOverallWidth = kBackgroundWidth + 2 * kSliderOverhang;
+const CGFloat kLegacyOverallWidth =
+    kLegacyBackgroundWidth + 2 * kLegacySliderOverhang;
+// Overall width -- three segments plus two separators plus two margins between
+// leading/trailing segments and the slider.
+const CGFloat kOverallWidth =
+    3 * kSegmentWidth + 2 * kSeparatorWidth + 2 * kSliderMargin;
 
 // Radius used to draw the background and the slider.
-const CGFloat kCornerRadius = 13.0;
+const CGFloat kSliderCornerRadius = 13.0;
+const CGFloat kBackgroundCornerRadius = 15.0;
+const CGFloat kLegacyBackgroundCornerRadius = 13.0;
 
 // Sizes for the labels and their selected counterparts.
 const CGFloat kLabelSize = 20.0;
@@ -98,16 +120,16 @@
 const NSTimeInterval kSliderMoveDuration = 0.2;
 
 // Color for the slider
-const int kSliderColor = 0xF8F9FA;
-// Color for the background view.
-const int kBackgroundColor = 0xFFFFFF;
+const int kLegacySliderColor = 0xF8F9FA;
 // Alpha for the background view.
-const CGFloat kBackgroundAlpha = 0.3;
+const CGFloat kLegacyBackgroundAlpha = 0.3;
+const CGFloat kBackgroundAlpha = 0.15;
 // Color for the regular tab count label and icons.
-const CGFloat kSelectedColor = 0x3C4043;
+const CGFloat kLegacySelectedColor = 0x3C4043;
 
-// The size of the symbol image.
-const CGFloat kSymbolTabGridPageControlPointSize = 24.;
+// The sizes of the symbol images.
+const CGFloat kUnselectedSymbolSize = 22.;
+const CGFloat kSelectedSymbolSize = 24.;
 
 // Returns the point that's at the center of `rect`.
 CGPoint RectCenter(CGRect rect) {
@@ -134,11 +156,11 @@
               imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
 }
 
-// Returns an UIImageView for the given symbolName.
-UIImageView* ImageViewForSymbolNamed(NSString* symbolName) {
+// Returns an UIImageView for the given `symbolName` and `selected` state.
+UIImageView* ImageViewForSymbol(NSString* symbolName, bool selected) {
+  CGFloat size = selected ? kSelectedSymbolSize : kUnselectedSymbolSize;
   return [[UIImageView alloc]
-      initWithImage:CustomSymbolTemplateWithPointSize(
-                        symbolName, kSymbolTabGridPageControlPointSize)];
+      initWithImage:CustomSymbolTemplateWithPointSize(symbolName, size)];
 }
 
 }  // namespace
@@ -159,6 +181,10 @@
 @property(nonatomic, weak) UILayoutGuide* incognitoGuide;
 @property(nonatomic, weak) UILayoutGuide* regularGuide;
 @property(nonatomic, weak) UILayoutGuide* remoteGuide;
+// The separator between incognito and regular tabs.
+@property(nonatomic, weak) UIView* firstSeparator;
+// The separator between the regular and remote tabs.
+@property(nonatomic, weak) UIView* secondSeparator;
 // The view for the slider.
 @property(nonatomic, weak) UIView* sliderView;
 // The view for the selected images and labels (a subview of `sliderView).
@@ -208,7 +234,12 @@
 }
 
 - (instancetype)init {
-  CGRect frame = CGRectMake(0, 0, kOverallWidth, kOverallHeight);
+  CGRect frame;
+  if (UseSymbols()) {
+    frame = CGRectMake(0, 0, kOverallWidth, kOverallHeight);
+  } else {
+    frame = CGRectMake(0, 0, kLegacyOverallWidth, kLegacyOverallHeight);
+  }
   if (self = [super initWithFrame:frame]) {
     // Default to the regular tab page as the selected page.
     _selectedPage = TabGridPageRegularTabs;
@@ -275,6 +306,12 @@
   else
     _selectedPage = TabGridPageRemoteTabs;
 
+  // Hide/show the separator based on the slider position. Add a delta for the
+  // comparison to avoid issues when the regular tabs are selected.
+  const CGFloat kDelta = 0.001;
+  self.firstSeparator.hidden = sliderPosition < 0.5 + kDelta;
+  self.secondSeparator.hidden = sliderPosition > 0.5 - kDelta;
+
   if (_selectedPage != previousSelectedPage)
     [self updateSelectedPageAccessibility];
 }
@@ -385,7 +422,10 @@
 #pragma mark - UIView
 
 - (CGSize)intrinsicContentSize {
-  return CGSizeMake(kOverallWidth, kOverallHeight);
+  if (UseSymbols()) {
+    return CGSizeMake(kOverallWidth, kOverallHeight);
+  }
+  return CGSizeMake(kLegacyOverallWidth, kLegacyOverallHeight);
 }
 
 - (void)willMoveToSuperview:(UIView*)newSuperview {
@@ -489,8 +529,8 @@
   switch (tab) {
     case TabGridPageRegularTabs: {
       if (UseSymbols()) {
-        iconSelected = ImageViewForSymbolNamed(kSquareNumberSymbol);
-        iconNotSelected = ImageViewForSymbolNamed(kSquareNumberSymbol);
+        iconSelected = ImageViewForSymbol(kSquareNumberSymbol, true);
+        iconNotSelected = ImageViewForSymbol(kSquareNumberSymbol, false);
       } else {
         iconSelected = ImageViewForImageNamed(kImagePageControlRegularSelected);
         iconNotSelected =
@@ -502,8 +542,8 @@
     }
     case TabGridPageIncognitoTabs: {
       if (UseSymbols()) {
-        iconSelected = ImageViewForSymbolNamed(kIncognitoSymbol);
-        iconNotSelected = ImageViewForSymbolNamed(kIncognitoSymbol);
+        iconSelected = ImageViewForSymbol(kIncognitoSymbol, true);
+        iconNotSelected = ImageViewForSymbol(kIncognitoSymbol, false);
       } else {
         iconSelected =
             ImageViewForImageNamed(kImagePageControlIncognitoSelected);
@@ -516,8 +556,8 @@
     }
     case TabGridPageRemoteTabs: {
       if (UseSymbols()) {
-        iconSelected = ImageViewForSymbolNamed(kRecentTabsSymbol);
-        iconNotSelected = ImageViewForSymbolNamed(kRecentTabsSymbol);
+        iconSelected = ImageViewForSymbol(kRecentTabsSymbol, true);
+        iconNotSelected = ImageViewForSymbol(kRecentTabsSymbol, false);
       } else {
         iconSelected = ImageViewForImageNamed(kImagePageControlRemoteSelected);
         iconNotSelected =
@@ -529,8 +569,13 @@
     }
   }
 
-  iconNotSelected.tintColor = UIColorFromRGB(kSliderColor);
-  iconSelected.tintColor = UIColorFromRGB(kSelectedColor);
+  if (UseSymbols()) {
+    iconNotSelected.tintColor = [UIColor colorNamed:kGrey300Color];
+    iconSelected.tintColor = UIColor.blackColor;
+  } else {
+    iconNotSelected.tintColor = UIColorFromRGB(kLegacySliderColor);
+    iconSelected.tintColor = UIColorFromRGB(kLegacySelectedColor);
+  }
 
   [self insertSubview:iconNotSelected belowSubview:self.sliderView];
   [self.selectedImageView addSubview:iconSelected];
@@ -539,13 +584,31 @@
 // Sets up all of the subviews for this control, as well as the layout guides
 // used to position the section content.
 - (void)setupViews {
-  UIView* backgroundView = [[TabGridPageControlBackground alloc] init];
+  UIView* backgroundView = nil;
+  if (UseSymbols()) {
+    backgroundView = [[UIView alloc]
+        initWithFrame:CGRectMake(0, 0, kOverallWidth, kSegmentHeight)];
+    backgroundView.backgroundColor = [UIColor colorWithWhite:1
+                                                       alpha:kBackgroundAlpha];
+
+  } else {
+    backgroundView = [[TabGridPageControlBackground alloc] init];
+  }
   backgroundView.userInteractionEnabled = NO;
-  backgroundView.layer.cornerRadius = kCornerRadius;
+  if (UseSymbols()) {
+    backgroundView.layer.cornerRadius = kBackgroundCornerRadius;
+  } else {
+    backgroundView.layer.cornerRadius = kLegacyBackgroundCornerRadius;
+  }
   backgroundView.layer.masksToBounds = YES;
   [self addSubview:backgroundView];
-  backgroundView.center =
-      CGPointMake(kOverallWidth / 2.0, kOverallHeight / 2.0);
+  if (UseSymbols()) {
+    backgroundView.center =
+        CGPointMake(kOverallWidth / 2.0, kOverallHeight / 2.0);
+  } else {
+    backgroundView.center =
+        CGPointMake(kLegacyOverallWidth / 2.0, kLegacyOverallHeight / 2.0);
+  }
 
   // Set up the layout guides for the segments.
   UILayoutGuide* incognitoGuide = [[UILayoutGuide alloc] init];
@@ -561,41 +624,94 @@
   // All of the guides are of the same height, and vertically centered in the
   // control.
   for (UILayoutGuide* guide in @[ incognitoGuide, regularGuide, remoteGuide ]) {
-    [guide.heightAnchor constraintEqualToConstant:kOverallHeight].active = YES;
+    if (UseSymbols()) {
+      [guide.heightAnchor constraintEqualToConstant:kOverallHeight].active =
+          YES;
+      // Guides are all the same width. The regular guide is centered in the
+      // control, and the incognito and remote guides are on the leading and
+      // trailing sides of it, with separators in between.
+      [guide.widthAnchor constraintEqualToConstant:kSegmentWidth].active = YES;
+    } else {
+      [guide.heightAnchor constraintEqualToConstant:kLegacyOverallHeight]
+          .active = YES;
+    }
     [guide.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active =
         YES;
   }
 
-  // Guides are all the same width (except the regular guide is wider to include
-  // the separators on either side of it. The regular guide is centered in the
-  // control, and the incognito and remote guides are on the leading and
-  // trailing sides of it.
-  [NSLayoutConstraint activateConstraints:@[
-    [incognitoGuide.widthAnchor constraintEqualToConstant:kSegmentWidth],
-    [regularGuide.widthAnchor
-        constraintEqualToConstant:kSegmentWidth + 2 * kSeparatorWidth],
-    [remoteGuide.widthAnchor constraintEqualToConstant:kSegmentWidth],
-    [regularGuide.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
-    [incognitoGuide.trailingAnchor
-        constraintEqualToAnchor:regularGuide.leadingAnchor],
-    [remoteGuide.leadingAnchor
-        constraintEqualToAnchor:regularGuide.trailingAnchor]
-  ]];
+  if (UseSymbols()) {
+    UIView* firstSeparator = [self newSeparator];
+    [self addSubview:firstSeparator];
+    self.firstSeparator = firstSeparator;
+    UIView* secondSeparator = [self newSeparator];
+    [self addSubview:secondSeparator];
+    self.secondSeparator = secondSeparator;
+
+    [NSLayoutConstraint activateConstraints:@[
+      [incognitoGuide.trailingAnchor
+          constraintEqualToAnchor:firstSeparator.leadingAnchor],
+      [firstSeparator.trailingAnchor
+          constraintEqualToAnchor:regularGuide.leadingAnchor],
+      [regularGuide.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
+      [regularGuide.trailingAnchor
+          constraintEqualToAnchor:secondSeparator.leadingAnchor],
+      [secondSeparator.trailingAnchor
+          constraintEqualToAnchor:remoteGuide.leadingAnchor],
+
+      [firstSeparator.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
+      [secondSeparator.centerYAnchor
+          constraintEqualToAnchor:self.centerYAnchor],
+    ]];
+
+  } else {
+    // Guides are all the same width (except the regular guide is wider to
+    // include the separators on either side of it). The regular guide is
+    // centered in the control, and the incognito and remote guides are on the
+    // leading and trailing sides of it.
+    [NSLayoutConstraint activateConstraints:@[
+      [incognitoGuide.widthAnchor
+          constraintEqualToConstant:kLegacySegmentWidth],
+      [regularGuide.widthAnchor
+          constraintEqualToConstant:kLegacySegmentWidth + 2 * kSeparatorWidth],
+      [remoteGuide.widthAnchor constraintEqualToConstant:kLegacySegmentWidth],
+      [regularGuide.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
+      [incognitoGuide.trailingAnchor
+          constraintEqualToAnchor:regularGuide.leadingAnchor],
+      [remoteGuide.leadingAnchor
+          constraintEqualToAnchor:regularGuide.trailingAnchor]
+    ]];
+  }
 
   // Add the slider above the section images and labels.
-  CGRect sliderFrame = CGRectMake(0, 0, kSliderWidth, kSliderHeight);
+  CGRect sliderFrame;
+  if (UseSymbols()) {
+    sliderFrame =
+        CGRectMake(0, kSliderVerticalMargin, kSliderWidth, kSliderHeight);
+  } else {
+    sliderFrame = CGRectMake(0, 0, kLegacySliderWidth, kSliderHeight);
+  }
   UIView* slider = [[UIView alloc] initWithFrame:sliderFrame];
-  slider.layer.cornerRadius = kCornerRadius;
+  slider.layer.cornerRadius = kSliderCornerRadius;
   slider.layer.masksToBounds = YES;
-  slider.backgroundColor = UIColorFromRGB(kSliderColor);
+  if (UseSymbols()) {
+    slider.backgroundColor = UIColor.whiteColor;
+  } else {
+    slider.backgroundColor = UIColorFromRGB(kLegacySliderColor);
+  }
 
   [self addSubview:slider];
   self.sliderView = slider;
 
   // Selected images and labels are added to the selected image view so they
   // will be clipped by the slider.
-  UIView* selectedImageView = [[UIView alloc]
-      initWithFrame:(CGRectMake(0, 0, kOverallWidth, kOverallHeight))];
+  CGRect selectedImageFrame;
+  if (UseSymbols()) {
+    selectedImageFrame = CGRectMake(0, 0, kOverallWidth, kOverallHeight);
+  } else {
+    selectedImageFrame =
+        CGRectMake(0, 0, kLegacyOverallWidth, kLegacyOverallHeight);
+  }
+  UIView* selectedImageView = [[UIView alloc] initWithFrame:selectedImageFrame];
   selectedImageView.userInteractionEnabled = NO;
   [self.sliderView addSubview:selectedImageView];
   self.selectedImageView = selectedImageView;
@@ -611,7 +727,12 @@
   [self.selectedImageView addSubview:regularSelectedLabel];
   self.regularSelectedLabel = regularSelectedLabel;
 
-  CGRect segmentRect = CGRectMake(0, 0, kSegmentWidth, kOverallHeight);
+  CGRect segmentRect;
+  if (UseSymbols()) {
+    segmentRect = CGRectMake(0, 0, kSegmentWidth, kOverallHeight);
+  } else {
+    segmentRect = CGRectMake(0, 0, kLegacySegmentWidth, kLegacyOverallHeight);
+  }
   UIView* incognitoHoverView = [[UIView alloc] initWithFrame:segmentRect];
   UIView* regularHoverView = [[UIView alloc] initWithFrame:segmentRect];
   UIView* remoteHoverView = [[UIView alloc] initWithFrame:segmentRect];
@@ -654,13 +775,26 @@
 // Selected labels use a different size and are black.
 - (UILabel*)labelSelected:(BOOL)selected {
   CGFloat size = selected ? kSelectedLabelSize : kLabelSize;
-  UIColor* color =
-      selected ? UIColorFromRGB(kSelectedColor) : UIColorFromRGB(kSliderColor);
+  UIColor* color;
+  if (UseSymbols()) {
+    color = selected ? UIColor.blackColor : [UIColor colorNamed:kGrey300Color];
+  } else {
+    color = selected ? UIColorFromRGB(kLegacySelectedColor)
+                     : UIColorFromRGB(kLegacySliderColor);
+  }
   UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, size, size)];
   label.backgroundColor = UIColor.clearColor;
   label.textAlignment = NSTextAlignmentCenter;
   label.textColor = color;
-  label.font = [UIFont systemFontOfSize:size * .6 weight:UIFontWeightBold];
+  if (UseSymbols()) {
+    CGFloat fontSize = size * .6;
+    UIFont* font = [UIFont systemFontOfSize:fontSize weight:UIFontWeightBold];
+    UIFontDescriptor* descriptor = [font.fontDescriptor
+        fontDescriptorWithDesign:UIFontDescriptorSystemDesignRounded];
+    label.font = [UIFont fontWithDescriptor:descriptor size:fontSize];
+  } else {
+    label.font = [UIFont systemFontOfSize:size * .6 weight:UIFontWeightBold];
+  }
   return label;
 }
 
@@ -699,6 +833,19 @@
   }
 }
 
+// Creates and returns a new separator, with constraints on its height/width.
+- (UIView*)newSeparator {
+  UIView* separator = [[UIView alloc] init];
+  separator.backgroundColor = [UIColor colorNamed:kGrey700Color];
+  separator.layer.cornerRadius = kSeparatorWidth / 2.0;
+  separator.translatesAutoresizingMaskIntoConstraints = NO;
+  [separator.heightAnchor constraintEqualToConstant:kSeparatorHeight].active =
+      YES;
+  [separator.widthAnchor constraintEqualToConstant:kSeparatorWidth].active =
+      YES;
+  return separator;
+}
+
 #pragma mark UIPointerInteractionDelegate
 
 - (UIPointerRegion*)pointerInteraction:(UIPointerInteraction*)interaction
@@ -716,7 +863,7 @@
                             initWithView:interaction.view]];
   UIPointerShape* shape =
       [UIPointerShape shapeWithRoundedRect:interaction.view.frame
-                              cornerRadius:kCornerRadius];
+                              cornerRadius:kSliderCornerRadius];
   return [UIPointerStyle styleWithEffect:effect shape:shape];
 }
 
@@ -725,8 +872,9 @@
 @implementation TabGridPageControlBackground
 
 - (instancetype)init {
-  self =
-      [super initWithFrame:CGRectMake(0, 0, kBackgroundWidth, kSegmentHeight)];
+  DCHECK(!UseSymbols());
+  CGRect frame = CGRectMake(0, 0, kLegacyBackgroundWidth, kLegacySegmentHeight);
+  self = [super initWithFrame:frame];
   if (self) {
     self.backgroundColor = UIColor.clearColor;
   }
@@ -734,12 +882,13 @@
 }
 
 - (CGSize)intrinsicContentsSize {
-  return CGSizeMake(kBackgroundWidth, kSegmentHeight);
+  return CGSizeMake(kLegacyBackgroundWidth, kLegacySegmentHeight);
 }
 
 - (void)drawRect:(CGRect)rect {
   CGContextRef drawing = UIGraphicsGetCurrentContext();
-  UIColor* backgroundColor = UIColorFromRGB(kBackgroundColor, kBackgroundAlpha);
+  UIColor* backgroundColor = [UIColor colorWithWhite:1
+                                               alpha:kLegacyBackgroundAlpha];
   CGContextSetFillColorWithColor(drawing, backgroundColor.CGColor);
   CGRect fillRect = CGRectMake(0, 0, kSegmentWidth, kSegmentHeight);
   CGContextFillRect(drawing, fillRect);
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 89213d5..78b795e 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-997a5beb33a8e83c09b39712180e890ff02b359a
\ No newline at end of file
+47bb49160c55208b4af1ff0f026d5fe18ed1af56
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 29260a1..dc096b5 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-8b419238ee65422d55855bcd3933f3a227045070
\ No newline at end of file
+7f25830968619aad88f9dc5ce3545f84d4069522
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 45e155e9..8ef6697 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-ff118e39f07f18020c8f60de85cae4b933f89eb7
\ No newline at end of file
+7107da3eb1ec2b35121f06840c9566cb3fb48d0b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 2180bf2..65b7606fca 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-54c1b98462c8b44a97c03bcf3850bb1329e5029d
\ No newline at end of file
+27ddf93ba8c5ef580e1c8ff1675006f424531b2d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 6e1af0e..80bbd63f 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-295f34910b160ccf8caf15b801ebb5a8e5dba0f7
\ No newline at end of file
+3346c7d419df0e292e764999b355f47e3a5c77c0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 3c267ae..8ca74d2 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-63239915aa5059d10efe22b312d9c40cfd3fbb34
\ No newline at end of file
+61e5d96ae8d90481ee230c2ac1219a4298ca9ddf
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index a5385fa..96119c8c 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-a1ccf0dabed13ec71301c719a8ccfa4cf466f5bb
\ No newline at end of file
+2d667bcb1954a89586b58a04dbf8d38ca902d4a7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 5549013..c618a0c 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-65ffad4c7e4f485a9f1b68affe14499c7519df0f
\ No newline at end of file
+3e2007c07d506e2ccfe534cd999a569bb99b0709
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 19a666c..e92ae41 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b6e8a718854ee023e180ecb1749093598ec8f7c1
\ No newline at end of file
+0422e7b8268197e7588ed1343a091b1cb60b52e9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index ce010af0..a5e2f137 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-17265817754bd422944d50df309373eee4e0be78
\ No newline at end of file
+0e568a4fdee7c7af36606910766bff827309ae5e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index d22df79..67426b0 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-ce7e0faa409004f090fb9cd5f919f361383a1c7c
\ No newline at end of file
+912be2b58ee353fa897d6a1e7d76e33842ad4c0b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 91b6d54c..02355bf8 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-778eac85d7f0bc3222f56d8cca21a4b76ab4258e
\ No newline at end of file
+e38a111fbd973344e599c99749ea78ca74aefbd9
\ No newline at end of file
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 35d8bce..7dcd29a 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -99,6 +99,9 @@
   libs = []
   ldflags = []
 
+  # V4L2 and VAAPI for video acceleration should not be enabled simultaneously.
+  assert(!(use_v4l2_codec && use_vaapi))
+
   # TODO(crbug.com/1006266): consider using |use_chromeos_video_acceleration|.
   if (use_v4l2_codec || use_vaapi) {
     public_deps += [
diff --git a/media/gpu/chromeos/BUILD.gn b/media/gpu/chromeos/BUILD.gn
index 2b1f70c..7cfe1cf 100644
--- a/media/gpu/chromeos/BUILD.gn
+++ b/media/gpu/chromeos/BUILD.gn
@@ -7,6 +7,9 @@
 import("//testing/test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
+# V4L2 and VAAPI for video acceleration should not be enabled simultaneously.
+assert(!(use_v4l2_codec && use_vaapi))
+
 assert(use_v4l2_codec || use_vaapi)
 
 # V4L2 or Vaapi imply the OS is Linux or ChromeOS
diff --git a/media/gpu/chromeos/fourcc.cc b/media/gpu/chromeos/fourcc.cc
index cf76edf2..cc30a89 100644
--- a/media/gpu/chromeos/fourcc.cc
+++ b/media/gpu/chromeos/fourcc.cc
@@ -10,9 +10,7 @@
 
 #if BUILDFLAG(USE_V4L2_CODEC)
 #include <linux/videodev2.h>
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
-
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
 #include <va/va.h>
 #endif  // BUILDFLAG(USE_VAAPI)
 
@@ -201,9 +199,7 @@
   // Fourcc as V4L2.
   return static_cast<uint32_t>(value_);
 }
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
-
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
 // static
 absl::optional<Fourcc> Fourcc::FromVAFourCC(uint32_t va_fourcc) {
   switch (va_fourcc) {
diff --git a/media/gpu/chromeos/fourcc.h b/media/gpu/chromeos/fourcc.h
index 89195916..f61e7362 100644
--- a/media/gpu/chromeos/fourcc.h
+++ b/media/gpu/chromeos/fourcc.h
@@ -115,8 +115,7 @@
   // Converts a V4L2PixFmt to Fourcc.
   // Returns nullopt for invalid input.
   static absl::optional<Fourcc> FromV4L2PixFmt(uint32_t v4l2_pix_fmt);
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
   // Converts a VAFourCC to Fourcc.
   // Returns nullopt for invalid input.
   static absl::optional<Fourcc> FromVAFourCC(uint32_t va_fourcc);
@@ -130,8 +129,7 @@
   // Returns the V4L2PixFmt counterpart of the value.
   // Returns 0 if no mapping is found.
   uint32_t ToV4L2PixFmt() const;
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
   // Returns the VAFourCC counterpart of the value.
   // Returns nullopt if no mapping is found.
   absl::optional<uint32_t> ToVAFourCC() const;
diff --git a/media/gpu/chromeos/fourcc_unittests.cc b/media/gpu/chromeos/fourcc_unittests.cc
index 96947ebb..128d73c 100644
--- a/media/gpu/chromeos/fourcc_unittests.cc
+++ b/media/gpu/chromeos/fourcc_unittests.cc
@@ -10,8 +10,7 @@
 
 #if BUILDFLAG(USE_V4L2_CODEC)
 #include <linux/videodev2.h>
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
 #include <va/va.h>
 #endif  // BUILDFLAG(USE_VAAPI)
 
@@ -104,9 +103,9 @@
       V4L2_PIX_FMT_YUV422M,
       Fourcc::FromVideoPixelFormat(PIXEL_FORMAT_I422, false)->ToV4L2PixFmt());
 }
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
 
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
+
 // Checks that converting a VaFourCC to Fourcc and back to VaFourCC
 // yields the same format as the original one.
 static void CheckFromVAFourCCAndBack(uint32_t va_fourcc) {
@@ -155,7 +154,7 @@
   EXPECT_EQ(static_cast<uint32_t>(VA_FOURCC_P010),
             *Fourcc::FromVideoPixelFormat(PIXEL_FORMAT_P016LE)->ToVAFourCC());
 }
-#endif  // BUILDFLAG(USE_VAAPI)
+#endif
 
 TEST(FourccTest, FourccToSinglePlanar) {
   EXPECT_EQ(Fourcc(Fourcc::YU12).ToSinglePlanar(), Fourcc(Fourcc::YU12));
diff --git a/media/gpu/chromeos/image_processor_factory.cc b/media/gpu/chromeos/image_processor_factory.cc
index cc1379fb..96b9eb5e 100644
--- a/media/gpu/chromeos/image_processor_factory.cc
+++ b/media/gpu/chromeos/image_processor_factory.cc
@@ -22,13 +22,11 @@
 #if BUILDFLAG(USE_VAAPI)
 #include "media/gpu/vaapi/vaapi_image_processor_backend.h"
 #include "media/gpu/vaapi/vaapi_wrapper.h"
-#endif  // BUILDFLAG(USE_VAAPI)
-
-#if BUILDFLAG(USE_V4L2_CODEC)
+#elif BUILDFLAG(USE_V4L2_CODEC)
 #include "media/gpu/v4l2/v4l2_device.h"
 #include "media/gpu/v4l2/v4l2_image_processor_backend.h"
 #include "media/gpu/v4l2/v4l2_vda_helpers.h"
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
+#endif
 
 namespace media {
 
@@ -82,9 +80,9 @@
       output_config, ImageProcessor::OutputMode::IMPORT, VIDEO_ROTATION_0,
       std::move(error_cb), std::move(client_task_runner));
 }
-#endif  // BUILDFLAG(USE_VAAPI)
 
-#if BUILDFLAG(USE_V4L2_CODEC) && !BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_V4L2_CODEC)
+
 std::unique_ptr<ImageProcessor> CreateV4L2ImageProcessorWithInputCandidates(
     const std::vector<PixelLayoutCandidate>& input_candidates,
     const gfx::Rect& visible_rect,
@@ -227,7 +225,7 @@
       output_config, ImageProcessor::OutputMode::IMPORT, VIDEO_ROTATION_0,
       std::move(error_cb), std::move(client_task_runner));
 }
-#endif  // BUILDFLAG(USE_V4L2_CODEC) && !BUILDFLAG(USE_VAAPI)
+#endif
 
 }  // namespace
 
@@ -247,7 +245,7 @@
 #elif BUILDFLAG(USE_V4L2_CODEC)
   create_funcs.push_back(base::BindRepeating(
       &V4L2ImageProcessorBackend::Create, V4L2Device::Create(), num_buffers));
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
+#endif
   create_funcs.push_back(
       base::BindRepeating(&LibYUVImageProcessorBackend::Create));
 
@@ -299,7 +297,7 @@
   if (processor)
     return processor;
 
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
+#endif
 
   // TODO(crbug.com/1004727): Implement LibYUVImageProcessorBackend. When doing
   // so, we must keep in mind that it might not be desirable to fallback to
diff --git a/media/gpu/gpu_video_encode_accelerator_factory.cc b/media/gpu/gpu_video_encode_accelerator_factory.cc
index 9264f446..484fe741 100644
--- a/media/gpu/gpu_video_encode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_encode_accelerator_factory.cc
@@ -21,9 +21,6 @@
 #include "media/gpu/macros.h"
 #include "media/video/video_encode_accelerator.h"
 
-#if BUILDFLAG(USE_V4L2_CODEC)
-#include "media/gpu/v4l2/v4l2_video_encode_accelerator.h"
-#endif
 #if BUILDFLAG(IS_ANDROID)
 #include "media/gpu/android/android_video_encode_accelerator.h"
 #include "media/gpu/android/ndk_video_encode_accelerator.h"
@@ -34,7 +31,9 @@
 #if BUILDFLAG(IS_WIN)
 #include "media/gpu/windows/media_foundation_video_encode_accelerator_win.h"
 #endif
-#if BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_V4L2_CODEC)
+#include "media/gpu/v4l2/v4l2_video_encode_accelerator.h"
+#elif BUILDFLAG(USE_VAAPI)
 #include "media/gpu/vaapi/vaapi_video_encode_accelerator.h"
 #endif
 #if BUILDFLAG(IS_FUCHSIA)
@@ -58,9 +57,7 @@
   return nullptr;
 #endif
 }
-#endif
-
-#if BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_VAAPI)
 std::unique_ptr<VideoEncodeAccelerator> CreateVaapiVEA() {
   return base::WrapUnique<VideoEncodeAccelerator>(
       new VaapiVideoEncodeAccelerator());
@@ -129,10 +126,10 @@
 #else
   vea_factory_functions.push_back(base::BindRepeating(&CreateVaapiVEA));
 #endif
-#endif
-#if BUILDFLAG(USE_V4L2_CODEC)
+#elif BUILDFLAG(USE_V4L2_CODEC)
   vea_factory_functions.push_back(base::BindRepeating(&CreateV4L2VEA));
 #endif
+
 #if BUILDFLAG(IS_ANDROID)
   vea_factory_functions.push_back(base::BindRepeating(&CreateAndroidVEA));
 #endif
diff --git a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
index 25e31b6..b8fd522b 100644
--- a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
+++ b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
@@ -72,7 +72,7 @@
           BrokerFilePermission::ReadOnlyRecursive(path + "/"));
     }
   }
-#endif  // BUILDFLAG(USE_V4L2_CODEC)
+#endif
 
   // TODO(b/195769334): consider using the type of client to decide if we should
   // allow access to the render node:
@@ -125,7 +125,7 @@
 #else
   dlopen("/usr/lib/libv4l2.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
 #endif  // defined(__aarch64__)
-#endif  // BUILDFLAG(USE_VAAPI)
+#endif
 
   return true;
 }
diff --git a/sandbox/win/src/policy_engine_opcodes.cc b/sandbox/win/src/policy_engine_opcodes.cc
index b9b856a..51c3befa 100644
--- a/sandbox/win/src/policy_engine_opcodes.cc
+++ b/sandbox/win/src/policy_engine_opcodes.cc
@@ -44,7 +44,7 @@
 
 size_t OpcodeFactory::memory_size() const {
   DCHECK_GE(memory_bottom_, memory_top_);
-  return memory_bottom_ - memory_top_;
+  return static_cast<size_t>(memory_bottom_ - memory_top_);
 }
 
 template <int>
@@ -57,7 +57,7 @@
 // Does not require input parameter.
 
 PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32_t options) {
-  return MakeBase(OP_ALWAYS_FALSE, options, -1);
+  return MakeBase(OP_ALWAYS_FALSE, options);
 }
 
 template <>
@@ -72,7 +72,7 @@
 // Does not require input parameter.
 
 PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32_t options) {
-  return MakeBase(OP_ALWAYS_TRUE, options, -1);
+  return MakeBase(OP_ALWAYS_TRUE, options);
 }
 
 template <>
@@ -110,7 +110,7 @@
 // Argument 0 is the stored number to match.
 // Argument 1 is the C++ type of the 0th argument.
 
-PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16_t selected_param,
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(uint8_t selected_param,
                                                uint32_t match,
                                                uint32_t options) {
   PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
@@ -121,7 +121,7 @@
   return opcode;
 }
 
-PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16_t selected_param,
+PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(uint8_t selected_param,
                                                 const void* match,
                                                 uint32_t options) {
   PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
@@ -158,7 +158,7 @@
 // Argument 0 is the stored lower bound to match.
 // Argument 1 is the stored upper bound to match.
 
-PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16_t selected_param,
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(uint8_t selected_param,
                                                     uint32_t lower_bound,
                                                     uint32_t upper_bound,
                                                     uint32_t options) {
@@ -195,7 +195,7 @@
 // Requires a uint32_t in selected_param.
 // Argument 0 is the stored number to match.
 
-PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16_t selected_param,
+PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(uint8_t selected_param,
                                                   uint32_t match,
                                                   uint32_t options) {
   PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param);
@@ -227,7 +227,7 @@
 // as noted in the header file.
 // Argument 3 is the string matching options.
 
-PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16_t selected_param,
+PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(uint8_t selected_param,
                                                 const wchar_t* match_str,
                                                 int start_position,
                                                 StringMatchOptions match_opts,
@@ -237,12 +237,12 @@
   if ('\0' == match_str[0])
     return nullptr;
 
-  int length = lstrlenW(match_str);
+  size_t length = wcslen(match_str);
 
   PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param);
   if (!opcode)
     return nullptr;
-  ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str) + 1);
+  ptrdiff_t delta_str = AllocRelative(opcode, match_str, length + 1);
   if (0 == delta_str)
     return nullptr;
   opcode->SetArgument(0, delta_str);
@@ -268,7 +268,7 @@
     return EVAL_FALSE;
 
   int start_position = 0;
-  int match_len = 0;
+  size_t match_len = 0;
   unsigned int match_opts = 0;
   opcode->GetArgument(1, &match_len);
   opcode->GetArgument(2, &start_position);
@@ -278,7 +278,7 @@
   // Advance the source string to the last successfully evaluated position
   // according to the match context.
   source_str = &source_str[context->position];
-  int source_len = static_cast<int>(GetNtExports()->wcslen(source_str));
+  size_t source_len = GetNtExports()->wcslen(source_str);
 
   if (0 == source_len) {
     // If we reached the end of the source string there is nothing we can
@@ -298,22 +298,23 @@
   // Case 2: We skip to the end and compare once.
   // Case 3: We match the first substring (if we find any).
   if (start_position >= 0) {
+    size_t start_offset = static_cast<size_t>(start_position);
     if (kSeekToEnd == start_position) {
-      start_position = source_len - match_len;
+      start_offset = static_cast<size_t>(source_len - match_len);
     } else if (match_opts & EXACT_LENGTH) {
       // A sub-case of case 3 is when the EXACT_LENGTH flag is on
       // the match needs to be not just substring but full match.
-      if ((match_len + start_position) != source_len) {
+      if ((match_len + start_offset) != source_len) {
         return EVAL_FALSE;
       }
     }
 
     // Advance start_pos characters. Warning! this does not consider
     // utf16 encodings (surrogate pairs) or other Unicode 'features'.
-    source_str += start_position;
+    source_str += start_offset;
 
     // Since we skipped, lets reevaluate just the lengths again.
-    if ((match_len + start_position) > source_len) {
+    if ((match_len + start_offset) > source_len) {
       return EVAL_FALSE;
     }
 
@@ -326,7 +327,7 @@
     if (0 == GetNtExports()->RtlCompareUnicodeString(&match_ustr, &source_ustr,
                                                      case_sensitive)) {
       // Match! update the match context.
-      context->position += start_position + match_len;
+      context->position += start_offset + match_len;
       return EVAL_TRUE;
     } else {
       return EVAL_FALSE;
@@ -342,7 +343,8 @@
       if (0 == GetNtExports()->RtlCompareUnicodeString(
                    &match_ustr, &source_ustr, case_sensitive)) {
         // Match! update the match context.
-        context->position += (source_ustr.Buffer - source_str) + match_len;
+        context->position +=
+            static_cast<size_t>(source_ustr.Buffer - source_str) + match_len;
         return EVAL_TRUE;
       }
       ++source_ustr.Buffer;
@@ -355,9 +357,7 @@
 //////////////////////////////////////////////////////////////////////////////
 // OpcodeMaker (other member functions).
 
-PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
-                                      uint32_t options,
-                                      int16_t selected_param) {
+PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id, uint32_t options) {
   if (memory_size() < sizeof(PolicyOpcode))
     return nullptr;
 
@@ -368,6 +368,18 @@
   memory_top_ += sizeof(PolicyOpcode);
   opcode->opcode_id_ = opcode_id;
   opcode->SetOptions(options);
+  opcode->has_param_ = 0;
+  opcode->parameter_ = 0;
+  return opcode;
+}
+
+PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
+                                      uint32_t options,
+                                      uint8_t selected_param) {
+  PolicyOpcode* opcode = MakeBase(opcode_id, options);
+  if (!opcode)
+    return nullptr;
+  opcode->has_param_ = 1;
   opcode->parameter_ = selected_param;
   return opcode;
 }
@@ -404,8 +416,8 @@
   if (!call_params)
     return EVAL_ERROR;
   const ParameterSet* selected_param = nullptr;
-  if (parameter_ >= 0) {
-    if (static_cast<size_t>(parameter_) >= param_count) {
+  if (has_param_) {
+    if (parameter_ >= param_count) {
       return EVAL_ERROR;
     }
     selected_param = &call_params[parameter_];
diff --git a/sandbox/win/src/policy_engine_opcodes.h b/sandbox/win/src/policy_engine_opcodes.h
index fbaeecd..a457fee 100644
--- a/sandbox/win/src/policy_engine_opcodes.h
+++ b/sandbox/win/src/policy_engine_opcodes.h
@@ -73,8 +73,8 @@
   TERMINATE_PROCESS,   // Destroy target process. Do IPC as well.
 };
 
-// The following are the implemented opcodes.
-enum OpcodeID {
+// The following are the implemented opcodes. uint16_t purely to pack nicely.
+enum OpcodeID : uint16_t {
   OP_ALWAYS_FALSE,        // Evaluates to false (EVAL_FALSE).
   OP_ALWAYS_TRUE,         // Evaluates to true (EVAL_TRUE).
   OP_NUMBER_MATCH,        // Match a 32-bit integer as n == a.
@@ -195,7 +195,7 @@
   void SetOptions(uint32_t options) { options_ = options; }
 
   // Returns the parameter of the function the opcode concerns.
-  uint16_t GetParameter() const { return parameter_; }
+  uint8_t GetParameter() const { return parameter_; }
 
  private:
   static const size_t kArgumentCount = 4;  // The number of supported argument.
@@ -213,7 +213,10 @@
   EvalResult EvaluateHelper(const ParameterSet* parameters,
                             MatchContext* match);
   OpcodeID opcode_id_;
-  int16_t parameter_;
+  // Used a boolean field but provided as a uint8_t to maintain packing.
+  uint8_t has_param_;
+  // Not used if has_param_ is false.
+  uint8_t parameter_;
   uint32_t options_;
   OpcodeArgument arguments_[PolicyOpcode::kArgumentCount];
 };
@@ -301,7 +304,7 @@
   // selected_param: index of the input argument. It must be a uint32_t or the
   // evaluation result will generate a EVAL_ERROR.
   // match: the number to compare against the selected_param.
-  PolicyOpcode* MakeOpNumberMatch(int16_t selected_param,
+  PolicyOpcode* MakeOpNumberMatch(uint8_t selected_param,
                                   uint32_t match,
                                   uint32_t options);
 
@@ -309,7 +312,7 @@
   // selected_param: index of the input argument. It must be an void* or the
   // evaluation result will generate a EVAL_ERROR.
   // match: the pointer numeric value to compare against selected_param.
-  PolicyOpcode* MakeOpVoidPtrMatch(int16_t selected_param,
+  PolicyOpcode* MakeOpVoidPtrMatch(uint8_t selected_param,
                                    const void* match,
                                    uint32_t options);
 
@@ -317,7 +320,7 @@
   // selected_param: index of the input argument. It must be a uint32_t or the
   // evaluation result will generate a EVAL_ERROR.
   // lower_bound, upper_bound: the range to compare against selected_param.
-  PolicyOpcode* MakeOpNumberMatchRange(int16_t selected_param,
+  PolicyOpcode* MakeOpNumberMatchRange(uint8_t selected_param,
                                        uint32_t lower_bound,
                                        uint32_t upper_bound,
                                        uint32_t options);
@@ -335,7 +338,7 @@
   // current implementation.
   // match_opts: Indicates additional matching flags. Currently CaseInsensitive
   // is supported.
-  PolicyOpcode* MakeOpWStringMatch(int16_t selected_param,
+  PolicyOpcode* MakeOpWStringMatch(uint8_t selected_param,
                                    const wchar_t* match_str,
                                    int start_position,
                                    StringMatchOptions match_opts,
@@ -345,17 +348,17 @@
   // selected_param: index of the input argument. It must be uint32_t or the
   // evaluation result will generate a EVAL_ERROR.
   // match: the value to bitwise AND against selected_param.
-  PolicyOpcode* MakeOpNumberAndMatch(int16_t selected_param,
+  PolicyOpcode* MakeOpNumberAndMatch(uint8_t selected_param,
                                      uint32_t match,
                                      uint32_t options);
 
  private:
   // Constructs the common part of every opcode. selected_param is the index
-  // of the input param to use when evaluating the opcode. Pass -1 in
-  // selected_param to indicate that no input parameter is required.
+  // of the input param to use when evaluating the opcode.
+  PolicyOpcode* MakeBase(OpcodeID opcode_id, uint32_t options);
   PolicyOpcode* MakeBase(OpcodeID opcode_id,
                          uint32_t options,
-                         int16_t selected_param);
+                         uint8_t selected_param);
 
   // Allocates (and copies) a string (of size length) inside the buffer and
   // returns the displacement with respect to start.
diff --git a/sandbox/win/src/policy_low_level.cc b/sandbox/win/src/policy_low_level.cc
index e67077c..0f47c96 100644
--- a/sandbox/win/src/policy_low_level.cc
+++ b/sandbox/win/src/policy_low_level.cc
@@ -157,7 +157,7 @@
 // to zero.
 bool PolicyRule::GenStringOpcode(RuleType rule_type,
                                  StringMatchOptions match_opts,
-                                 uint16_t parameter,
+                                 uint8_t parameter,
                                  int state,
                                  bool last_call,
                                  int* skip_count,
@@ -221,7 +221,7 @@
 }
 
 bool PolicyRule::AddStringMatch(RuleType rule_type,
-                                int16_t parameter,
+                                uint8_t parameter,
                                 const wchar_t* string,
                                 StringMatchOptions match_opts) {
   if (done_) {
@@ -283,7 +283,7 @@
 }
 
 bool PolicyRule::AddNumberMatch(RuleType rule_type,
-                                int16_t parameter,
+                                uint8_t parameter,
                                 uint32_t number,
                                 RuleOp comparison_op) {
   if (done_) {
diff --git a/sandbox/win/src/policy_low_level.h b/sandbox/win/src/policy_low_level.h
index c2828a1c..fd7d1396 100644
--- a/sandbox/win/src/policy_low_level.h
+++ b/sandbox/win/src/policy_low_level.h
@@ -140,7 +140,7 @@
   // string: is the desired matching pattern.
   // match_opts: if the pattern matching is case sensitive or not.
   bool AddStringMatch(RuleType rule_type,
-                      int16_t parameter,
+                      uint8_t parameter,
                       const wchar_t* string,
                       StringMatchOptions match_opts);
 
@@ -150,7 +150,7 @@
   // number: the value to compare the input to.
   // comparison_op: the comparison kind (equal, logical and, etc).
   bool AddNumberMatch(RuleType rule_type,
-                      int16_t parameter,
+                      uint8_t parameter,
                       uint32_t number,
                       RuleOp comparison_op);
 
@@ -168,7 +168,7 @@
   // in AddStringMatch.
   bool GenStringOpcode(RuleType rule_type,
                        StringMatchOptions match_opts,
-                       uint16_t parameter,
+                       uint8_t parameter,
                        int state,
                        bool last_call,
                        int* skip_count,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2f5742b..b534164f 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5922,9 +5922,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5936,8 +5936,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -6088,9 +6088,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6102,8 +6102,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -6239,9 +6239,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6253,8 +6253,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index aeeb737..5c33ac2 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -87396,9 +87396,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87410,8 +87410,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -87532,9 +87532,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87546,8 +87546,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -87658,9 +87658,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -87672,8 +87672,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -89013,9 +89013,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89026,8 +89026,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -89179,9 +89179,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89192,8 +89192,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -89330,9 +89330,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -89343,8 +89343,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -90865,9 +90865,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -90878,8 +90878,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -91031,9 +91031,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -91044,8 +91044,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -91182,9 +91182,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -91195,8 +91195,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -91994,9 +91994,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -92007,8 +92007,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index bddee2b..cc717ab 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18559,10 +18559,10 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18574,8 +18574,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -18733,10 +18733,10 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18748,8 +18748,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
@@ -18889,10 +18889,10 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always"
         ],
-        "description": "Run with ash-chrome version 110.0.5424.0",
+        "description": "Run with ash-chrome version 110.0.5425.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18904,8 +18904,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v110.0.5424.0",
-              "revision": "version:110.0.5424.0"
+              "location": "lacros_version_skew_tests_v110.0.5425.0",
+              "revision": "version:110.0.5425.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.webrtc.fyi.json b/testing/buildbot/chromium.webrtc.fyi.json
index b2fb128..17b5018 100644
--- a/testing/buildbot/chromium.webrtc.fyi.json
+++ b/testing/buildbot/chromium.webrtc.fyi.json
@@ -55,96 +55,6 @@
       }
     ]
   },
-  "WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=WebRtc*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_os_type": "userdebug",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      }
-    ]
-  },
-  "WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=WebRtc*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "N",
-              "device_os_type": "userdebug",
-              "device_type": "bullhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      }
-    ]
-  },
   "WebRTC Chromium FYI Android Tests ARM64 (dbg)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 74bceff..e23031b 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -1050,13 +1050,6 @@
       ]
     },
   },
-  'nougat_generic': {
-    'swarming': {
-      'dimensions': {
-        'device_os': 'N',
-      },
-    },
-  },
   'oreo-x86-emulator': {
     '$mixin_append': {
       'args': [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index cc940c4..787e116c 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1676,16 +1676,6 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter',
         ],
       },
-      'WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter',
-        ],
-      },
-      'WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter',
-        ],
-      },
       'WebRTC Chromium FYI Android Tests ARM64 (dbg)': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/chromium.webrtc.fyi.android.tests.dbg.content_browsertests.filter',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index cbe9b05..c746f59 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -590,7 +590,6 @@
           'flame',
           'marshmallow',
           'mdarcy',
-          'nougat_generic',
           'oreo_fleet',
           'pie_fleet',
           'walleye',
@@ -1598,7 +1597,6 @@
           'flame',
           'marshmallow',
           'mdarcy',
-          'nougat_generic',
           'oreo_fleet',
           'pie_fleet',
           'walleye',
@@ -4291,7 +4289,6 @@
           'flame',
           'marshmallow',
           'mdarcy',
-          'nougat_generic',
           'oreo_fleet',
           'pie_fleet',
           'walleye',
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 35e81fbc..25836ad4 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5424.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v110.0.5425.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 110.0.5424.0',
+    'description': 'Run with ash-chrome version 110.0.5425.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v110.0.5424.0',
-          'revision': 'version:110.0.5424.0',
+          'location': 'lacros_version_skew_tests_v110.0.5425.0',
+          'revision': 'version:110.0.5425.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index fcef396e..45b1bad 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5944,26 +5944,6 @@
           'gtest_tests': 'webrtc_chromium_simple_gtests',
         },
       },
-      'WebRTC Chromium FYI Android Tests (dbg) (M Nexus5X)': {
-        'os_type': 'android',
-        'mixins': [
-          'marshmallow',
-          'bullhead',
-        ],
-        'test_suites': {
-          'gtest_tests': 'webrtc_chromium_simple_gtests',
-        },
-      },
-      'WebRTC Chromium FYI Android Tests (dbg) (N Nexus5X)': {
-        'os_type': 'android',
-        'mixins': [
-          'nougat_generic',
-          'bullhead',
-        ],
-        'test_suites': {
-          'gtest_tests': 'webrtc_chromium_simple_gtests',
-        },
-      },
       'WebRTC Chromium FYI Android Tests ARM64 (dbg)': {
         'os_type': 'android',
         'mixins': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9652c2c..d7f723582 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2769,7 +2769,104 @@
             ],
             "experiments": [
                 {
-                    "name": "Shopping_Launch",
+                    "name": "Dogfood",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "bookmark_compact_visuals_enabled": "true",
+                        "bookmark_in_app_menu": "true",
+                        "bookmark_visuals_enabled": "true",
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_notification": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "BookmarksRefresh",
+                        "CommercePriceTracking",
+                        "OptimizationGuidePushNotifications",
+                        "ReadLater",
+                        "ShoppingList"
+                    ]
+                },
+                {
+                    "name": "Default_1__M100_C_v5",
+                    "params": {
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "ReadLater_CCT_non_US__NoCustomTab_M100_C_v5",
+                    "params": {
+                        "use_cct": "false",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "ReadLater_SaveFlow_non_US__SemiIntegratedRedux_M100_C_v5",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "Default_1__M100_A_v5",
+                    "params": {
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "CommercePriceTracking",
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "ReadLater_CCT_US__NoCustomTab_M100_A_v5",
+                    "params": {
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_cct": "false",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "CommercePriceTracking",
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "ReadLater_SaveFlow_US__SemiIntegratedRedux_M100_A_v5",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "CommercePriceTracking",
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "WallE_US__ShoppingCompact_M100_A_v5",
                     "params": {
                         "autodismiss_enabled": "true",
                         "bookmark_compact_visuals_enabled": "true",
@@ -2778,13 +2875,75 @@
                         "enable_persisted_tab_data_maintenance": "true",
                         "enable_price_notification": "true",
                         "enable_price_tracking": "true",
-                        "price_tracking_with_optimization_guide": "true"
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_root_bookmark_as_default": "true"
                     },
                     "enable_features": [
                         "BookmarksImprovedSaveFlow",
                         "BookmarksRefresh",
                         "CommercePriceTracking",
                         "OptimizationGuidePushNotifications",
+                        "ReadLater",
+                        "ShoppingList"
+                    ]
+                },
+                {
+                    "name": "ReadLater_SaveFlow_non_US__SemiIntegrated_NoCCT_M100_C_v7",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "use_cct": "false",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "ReadLater"
+                    ]
+                },
+                {
+                    "name": "WallE_US__ShoppingCompact_WithRL_M100_A_v7",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "bookmark_compact_visuals_enabled": "true",
+                        "bookmark_in_app_menu": "true",
+                        "bookmark_visuals_enabled": "true",
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_notification": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "BookmarksRefresh",
+                        "CommercePriceTracking",
+                        "OptimizationGuidePushNotifications",
+                        "ReadLater",
+                        "ShoppingList"
+                    ]
+                },
+                {
+                    "name": "WallE_US__ShoppingCompact_WithRL_NoCCT_M100_A_v7",
+                    "params": {
+                        "allow_bookmark_type_swapping": "true",
+                        "autodismiss_enabled": "true",
+                        "bookmark_compact_visuals_enabled": "true",
+                        "bookmark_in_app_menu": "true",
+                        "bookmark_visuals_enabled": "true",
+                        "enable_persisted_tab_data_maintenance": "true",
+                        "enable_price_notification": "true",
+                        "enable_price_tracking": "true",
+                        "price_tracking_with_optimization_guide": "true",
+                        "use_cct": "false",
+                        "use_root_bookmark_as_default": "true"
+                    },
+                    "enable_features": [
+                        "BookmarksImprovedSaveFlow",
+                        "BookmarksRefresh",
+                        "CommercePriceTracking",
+                        "OptimizationGuidePushNotifications",
+                        "ReadLater",
                         "ShoppingList"
                     ]
                 }
@@ -9156,25 +9315,6 @@
             ]
         }
     ],
-    "ReadLaterUSOnly": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "params": {
-                        "allow_bookmark_type_swapping": "true",
-                        "use_cct": "false"
-                    },
-                    "enable_features": [
-                        "ReadLater"
-                    ]
-                }
-            ]
-        }
-    ],
     "RecordPermissionExpirationTimestamps": [
         {
             "platforms": [
diff --git a/third_party/blink/public/common/loader/loading_behavior_flag.h b/third_party/blink/public/common/loader/loading_behavior_flag.h
index 8d1308f..2807058 100644
--- a/third_party/blink/public/common/loader/loading_behavior_flag.h
+++ b/third_party/blink/public/common/loader/loading_behavior_flag.h
@@ -69,6 +69,9 @@
   // Indicates that the page is controlled by a Service Worker, but
   // the fetch handler is considered skippable.
   kLoadingBehaviorServiceWorkerFetchHandlerSkippable = 1 << 20,
+  // Indicates that the main resource fetch for the page controlled by
+  // a service worker at the navigation time fallback to network.
+  kLoadingBehaviorServiceWorkerMainResourceFetchFallback = 1 << 21,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 92fc4db..b536eea 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -552,6 +552,13 @@
   // use for segregated histograms.
   virtual void DidObserveLoadingBehavior(LoadingBehaviorFlag) {}
 
+  // A subresource load is observed.
+  // It is called when there is a subresouce load. The reported values via
+  // arguments are cumulative. They are NOT a difference from the previous call.
+  virtual void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) {}
+
   // Blink hits the code path for a certain UseCounterFeature for the first time
   // on this frame. As a performance optimization, features already hit on other
   // frames associated with the same page in the renderer are not currently
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
index 781c5cd8..8be0c6b 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache.cc
@@ -245,7 +245,7 @@
   // style stored for a shadow root child against a non shadow root child, we
   // would end up with an incorrect match.
   if (IsAtShadowBoundary(&state.GetElement()) &&
-      state.Style()->UserModify() != parent_style.UserModify()) {
+      state.StyleBuilder().UserModify() != parent_style.UserModify()) {
     return false;
   }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index eec6b37..56092062 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -269,8 +269,7 @@
 }
 
 void StyleAdjuster::AdjustStyleForEditing(ComputedStyleBuilder& builder) {
-  const ComputedStyle& style = *builder.InternalStyle();
-  if (style.UserModify() != EUserModify::kReadWritePlaintextOnly)
+  if (builder.UserModify() != EUserModify::kReadWritePlaintextOnly)
     return;
   // Collapsing whitespace is harmful in plain-text editing.
   if (builder.WhiteSpace() == EWhiteSpace::kNormal)
@@ -589,8 +588,8 @@
 }
 
 bool StyleAdjuster::IsEditableElement(Element* element,
-                                      const ComputedStyle& style) {
-  if (style.UserModify() != EUserModify::kReadOnly)
+                                      const ComputedStyleBuilder& builder) {
+  if (builder.UserModify() != EUserModify::kReadOnly)
     return true;
 
   if (!element)
@@ -685,7 +684,7 @@
   if (element->GetDocument().IsVerticalScrollEnforced())
     enforced_by_policy = TouchAction::kPanY;
   if (::features::IsSwipeToMoveCursorEnabled() &&
-      IsEditableElement(element, style)) {
+      IsEditableElement(element, builder)) {
     element_touch_action &= ~TouchAction::kInternalPanXScrolls;
   }
 
@@ -694,7 +693,7 @@
   if (base::FeatureList::IsEnabled(blink::features::kStylusWritingToInput) &&
       RuntimeEnabledFeatures::StylusHandwritingEnabled() &&
       (element_touch_action & TouchAction::kPan) == TouchAction::kPan &&
-      IsEditableElement(element, style) &&
+      IsEditableElement(element, builder) &&
       !IsPasswordFieldWithUnrevealedPassword(element)) {
     element_touch_action &= ~TouchAction::kInternalNotWritable;
   }
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.h b/third_party/blink/renderer/core/css/resolver/style_adjuster.h
index 089a292..0693a5d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.h
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.h
@@ -47,7 +47,7 @@
   static void AdjustStyleForTextCombine(ComputedStyleBuilder&);
 
  private:
-  static bool IsEditableElement(Element*, const ComputedStyle&);
+  static bool IsEditableElement(Element*, const ComputedStyleBuilder&);
   static bool IsPasswordFieldWithUnrevealedPassword(Element*);
   static void AdjustEffectiveTouchAction(ComputedStyle&,
                                          ComputedStyleBuilder&,
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 248df0e..68ddcc62 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -211,6 +211,11 @@
   // propogates renderer loading behavior to the browser process for histograms.
   virtual void DidObserveLoadingBehavior(LoadingBehaviorFlag) {}
 
+  // Will be called when a sub resource load happens.
+  virtual void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) {}
+
   // Will be called when a new UseCounterFeature has been observed in a frame.
   // This propagates feature usage to the browser process for histograms.
   virtual void DidObserveNewFeatureUsage(const UseCounterFeature&) {}
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 860023bd..b2f8a26a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -740,6 +740,16 @@
     web_frame_->Client()->DidObserveLoadingBehavior(behavior);
 }
 
+void LocalFrameClientImpl::DidObserveSubresourceLoad(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  if (web_frame_->Client()) {
+    web_frame_->Client()->DidObserveSubresourceLoad(
+        number_of_subresources_loaded,
+        number_of_subresource_loads_handled_by_service_worker);
+  }
+}
+
 void LocalFrameClientImpl::DidObserveNewFeatureUsage(
     const UseCounterFeature& feature) {
   if (web_frame_->Client())
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index 8e634ec..c1d35e9 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -151,6 +151,9 @@
                                  UserInteractionType interaction_type) override;
   void DidChangeCpuTiming(base::TimeDelta) override;
   void DidObserveLoadingBehavior(LoadingBehaviorFlag) override;
+  void DidObserveSubresourceLoad(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) override;
   void DidObserveNewFeatureUsage(const UseCounterFeature&) override;
   void DidObserveSoftNavigation(uint32_t count) override;
   void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc b/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
index 45766fd..3fce465 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
@@ -20,6 +20,8 @@
 
 LayoutUnit LayoutBoxUtils::AvailableLogicalWidth(const LayoutBox& box,
                                                  const LayoutBlock* cb) {
+  // SVG <text> and <foreignObject> should not refer to its containing block.
+  DCHECK(!box.IsSVGChild());
   auto writing_mode = box.StyleRef().GetWritingMode();
   bool parallel_containing_block = IsParallelWritingMode(
       cb ? cb->StyleRef().GetWritingMode() : writing_mode, writing_mode);
@@ -45,6 +47,8 @@
 
 LayoutUnit LayoutBoxUtils::AvailableLogicalHeight(const LayoutBox& box,
                                                   const LayoutBlock* cb) {
+  // SVG <text> and <foreignObject> should not refer to its containing block.
+  DCHECK(!box.IsSVGChild());
   auto writing_mode = box.StyleRef().GetWritingMode();
   bool parallel_containing_block = IsParallelWritingMode(
       cb ? cb->StyleRef().GetWritingMode() : writing_mode, writing_mode);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index 629ccc9..d5361116 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -276,7 +276,8 @@
   }
 
   LayoutNGMixin<Base>::UpdateInFlowBlockLayout();
-  LayoutNGMixin<Base>::UpdateMargins();
+  if (!Base::IsSVGChild())
+    LayoutNGMixin<Base>::UpdateMargins();
 }
 
 template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 0e6b76bb..09c5807 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -44,7 +44,9 @@
   LogicalSize available_size;
   bool is_fixed_inline_size = false;
   bool is_fixed_block_size = false;
-  if (cb) {
+  if (block.IsSVGChild()) {
+    // SVG <text> and <foreignObject> should not refer to its containing block.
+  } else if (cb) {
     available_size.inline_size =
         LayoutBoxUtils::AvailableLogicalWidth(block, cb);
     available_size.block_size =
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 2aec75c..c214ea01d 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -2697,6 +2697,11 @@
           loading_behavior |
           kLoadingBehaviorServiceWorkerFetchHandlerSkippable);
     }
+    if (!response_.WasFetchedViaServiceWorker()) {
+      loading_behavior = static_cast<LoadingBehaviorFlag>(
+          loading_behavior |
+          kLoadingBehaviorServiceWorkerMainResourceFetchFallback);
+    }
     GetLocalFrameClient().DidObserveLoadingBehavior(loading_behavior);
   }
 
@@ -3207,6 +3212,14 @@
   GetDisableCodeCacheForTesting() = true;
 }
 
+void DocumentLoader::UpdateSubresourceLoadMetrics(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  GetLocalFrameClient().DidObserveSubresourceLoad(
+      number_of_subresources_loaded,
+      number_of_subresource_loads_handled_by_service_worker);
+}
+
 DEFINE_WEAK_IDENTIFIER_MAP(DocumentLoader)
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index 9e53223a..01e862c 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -452,6 +452,10 @@
     return navigation_delivery_type_;
   }
 
+  void UpdateSubresourceLoadMetrics(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker);
+
  protected:
   // Based on its MIME type, if the main document's response corresponds to an
   // MHTML archive, then every resources will be loaded from this archive.
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 5dee8a50..978d792 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -888,4 +888,12 @@
   return probe::ToCoreProbeSink(GetFrame()->GetDocument());
 }
 
+void FrameFetchContext::UpdateSubresourceLoadMetrics(
+    uint32_t number_of_subresources_loaded,
+    uint32_t number_of_subresource_loads_handled_by_service_worker) {
+  document_loader_->UpdateSubresourceLoadMetrics(
+      number_of_subresources_loaded,
+      number_of_subresource_loads_handled_by_service_worker);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 15209ba..df474419 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -138,6 +138,10 @@
 
   ExecutionContext* GetExecutionContext() const override;
 
+  void UpdateSubresourceLoadMetrics(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) override;
+
  private:
   friend class FrameFetchContextTest;
 
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index be64f48..6ab95da1 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2592,6 +2592,12 @@
   STACK_ALLOCATED();
 
  public:
+  friend class ColorPropertyFunctions;
+  friend class StyleAdjuster;
+  friend class StyleResolverState;
+  // Access to UserModify().
+  friend class MatchedPropertiesCache;
+
   explicit ComputedStyleBuilder(const ComputedStyle& style) {
     SetStyle(ComputedStyle::Clone(style));
   }
@@ -3087,10 +3093,6 @@
   }
 
  private:
-  friend class ColorPropertyFunctions;
-  friend class StyleAdjuster;
-  friend class StyleResolverState;
-
   ComputedStyleBuilder() = default;
 
   CORE_EXPORT void ClearVariableNamesCache();
diff --git a/third_party/blink/renderer/platform/graphics/color_space_gamut.cc b/third_party/blink/renderer/platform/graphics/color_space_gamut.cc
index 6413935..37c9a43a 100644
--- a/third_party/blink/renderer/platform/graphics/color_space_gamut.cc
+++ b/third_party/blink/renderer/platform/graphics/color_space_gamut.cc
@@ -18,10 +18,10 @@
   if (!color_space.IsValid())
     return ColorSpaceGamut::kUnknown;
 
-  // TODO(crbug.com/1049334): Change this function to operate on a
-  // gfx::DisplayColorSpaces structure.
+  // TODO(crbug.com/1385853): Perform a better computation, using the available
+  // SkColorSpacePrimaries.
   if (color_space.IsHDR())
-    return ColorSpaceGamut::BT2020;
+    return ColorSpaceGamut::P3;
 
   sk_sp<SkColorSpace> sk_color_space = color_space.ToSkColorSpace();
   if (!sk_color_space)
diff --git a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc
index 5c793ee..fb3ce1b 100644
--- a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc
@@ -158,7 +158,8 @@
     // Frame already complete
     return;
   }
-  if ((index < num_decoded_frames_) && dec_) {
+  if ((index < num_decoded_frames_) && dec_ &&
+      frame_buffer_cache_[index].GetStatus() != ImageFrame::kFramePartial) {
     // An animation frame that already has been decoded, but does not have
     // status ImageFrame::kFrameComplete, was requested.
     // This can mean two things:
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index 36d1127..b0b9afb0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -176,6 +176,11 @@
 
   // Returns if the request context is for prerendering or not.
   virtual bool IsPrerendering() const { return false; }
+
+  // Update SubresourceLoad metrics.
+  virtual void UpdateSubresourceLoadMetrics(
+      uint32_t number_of_subresources_loaded,
+      uint32_t number_of_subresource_loads_handled_by_service_worker) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 56c0d8f6..b1d12e1 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1966,6 +1966,17 @@
                                          bool should_report_corb_blocking) {
   DCHECK(resource);
 
+  // kRaw might not be subresource, and we do not need them.
+  if (resource->GetType() != ResourceType::kRaw) {
+    ++number_of_subresources_loaded_;
+    if (resource->GetResponse().WasFetchedViaServiceWorker()) {
+      ++number_of_subresource_loads_handled_by_service_worker_;
+    }
+  }
+  context_->UpdateSubresourceLoadMetrics(
+      number_of_subresources_loaded_,
+      number_of_subresource_loads_handled_by_service_worker_);
+
   DCHECK_LE(inflight_keepalive_bytes, inflight_keepalive_bytes_);
   inflight_keepalive_bytes_ -= inflight_keepalive_bytes;
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index e4c1e23..d8271ea 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -521,6 +521,12 @@
 
   std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_;
 
+  // The total number of sub resource loads except for ResourceType::kRaw.
+  uint32_t number_of_subresources_loaded_ = 0;
+  // The number of sub resource loads that a service worker fetch handler
+  // called respondWith. i.e. no fallback to network.
+  uint32_t number_of_subresource_loads_handled_by_service_worker_ = 0;
+
   // NOTE: This must be the last member.
   base::WeakPtrFactory<ResourceFetcher> weak_ptr_factory_{this};
 };
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index ebf233cb..61f7abb3 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -368,7 +368,7 @@
       status: "experimental",
       origin_trial_feature_name: "BackForwardCacheNotRestoredReasons",
       base_feature: "BackForwardCacheSendNotRestoredReasons",
-      base_feature_status: "enabled",
+      base_feature_status: "disabled",
       copied_from_base_feature_if: "overridden",
       public: true,
     },
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index c495002..2d6e58b 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -214,7 +214,6 @@
 crbug.com/1243943 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-blending-gradient-over-gradient.html [ Slow ]
 crbug.com/1243943 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-transforms.html [ Slow ]
 crbug.com/1243943 [ Mac ] virtual/oopr-canvas2d/fast/canvas/canvas-composite-canvas.html [ Slow ]
-crbug.com/1243943 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-fill-style.html [ Slow ]
 crbug.com/1312081 [ Mac ] virtual/gpu/fast/canvas/canvas-blend-solid.html [ Slow ]
 crbug.com/1312081 [ Linux ] virtual/gpu/fast/canvas/canvas-blend-solid.html [ Slow ]
 
@@ -757,7 +756,6 @@
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/idbtransaction_objectStoreNames.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/keygenerator-explicit.html [ Slow ]
 crbug.com/1195814 [ Mac11 ] external/wpt/IndexedDB/keypath-special-identifiers.htm [ Slow ]
-crbug.com/1195814 [ Mac11 ] storage/indexeddb/key-generator.html [ Slow ]
 
 crbug.com/1263580 editing/deleting/delete-many-lines-of-text.html [ Slow ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index b92fbe5..7c59426 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -211,6 +211,9 @@
 
 # ====== Popover and Anchor Positioning failures to here ======
 
+# Disabled to revert devtools-frontend change:
+crbug.com/1383296 http/tests/devtools/elements/elements-tab-stops.js [ Failure Pass ]
+
 # Sheriff on 2020-09-03
 crbug.com/1124352 media/picture-in-picture/clear-after-request.html [ Crash Pass ]
 crbug.com/1124352 media/picture-in-picture/controls/picture-in-picture-button.html [ Crash Pass ]
@@ -313,7 +316,6 @@
 external/wpt/editing/run/inserttext.html?2001-last [ Failure ]
 external/wpt/editing/run/forecolor.html?1-1000 [ Failure ]
 external/wpt/editing/run/forecolor.html?2001-last [ Failure ]
-external/wpt/editing/run/insertlinebreak.html [ Failure ]
 
 # WPT editing test failures
 crbug.com/1168974 external/wpt/editing/run/forwarddelete.html?6001-last [ Failure ]
@@ -1965,7 +1967,6 @@
 
 # Flaky tests on Mac after enabling scroll animations in web_tests
 crbug.com/944583 [ Mac ] fast/events/platform-wheelevent-paging-xy-in-scrolling-div.html [ Failure Pass ]
-crbug.com/944583 [ Mac ] fast/events/platform-wheelevent-paging-xy-in-scrolling-page.html [ Failure Pass ]
 crbug.com/944583 [ Mac ] fast/events/space-scroll-textinput-canceled.html [ Failure Pass ]
 crbug.com/944583 [ Mac ] fast/scrolling/percentage-mousewheel-scroll-on-iframe.html [ Failure Pass ]
 crbug.com/944583 [ Mac ] fast/scrolling/percentage-mousewheel-scroll.html [ Failure Pass ]
@@ -3000,7 +3001,6 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-016.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-020.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-179.xht [ Failure ]
-crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-189.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-192.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-193.xht [ Failure ]
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-194.xht [ Failure ]
@@ -3221,7 +3221,6 @@
 crbug.com/626703 [ Mac10.14 ] external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html?pen [ Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html?pen [ Timeout ]
 crbug.com/626703 [ Win ] external/wpt/websockets/stream/tentative/constructor.any.serviceworker.html?wss [ Failure Timeout ]
-crbug.com/626703 [ Win ] external/wpt/websockets/constructor/010.html?wss [ Failure Timeout ]
 crbug.com/626703 [ Win ] external/wpt/websockets/opening-handshake/005.html [ Failure Timeout ]
 crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Skip Timeout ]
@@ -4439,8 +4438,6 @@
 crbug.com/1048149 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-screeny.html [ Crash Timeout ]
 crbug.com/1048149 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-width.html [ Crash Timeout ]
 crbug.com/1048149 [ Mac ] fast/forms/calendar-picker/month-picker-appearance.html [ Crash Pass ]
-crbug.com/1048149 [ Mac ] fast/forms/calendar-picker/month-picker-appearance-step.html [ Crash Pass ]
-crbug.com/1048149 crbug.com/1050121 [ Mac ] fast/forms/month/month-picker-appearance-zoom150.html [ Crash Failure Pass ]
 
 # SwANGLE issues
 crbug.com/1204234 css3/blending/background-blend-mode-single-accelerated-element.html [ Failure ]
@@ -5159,7 +5156,6 @@
 crbug.com/1048761 [ Mac12 ] external/wpt/websockets/Send-0byte-data.any.html?wpt_flags=h2 [ Failure ]
 crbug.com/1048761 [ Mac12-arm64 ] external/wpt/websockets/Send-0byte-data.any.html?wpt_flags=h2 [ Failure ]
 crbug.com/1048761 [ Win ] external/wpt/websockets/Send-0byte-data.any.html?wpt_flags=h2 [ Failure ]
-crbug.com/1048761 [ Win ] external/wpt/websockets/Send-0byte-data.any.worker.html?wpt_flags=h2 [ Failure ]
 crbug.com/1048761 [ Linux ] external/wpt/websockets/Send-65K-data.any.html?wpt_flags=h2 [ Failure ]
 crbug.com/1048761 [ Mac10.15 ] external/wpt/websockets/Send-65K-data.any.html?wpt_flags=h2 [ Failure ]
 crbug.com/1048761 [ Mac11 ] external/wpt/websockets/Send-65K-data.any.html?wpt_flags=h2 [ Failure ]
@@ -6925,3 +6921,8 @@
 crbug.com/1372166 fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html [ Failure Pass ]
 crbug.com/1385497 http/tests/inspector-protocol/tracing/page-load-metrics.js [ Failure Pass ]
 crbug.com/1349215 external/wpt/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html [ Skip Timeout ]
+
+# To be removed after cherry picking
+crbug.com/1386017 external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-bfcache-reasons-stay.window.html [ Failure Pass ]
+crbug.com/1386017 external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-cross-origin-bfcache.window.html [ Failure Pass ]
+crbug.com/1386017 external/wpt/performance-timeline/not-restored-reasons/performance-navigation-timing-not-bfcached.window.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 9e71efc..fa494ec 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -481,6 +481,12 @@
     "args": ["--enable-features=PlzDedicatedWorker"]
   },
   {
+    "prefix": "service-worker-storage-control-on-thread-pool",
+    "platforms": ["Linux", "Mac", "Win"],
+    "bases": ["external/wpt/service-workers/service-worker/fetch-event.https.html"],
+    "args": ["--enable-features=ServiceWorkerStorageControlOnThreadPool"]
+  },
+  {
     "prefix": "direct-sockets",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/direct-sockets",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 044d3bd..b0f78b4e 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -3556,13 +3556,6 @@
        null,
        {}
       ]
-     ],
-     "uncontained-transition-crash.html": [
-      "98632508aedc849999c760625f45ad2b54a829d0",
-      [
-       null,
-       {}
-      ]
      ]
     },
     "css-writing-modes": {
@@ -217161,7 +217154,7 @@
       ]
      ],
      "new-content-element-writing-modes.html": [
-      "4c2268ffc0de78dbd82a253443789ff3b50b5d52",
+      "0c50e22fc0dea2d2f1a4325895086f83ebeabafc",
       [
        null,
        [
@@ -217234,7 +217227,7 @@
       ]
      ],
      "new-content-object-fit-fill.html": [
-      "47c7f77cd0f31232c60041abd57e5db3e9237c02",
+      "5b1941aa3e6f7e6bce6b54ae4bcf823a76d581c7",
       [
        null,
        [
@@ -217267,7 +217260,7 @@
       ]
      ],
      "new-content-object-fit-none.html": [
-      "be477691013fd76c0959848372c4d4a03ac07149",
+      "d3e4d2dc3def3527de5fd10a3a2540c9a16ab64d",
       [
        null,
        [
@@ -217689,7 +217682,7 @@
       ]
      ],
      "old-content-object-fit-fill.html": [
-      "587c05c0cb189e03d6966f7f7ed0080a282434f5",
+      "75dc628f944d49e19c98a95e5fc03f57c2434a39",
       [
        null,
        [
@@ -217722,7 +217715,7 @@
       ]
      ],
      "old-content-object-fit-none.html": [
-      "71f3f5474876e533c297f08b454fe8a9635f4a42",
+      "c40ad13435a773cb48b3454705ea8955cdcadbee",
       [
        null,
        [
@@ -276223,6 +276216,10 @@
       "06f866c02dd04724a35cf5032b1d40e6783c3389",
       []
      ],
+     "nested-color-mix-with-currentcolor-expected.txt": [
+      "13c385b073f45c5648976704d28d8284392f8049",
+      []
+     ],
      "oklab-004-ref.html": [
       "d947445321da29d5658fb957cb45c83e8cca2424",
       []
@@ -352188,7 +352185,7 @@
       []
      ],
      "util.js": [
-      "d6f54bcfc7ebd16caf1414e828e3b7b8ecfc3f9e",
+      "1b3c82d7d68da9b2f94159db850d1951dadd33f6",
       []
      ]
     }
@@ -361581,7 +361578,7 @@
      []
     ],
     "META.yml": [
-     "b8c0b9741d4a22ac42a995ca04b3df2c96cfc16f",
+     "633c917b0e60783c41db597695e22c499080a95d",
      []
     ],
     "active-lock-expected.txt": [
@@ -417527,6 +417524,13 @@
        {}
       ]
      ],
+     "nested-color-mix-with-currentcolor.html": [
+      "a4dd687dd5814af2e4660586a2c97c09ba34ffe4",
+      [
+       null,
+       {}
+      ]
+     ],
      "parsing": {
       "color-computed-color-contrast-function.html": [
        "74be5ced3748dcaa9b86d99938390cd7de122de0",
@@ -441797,8 +441801,15 @@
      ]
     },
     "css-view-transitions": {
-     "duplicate_tag_rejects.html": [
-      "c7aef2aa1a45183a8ddfa5d0ca19647f3d81d838",
+     "duplicate-tag-rejects-capture.html": [
+      "517502b6741818d84e9faeb81a9ce69bb5c0b6cc",
+      [
+       null,
+       {}
+      ]
+     ],
+     "duplicate-tag-rejects-start.html": [
+      "2d99717df446b210fcc47f4992d980e0c8ce8e73",
       [
        null,
        {}
@@ -441834,6 +441845,27 @@
        {}
       ]
      ],
+     "no-containment-on-new-element-mid-transition.html": [
+      "869fd24f42c34740809aa075be96a73b6ee465ef",
+      [
+       null,
+       {}
+      ]
+     ],
+     "no-containment-on-new-element.html": [
+      "ecb05373b3e653686a3d724fc5418aa28ffb2979",
+      [
+       null,
+       {}
+      ]
+     ],
+     "no-containment-on-old-element.html": [
+      "22cad098c76c21b424fef72db5e4db2d8b8dbf7f",
+      [
+       null,
+       {}
+      ]
+     ],
      "no-crash-set-exception.html": [
       "035d050e4487b1443f518b425a0b6a301d83b093",
       [
@@ -441875,6 +441907,13 @@
        ]
       ]
      },
+     "pseudo-computed-style-stays-in-sync-with-new-element.html": [
+      "b1ed783b0af4875abb2d381986797059c054b192",
+      [
+       null,
+       {}
+      ]
+     ],
      "pseudo-get-computed-style.html": [
       "e837d52a5709eb71e80a1dfc5c0a35f6a17a14c4",
       [
@@ -441895,6 +441934,48 @@
        null,
        {}
       ]
+     ],
+     "synchronous-callback-skipped-before-run.html": [
+      "1bda243449c564134bf8fb1d1d93f7858460a533",
+      [
+       null,
+       {}
+      ]
+     ],
+     "transition-skipped-after-animation-started.html": [
+      "78f32def3e58b59a5568d2e25806d77ad8ee84a2",
+      [
+       null,
+       {}
+      ]
+     ],
+     "transition-skipped-from-invalid-callback.html": [
+      "4a56f81efe0f9c8512db85230b7da6713be33223",
+      [
+       null,
+       {}
+      ]
+     ],
+     "unset-and-initial-view-transition-name.html": [
+      "93c8eb64d79ac8c24995a8a54442d71b31ae6fe6",
+      [
+       null,
+       {}
+      ]
+     ],
+     "view-transition-name-on-added-element.html": [
+      "cd957973b7d9a9c67574c5ced363cf4e18e4eaa3",
+      [
+       null,
+       {}
+      ]
+     ],
+     "view-transition-name-on-removed-element.html": [
+      "4a26a8154f5dbaa407eec0a074cf8f56bb53c94e",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "css-will-change": {
@@ -538419,7 +538500,7 @@
      ]
     ],
     "simple-block-movement.html": [
-     "837b438ef6b87e177c65ebbcd381d378d372ba24",
+     "10261f7d81d0f04eedc4fa1f7998bcf09d866d2a",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html
index 099ac511..3b1606b 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html
@@ -7,6 +7,8 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  await test_driver.delete_all_cookies();
+  t.add_cleanup(test_driver.delete_all_cookies);
   document.cookie = "test0=0";
   const cookies = await test_driver.get_all_cookies();
   assert_equals(cookies.length, 1);
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html.ini b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html.ini
deleted file mode 100644
index 6219d6e..0000000
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[get_all_cookies-default-samesite.html]
-  [Get all cookies w/ default SameSite]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html
index 405473c..2ee5d0f 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html
@@ -7,6 +7,8 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  await test_driver.delete_all_cookies();
+  t.add_cleanup(test_driver.delete_all_cookies);
   document.cookie = "test0=0";
   const cookie = await test_driver.get_named_cookie("test0");
   assert_equals(cookie["name"], "test0");
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html.ini b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html.ini
deleted file mode 100644
index a08ca555..0000000
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[get_named_cookie-default-samesite.html]
-  [Get Named cookie  w/ default SameSite]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002-expected.txt
new file mode 100644
index 0000000..3b126fc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL #inner color change to red triggers a step transition starting at green assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002.html
new file mode 100644
index 0000000..dc92970
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/transition-style-change-event-002.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Container Queries - Style Change Event for transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/cq-testcommon.js"></script>
+<style>
+  .container {
+    container-type: inline-size;
+  }
+  #outer {
+    width: 100px;
+    color: green;
+  }
+  #target {
+    transition: color 100s step-end;
+  }
+
+  @container (min-width: 200px) {
+    #inner { color: red; }
+  }
+  @container (min-width: 200px) {
+    #target {
+      /* This rule exists just to have a container query dependency between
+         target and #inner */
+      background-color: orange;
+    }
+  }
+</style>
+<div id="outer" class="container">
+  <div id="inner" class="container">
+    <div id="target">Green</div>
+  </div>
+</div>
+<script>
+  setup(() => assert_implements_container_queries());
+
+  test(() => {
+    outer.offsetTop;
+    outer.style.width = "200px";
+    assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)");
+  }, "#inner color change to red triggers a step transition starting at green");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
index a145e52..84f93af0 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
@@ -7,6 +7,7 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  t.add_cleanup(test_driver.delete_all_cookies);
   const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
   document.cookie = "test0=0";
   document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
index e3402780..e941671 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
@@ -7,6 +7,7 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  t.add_cleanup(test_driver.delete_all_cookies);
   const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
   document.cookie = "test0=0";
   document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
index 3cbc784..28950e2 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
@@ -7,6 +7,7 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  t.add_cleanup(test_driver.delete_all_cookies);
   const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
   document.cookie = "test0=0";
   document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
index d0d8612a..8e8f4433 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
@@ -7,6 +7,7 @@
 <script src="/resources/testdriver-vendor.js"></script>
 <script>
 promise_test(async t => {
+  t.add_cleanup(test_driver.delete_all_cookies);
   const kTenDaysFromNow = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000);
   document.cookie = "test0=0";
   document.cookie = `test1=1; Expires=${kTenDaysFromNow.toUTCString()}`;
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/parallel-capture-requests.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/parallel-capture-requests.https.html
index 01b7f32..301515d 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/parallel-capture-requests.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/parallel-capture-requests.https.html
@@ -4,38 +4,52 @@
 <title>Parallel capture requests</title>
 </head>
 <body>
+<button id="button">User gesture</button>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
 <script>
+async function getDisplayMedia(constraints) {
+  const p = new Promise(r => button.onclick = r);
+  await test_driver.click(button);
+  await p;
+  return navigator.mediaDevices.getDisplayMedia(constraints);
+}
+
 promise_test(function() {
   const getUserMediaPromise =
         navigator.mediaDevices.getUserMedia({audio: true, video:true});
   const getDisplayMediaPromise =
-        navigator.mediaDevices.getDisplayMedia({video: true, audio: true});
+        getDisplayMedia({video: true, audio: true});
   return Promise.all([getUserMediaPromise, getDisplayMediaPromise])
       .then(function(s) {
-        assert_equals(s[0].getTracks().length, 2);
-        assert_equals(s[0].getAudioTracks().length, 1);
+        assert_greater_than_equal(s[0].getTracks().length, 1);
+        assert_less_than_equal(s[0].getTracks().length, 2);
         assert_equals(s[0].getVideoTracks().length, 1);
-        assert_equals(s[1].getTracks().length, 2);
-        assert_equals(s[1].getAudioTracks().length, 1);
+        assert_less_than_equal(s[0].getAudioTracks().length, 1);
+        assert_greater_than_equal(s[1].getTracks().length, 1);
+        assert_less_than_equal(s[1].getTracks().length, 2);
         assert_equals(s[1].getVideoTracks().length, 1);
+        assert_less_than_equal(s[1].getAudioTracks().length, 1);
       });
 }, 'getDisplayMedia() and parallel getUserMedia()');
 
 promise_test(function() {
   const getDisplayMediaPromise =
-        navigator.mediaDevices.getDisplayMedia({video: true, audio: true});
+        getDisplayMedia({video: true, audio: true});
   const getUserMediaPromise =
         navigator.mediaDevices.getUserMedia({audio: true, video:true});
   return Promise.all([getDisplayMediaPromise, getUserMediaPromise])
       .then(function(s) {
-        assert_equals(s[0].getTracks().length, 2);
-        assert_equals(s[0].getAudioTracks().length, 1);
+        assert_greater_than_equal(s[0].getTracks().length, 1);
+        assert_less_than_equal(s[0].getTracks().length, 2);
         assert_equals(s[0].getVideoTracks().length, 1);
-        assert_equals(s[1].getTracks().length, 2);
-        assert_equals(s[1].getAudioTracks().length, 1);
+        assert_less_than_equal(s[0].getAudioTracks().length, 1);
+        assert_greater_than_equal(s[1].getTracks().length, 1);
+        assert_less_than_equal(s[1].getTracks().length, 2);
         assert_equals(s[1].getVideoTracks().length, 1);
+        assert_less_than_equal(s[1].getAudioTracks().length, 1);
       });
 }, 'getUserMedia() and parallel getDisplayMedia()');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
index b8c0b97..633c917b0 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
@@ -3,3 +3,4 @@
   - marcoscaceres
   - cdumez
   - michaelwasserman
+  - makotokato
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale-change-repaint.html b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale-change-repaint.html
index bd2773b59..aa3939c1 100644
--- a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale-change-repaint.html
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale-change-repaint.html
@@ -1,16 +1,14 @@
 <!doctype HTML>
-<head>
-  <meta charset="utf-8">
-  <title>Testcase for changing currentScale on SVG embedded in HTML</title>
-  <link rel="help" href="https://www.w3.org/TR/SVG/struct.html#__svg__SVGSVGElement__currentScale">
-  <link rel="match" href="reference/green-100x100.svg"/>
-  <script>
-    function go() {
-      var mySVG = document.getElementById("mySVG");
-      mySVG.currentScale = 0.5;
-    }
-  </script>
-</head>
+<meta charset="utf-8">
+<title>Testcase for changing currentScale on SVG embedded in HTML</title>
+<link rel="help" href="https://www.w3.org/TR/SVG/struct.html#__svg__SVGSVGElement__currentScale">
+<link rel="match" href="reference/green-100x100.html">
+<script>
+  function go() {
+    const mySVG = document.getElementById("mySVG");
+    mySVG.currentScale = 0.5;
+  }
+</script>
 <body onload="go()">
   <svg id="mySVG">
     <rect width="100" height="100" fill="green"></rect>
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale.svg b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale.svg
new file mode 100644
index 0000000..926117b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/currentScale.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml" onload="scaleDown()">
+  <title>Testcase for changing currentScale on SVG embedded in HTML</title>
+  <h:link rel="help" href="https://www.w3.org/TR/SVG/struct.html#__svg__SVGSVGElement__currentScale"/>
+  <h:link rel="match" href="reference/green-100x100.svg"/>
+  <script>
+    function scaleDown() {
+      document.documentElement.currentScale = 0.5;
+    }
+  </script>
+  <rect width="200" height="200" fill="green"/>
+</svg>
diff --git a/third_party/blink/web_tests/virtual/service-worker-storage-control-on-thread-pool/README.md b/third_party/blink/web_tests/virtual/service-worker-storage-control-on-thread-pool/README.md
new file mode 100644
index 0000000..24be641
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/service-worker-storage-control-on-thread-pool/README.md
@@ -0,0 +1 @@
+This directory is for testing ServiceWorkerStorageControlOnThreadPool (https://crbug.com/1375174).
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 9bd4eb9..1410e0e 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1030,7 +1030,7 @@
       'ios-angle-try-intel': 'angle_deqp_release_trybot_ios',
       'linux-angle-chromium-try': 'gpu_tests_release_trybot_reclient',
       'mac-angle-chromium-try': 'gpu_tests_release_trybot',
-      'win-angle-chromium-x64-try': 'gpu_tests_release_trybot',
+      'win-angle-chromium-x64-try': 'gpu_tests_release_trybot_reclient',
       'win-angle-chromium-x86-try': 'gpu_tests_release_trybot_x86',
     },
 
@@ -1292,7 +1292,7 @@
       'win-swangle-try-tot-swiftshader-x64': 'angle_deqp_release_trybot',
       'win-swangle-try-tot-swiftshader-x86': 'angle_deqp_release_trybot_x86',
       'win-swangle-try-x64': 'angle_deqp_release_trybot',
-      'win-swangle-try-x86': 'angle_deqp_release_trybot_x86',
+      'win-swangle-try-x86': 'angle_deqp_release_trybot_x86_reclient',
     },
 
     'tryserver.chromium.tricium': {
@@ -1791,6 +1791,10 @@
       'angle_deqp_tests', 'shared_release_trybot', 'x86',
     ],
 
+    'angle_deqp_release_trybot_x86_reclient': [
+      'angle_deqp_tests', 'shared_release_trybot_reclient', 'x86',
+    ],
+
     'asan_clang_fuzzer_static_v8_heap_minimal_symbols_release_reclient': [
       'asan', 'fuzzer', 'static', 'v8_heap', 'minimal_symbols', 'release_bot_reclient',
     ],
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json
index 9876678..d2fbe36 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json
@@ -71,7 +71,7 @@
       "is_debug": false,
       "proprietary_codecs": true,
       "symbol_level": 0,
-      "use_goma": true
+      "use_remoteexec": true
     }
   },
   "win-angle-chromium-x86-try": {
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
index 36ea9fc4..b08613706 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
@@ -93,7 +93,7 @@
       "is_debug": false,
       "symbol_level": 0,
       "target_cpu": "x86",
-      "use_goma": true
+      "use_remoteexec": true
     }
   }
 }
\ No newline at end of file
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 7901c6c3..4418e97 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -54149,6 +54149,19 @@
   <int value="2" label="Subresource"/>
 </enum>
 
+<enum name="IsolatedWebAppReadIntegrityBlockAndMetadataStatus">
+  <int value="0" label="Success"/>
+  <int value="1" label="Error: Integrity Block parsing: Internal error"/>
+  <int value="2" label="Error: Integrity Block parsing: Format error"/>
+  <int value="3" label="Error: Integrity Block parsing: Version error"/>
+  <int value="4" label="Error: Integrity Block validation error"/>
+  <int value="5" label="Error: Signature verification error"/>
+  <int value="6" label="Error: Metadata parsing: Internal error"/>
+  <int value="7" label="Error: Metadata parsing: Format error"/>
+  <int value="8" label="Error: Metadata parsing: Version error"/>
+  <int value="9" label="Error: Metadata validation error"/>
+</enum>
+
 <enum name="IsolatedWebAppResponseReaderCacheState">
   <int value="0" label="Not cached"/>
   <int value="1" label="Cached and ready"/>
@@ -91817,6 +91830,31 @@
   <int value="1" label="Received on uninstalled service worker."/>
 </enum>
 
+<enum name="ServiceWorkerResourceLoadStatus">
+  <int value="0"
+      label="falled back for loading both main resource and sub resource."/>
+  <int value="1"
+      label="falled back for loading main resource, but did not fallback for
+             sub resource."/>
+  <int value="2"
+      label="falled back for loading main resource, and some sub resource
+             fallbacks and the others are not."/>
+  <int value="3"
+      label="falled back for loading main resource, and no sub resource are
+             loaded."/>
+  <int value="4"
+      label="not falled back for loading main resource, but falled back for
+             sub resource."/>
+  <int value="5"
+      label="not falled back for both main resource and sub resource."/>
+  <int value="6"
+      label="not falled back for main resource, but sub resource has both
+             fallback case and non-fallback cases."/>
+  <int value="7"
+      label="not falled back for main resource, and no sub resource are
+             loaded."/>
+</enum>
+
 <enum name="ServiceWorkerResponseError">
   <obsolete>
     No longer recorded since NetS13nSW shipped on Dec 2018.
@@ -93826,6 +93864,12 @@
   <int value="21" label="User clicked signout from clear browsing data page">
     User clicked sign-out in the clear browsing data page.
   </int>
+  <int value="22" label="AccountReconcilor GaiaCookiesUpdated">
+    The reconcilor cleared the signin primary account on a Gaia cookie update.
+  </int>
+  <int value="23" label="AccountReconcilor Reconcile">
+    The reconcilor cleared the signin primary account during reconcilation.
+  </int>
 </enum>
 
 <enum name="SigninSource">
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 09dcca6..0e9660b 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -3019,7 +3019,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileImport.SilentUpdatesProfileImportType"
-    enum="AutofillSilentUpdatesProfileImportType" expires_after="M110">
+    enum="AutofillSilentUpdatesProfileImportType" expires_after="2023-04-30">
   <owner>koerber@google.com</owner>
   <owner>src/components/autofill/OWNERS</owner>
   <summary>
@@ -3045,7 +3045,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileImport.UpdateProfileAffectedType.{Decision}"
-    enum="AutofillSettingsVisibleTypes" expires_after="M110">
+    enum="AutofillSettingsVisibleTypes" expires_after="2023-04-30">
   <owner>koerber@google.com</owner>
   <owner>src/components/autofill/OWNERS</owner>
   <summary>
@@ -3126,7 +3126,7 @@
 
 <histogram
     name="Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields.{Decision}"
-    units="fields" expires_after="M110">
+    units="fields" expires_after="2023-04-30">
   <owner>koerber@google.com</owner>
   <owner>src/components/autofill/OWNERS</owner>
   <summary>
@@ -3225,7 +3225,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileSuggestionsMadeWithFormatter"
-    enum="BooleanCreated" expires_after="M110">
+    enum="BooleanCreated" expires_after="2023-04-30">
   <owner>battre@chromium.org</owner>
   <owner>src/components/autofill/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 8e8b412..0de8887 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -2425,8 +2425,8 @@
 
 <histogram name="PasswordManager.PasswordStore.OnLoginsChanged" enum="Boolean"
     expires_after="2023-03-19">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Recorded whenever PasswordStore notifies consumers about changes to logins.
     Changes can be made locally (in settings, in bubbles etc.) or remotely (via
@@ -2436,8 +2436,8 @@
 
 <histogram name="PasswordManager.PasswordStore.OnLoginsRetained"
     enum="LoginsChangedTrigger" expires_after="2023-03-19">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Android only. |OnLoginsRetained| replaces |OnLoginsChanged| and this metric
     records potential calls of |OnLoginsRetained| to measure differences in
@@ -2478,9 +2478,9 @@
 <histogram
     name="PasswordManager.PasswordStore.WasEnrolledInUPMWhenBackendWasCreated"
     enum="Boolean" expires_after="2023-03-19">
-  <owner>fhorschig@chromium.org</owner>
   <owner>kazinova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Recorded on Android when the password store backend is created. This happens
     on startup and once per profile. It logs whether the user is enrolled in
@@ -2510,8 +2510,8 @@
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend.ClearAllLocalPasswords.LoginsToRemove"
     units="count" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Total number of logins to be removed by ClearAllLocalPasswords.
   </summary>
@@ -2520,8 +2520,8 @@
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend.ClearAllLocalPasswords.SuccessRate"
     units="%" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Ratio between successfully removed logins and total number of logins in the
     GMS's local storage. Removal is considered successful when change list is
@@ -2617,8 +2617,10 @@
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend{Function}.APIError"
     enum="PasswordStoreAndroidBackendAPIError" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     The error codes returned by the GMS Core ChromeSync 1P API{Function}.
     Recorded when the asynchronous job has returned.
@@ -2660,8 +2662,10 @@
 <histogram
     name="PasswordManager.PasswordStoreAndroidBackend{Function}.ErrorCode"
     enum="PasswordStoreAndroidBackendError" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     This metric reports the error observed when {Function} the PasswordStore
     Android backend. Recorded when the asynchronous job has returned.
@@ -2736,8 +2740,10 @@
 <histogram
     name="PasswordManager.PasswordStoreProxyBackend.{Function}.{Metric}.{Measurement}"
     units="count" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records the number of logins {Metric}{Measurement} Recorded when the
     asynchronous job for {Function} has returned.
@@ -2773,8 +2779,10 @@
 <histogram
     name="PasswordManager.PasswordStoreProxyBackend.{ModifyingFunction}.{Metric}.{Measurement}"
     units="count" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records the number of password store changes {Metric}{Measurement} Recorded
     when the asynchronous job for {ModifyingFunction} has returned. Recorded
@@ -2812,8 +2820,10 @@
 
 <histogram name="PasswordManager.PasswordStore{Backend}{Function}"
     enum="PasswordStoreAndroidBackendRequestStatus" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records each {Function} call by the PasswordStore {Backend}. Recorded twice:
     1) when the store issues the request, and 2) as the asynchronous job has
@@ -2847,8 +2857,10 @@
 
 <histogram name="PasswordManager.PasswordStore{Backend}{Function}.Latency"
     units="ms" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Real-time duration of the asynchronous call to {Function} the PasswordStore
     {Backend}. Recorded when the asynchronous job has returned.
@@ -2882,8 +2894,10 @@
 
 <histogram name="PasswordManager.PasswordStore{Backend}{Function}.Success"
     enum="BooleanSuccess" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
+  <owner>maxan@chromium.org</owner>
+  <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records whether {Function} the PasswordStore {Backend}. Recorded when the
     asynchronous job has returned. False is emitted if an error occurs;
@@ -3509,9 +3523,9 @@
 
 <histogram name="PasswordManager.UnenrolledFromUPMDueToErrors" enum="Boolean"
     expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>kazinova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records true when a client's profile is being unenrolled from UPM. This
     happens when a password store request to GMS Core fails with an error that
@@ -3525,9 +3539,9 @@
     Obsolete in M110 after PasswordStore is no longer created for non-regular,
     guest, system and incognito profiles.
   </obsolete>
-  <owner>fhorschig@chromium.org</owner>
   <owner>kazinova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Recorded on profile open after the sync service is initialized and once per
     profile. It is recorded for clients that have UPM enabled and logs whether
@@ -3541,9 +3555,9 @@
 
 <histogram name="PasswordManager.UnifiedPasswordManager.ActiveStatus2"
     enum="UnifiedPasswordManagerActiveStatus" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>kazinova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Recorded on profile open after the sync service is initialized and once per
     regular profile. It is recorded for clients that have UPM enabled and logs
@@ -3557,8 +3571,8 @@
 
 <histogram name="PasswordManager.UnifiedPasswordManager.WasMigrationDone"
     enum="BooleanSuccess" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records whether passwords were successfully migrated from built in backed to
     android backed and the current migration version stored in pref is
@@ -3569,8 +3583,8 @@
 <histogram
     name="PasswordManager.UnifiedPasswordManager.{UPMMigrationType}.Latency"
     units="ms" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Real-time duration of {UPMMigrationType}. Recorded when all operations are
     completed and migration is finished.
@@ -3581,8 +3595,8 @@
 <histogram
     name="PasswordManager.UnifiedPasswordManager.{UPMMigrationType}.Success"
     enum="BooleanSuccess" expires_after="M114">
-  <owner>fhorschig@chromium.org</owner>
   <owner>vsemeniuk@google.com</owner>
+  <owner>fhorschig@chromium.org</owner>
   <summary>
     Records success of {UPMMigrationType}. Recorded when the migration is
     finished.
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml
index 432390f7..f9c5e24 100644
--- a/tools/metrics/histograms/metadata/webapps/histograms.xml
+++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -755,6 +755,23 @@
   <summary>Records the result code of Web App installs.</summary>
 </histogram>
 
+<histogram name="WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus"
+    enum="IsolatedWebAppReadIntegrityBlockAndMetadataStatus"
+    expires_after="2023-11-08">
+  <owner>cmfcmf@chromium.org</owner>
+  <owner>peletskyi@chromium.org</owner>
+  <summary>
+    Records whether reading integrity block and metadata from a Signed Web
+    Bundle via the isolated-app: scheme was successful or resulted in an error.
+    This is logged every time the integrity block and metadata of an Isolated
+    Web App are parsed, which happens whenever the reader for an Isolated Web
+    App is not yet cached. Readers are evicted from the cache after
+    approximately 10 minutes of not reading any responses from their
+    corresponding Signed Web Bundle. Isolated Web Apps are parsed for any
+    resources loading for the web app, so any usage could trigger this UMA.
+  </summary>
+</histogram>
+
 <histogram name="WebApp.Isolated.ResponseReaderCacheState"
     enum="IsolatedWebAppResponseReaderCacheState" expires_after="2023-11-08">
   <owner>cmfcmf@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index deb06e4..9ac7aff 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -19583,6 +19583,40 @@
   </metric>
 </event>
 
+<event name="ServiceWorker.OnLoad">
+  <owner>yyanagisawa@chromium.org</owner>
+  <owner>chrome-worker@google.com</owner>
+  <summary>
+    Events taken at the end of the loading pages controlled by the service
+    workers.
+  </summary>
+  <metric name="MainAndSubResourceLoadLocation"
+      enum="ServiceWorkerResourceLoadStatus">
+    <summary>
+      Enum value to represent how main / sub resource are loaded.
+    </summary>
+  </metric>
+  <metric name="SubResourceFallbackRatio">
+    <summary>
+      An integer ratio (0 - 100) to represent the ratio of network fallbacks
+      from the total subresource load.
+    </summary>
+  </metric>
+  <metric name="TotalSubResourceFallback">
+    <summary>
+      The number of network fallbacks during sub resource load. This is rounded
+      down to the nearest exponential bucket (with a bucket ratio on 1.15).
+    </summary>
+  </metric>
+  <metric name="TotalSubResourceLoad">
+    <summary>
+      The number of all sub resource load of the page controlled by the service
+      worker. This is rounded down to the nearest exponential bucket (with a
+      bucket ratio on 1.15).
+    </summary>
+  </metric>
+</event>
+
 <event name="SharedHighlights.LinkGenerated">
   <owner>jeffreycohen@chromium.org</owner>
   <owner>chrome-creation@google.com</owner>
diff --git a/tools/perf/contrib/power/cpu_powerups.sql b/tools/perf/contrib/power/cpu_powerups.sql
index a6705f5..5b00b15 100644
--- a/tools/perf/contrib/power/cpu_powerups.sql
+++ b/tools/perf/contrib/power/cpu_powerups.sql
@@ -123,6 +123,24 @@
                             -- per CPU power up.
   ORDER BY ts ASC;
 
+-- A view with counts of power-ups grouped by Linux process & thread.
+--
+-- Schema:
+--   process_name   : The Linux process that ran after a power up.
+--   thread_name    : The thread in the Linux process that powered up.
+--   powerup_count  : The counts for the (process, thread) pair.
+DROP VIEW IF EXISTS cpu_power_powerup_count_by_process_and_thread;
+CREATE VIEW cpu_power_powerup_count_by_process_and_thread AS
+  SELECT
+    process.name AS process_name,
+    thread.name AS thread_name,
+    count() AS powerup_count
+  FROM cpu_power_first_sched_slice_after_powerup
+  JOIN thread using (utid)
+  JOIN process using (upid)
+  GROUP BY process_name, thread_name
+  ORDER BY powerup_count DESC;
+
 -- A view joining thread tracks and top-level slices.
 --
 -- This view is intended to be intersected by time with the scheduler
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index f6fc2b6..6cb3cb6b 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "bb2cc045bbee68ad3cd3daed827075285572fe49",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/3c036ab6b21b9d9ddf91dc6b7fe7f50142f28758/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/6f7678ba37a925e02df652a13c50be9daaeb484e/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "7e4cc10d0a4b47b170771988b6800e9438ad73cf",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6f7678ba37a925e02df652a13c50be9daaeb484e/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6c5c80b3c694219abfaa0a1fe814522e70c0dc65/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/tbmv3/metrics/power_rails_metric.sql b/tools/perf/core/tbmv3/metrics/power_rails_metric.sql
index 161d6e3..0b2eb11 100644
--- a/tools/perf/core/tbmv3/metrics/power_rails_metric.sql
+++ b/tools/perf/core/tbmv3/metrics/power_rails_metric.sql
@@ -16,14 +16,22 @@
 
 -- Compute cumulative power drain over the duration of the run_story event.
 CREATE VIEW story_drain AS
-SELECT
-    subsystem,
-    sum(dur * drain_w / 1e9) as drain_j,
-    sum(dur / 1e6) as dur_ms
-FROM run_story_span_join_drain
-JOIN power_counters USING (name)
+WITH
+  drain_per_rail AS (
+    SELECT
+      name,
+      sum(dur * drain_w / 1e9) AS drain_j,
+      sum(dur / 1e6) AS dur_ms
+    FROM run_story_span_join_drain
+    GROUP BY name
+  )
+SELECT subsystem, sum(drain_j) AS drain_j, max(dur_ms) AS dur_ms
+FROM drain_per_rail
+JOIN power_counters
+  USING (name)
 GROUP BY subsystem;
 
+
 CREATE VIEW interaction_events AS
 SELECT ts, dur
 FROM slice
@@ -34,12 +42,19 @@
 
 -- Compute cumulative power drain over the total duration of interaction events.
 CREATE VIEW interaction_drain AS
-SELECT
-    subsystem,
-    sum(dur * drain_w / 1e9) as drain_j,
-    sum(dur / 1e6) as dur_ms
-FROM interactions_span_join_drain
-JOIN power_counters USING (name)
+WITH
+  drain_per_rail AS (
+    SELECT
+      name,
+      sum(dur * drain_w / 1e9) AS drain_j,
+      sum(dur / 1e6) AS dur_ms
+    FROM interactions_span_join_drain
+    GROUP BY name
+  )
+SELECT subsystem, sum(drain_j) AS drain_j, max(dur_ms) AS dur_ms
+FROM drain_per_rail
+JOIN power_counters
+  USING (name)
 GROUP BY subsystem;
 
 -- Output power consumption as measured by several ODPMs, over the following
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index f502833b..44ad1e3 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -302,7 +302,6 @@
  <item id="tachyon_ice_config_fetcher" added_in_milestone="98" content_hash_code="01e878b0" os_list="chromeos" file_path="chrome/browser/nearby_sharing/tachyon_ice_config_fetcher.cc" />
  <item id="supervised_users_denylist" added_in_milestone="98" content_hash_code="01cebaff" os_list="chromeos,android" file_path="chrome/browser/supervised_user/supervised_user_service.cc" />
  <item id="app_suggestion_get_favicon" added_in_milestone="98" content_hash_code="07fca800" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/app_service_app_result.cc" />
- <item id="url_icon_source_fetch" added_in_milestone="98" content_hash_code="0297f30b" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/common/url_icon_source.cc" />
  <item id="launcher_item_suggest" added_in_milestone="98" content_hash_code="04a4041e" os_list="chromeos" file_path="chrome/browser/ui/app_list/search/files/item_suggest_cache.cc" />
  <item id="ambient_client" added_in_milestone="98" content_hash_code="062d821f" os_list="chromeos" file_path="chrome/browser/ui/ash/ambient/ambient_client_impl.cc" />
  <item id="calendar_get_events" added_in_milestone="98" content_hash_code="0603f52a" os_list="chromeos" file_path="chrome/browser/ui/ash/calendar/calendar_keyed_service.cc" />
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index b2e3885..825ac767 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -88,7 +88,6 @@
       <annotation id="tachyon_ice_config_fetcher"/>
       <annotation id="terms_of_service_fetch"/>
       <annotation id="timezone_lookup"/>
-      <annotation id="url_icon_source_fetch"/>
       <annotation id="wallpaper_backdrop_collection_names"/>
       <annotation id="wallpaper_backdrop_images_info"/>
       <annotation id="wallpaper_backdrop_surprise_me_image"/>
diff --git a/ui/ozone/platform/wayland/common/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc
index 12ae52b2..1c621e2 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -46,7 +46,12 @@
 namespace {
 
 void delete_gtk_surface1(gtk_surface1* surface) {
-  gtk_surface1_release(surface);
+  if (wl::get_version_of_object(surface) >=
+      GTK_SURFACE1_RELEASE_SINCE_VERSION) {
+    gtk_surface1_release(surface);
+  } else {
+    gtk_surface1_destroy(surface);
+  }
 }
 
 void delete_data_device(wl_data_device* data_device) {
diff --git a/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc b/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
index b6ce41b..78abcde8 100644
--- a/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_cursor_factory_unittest.cc
@@ -7,7 +7,6 @@
 #include <wayland-cursor.h>
 
 #include "base/containers/flat_map.h"
-#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "ui/base/cursor/platform_cursor.h"
 #include "ui/ozone/common/bitmap_cursor.h"
@@ -53,11 +52,9 @@
 
 }  // namespace
 
-class WaylandCursorFactoryTest : public WaylandTest,
+class WaylandCursorFactoryTest : public WaylandTestSimple,
                                  public CursorFactoryObserver {
  public:
-  WaylandCursorFactoryTest() = default;
-
   // CursorFactoryObserver:
   void OnThemeLoaded() override {
     ASSERT_TRUE(loop_quit_closure_);
@@ -87,7 +84,7 @@
 // Tests that the factory holds the cursor theme until a buffer taken from it
 // released.
 // TODO(1357512): fails on Linux (not used on LaCros).
-TEST_P(WaylandCursorFactoryTest,
+TEST_F(WaylandCursorFactoryTest,
        DISABLED_RetainOldThemeUntilNewBufferIsAttached) {
   std::unique_ptr<WaylandCursorFactory> cursor_factory =
       std::make_unique<DryRunningWaylandCursorFactory>(connection_.get());
@@ -167,7 +164,7 @@
 // Tests that the factory keeps the caches when either cursor size or buffer
 // scale are changed, and only resets them when the theme is changed.
 // TODO(1357512): fails on Linux (not used on LaCros).
-TEST_P(WaylandCursorFactoryTest, DISABLED_CachesSizesUntilThemeNameIsChanged) {
+TEST_F(WaylandCursorFactoryTest, DISABLED_CachesSizesUntilThemeNameIsChanged) {
   std::unique_ptr<WaylandCursorFactory> cursor_factory =
       std::make_unique<DryRunningWaylandCursorFactory>(connection_.get());
   cursor_factory->AddObserver(this);
@@ -259,8 +256,4 @@
   }
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandCursorFactoryTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index afb4371..4f196ad1 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -266,7 +266,7 @@
   std::unique_ptr<MockDragFinishedCallback> drag_finished_callback_;
 };
 
-TEST_P(WaylandDataDragControllerTest, StartDrag) {
+TEST_F(WaylandDataDragControllerTest, StartDrag) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
   auto test = [](WaylandDataDragControllerTest* self) {
@@ -287,7 +287,7 @@
   EXPECT_FALSE(data_device()->drag_delegate_);
 }
 
-TEST_P(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithWrongMimeType) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
   // The client starts dragging offering data with |kMimeTypeHTML|
@@ -307,7 +307,7 @@
 //  - https://crbug.com/1236708
 //  - https://crbug.com/1207607
 //  - https://crbug.com/1247063
-TEST_P(WaylandDataDragControllerTest, StartDragWithCustomFormats) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithCustomFormats) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
   OSExchangeData data(OSExchangeDataProviderFactory::CreateProvider());
   ClipboardFormatType kCustomFormats[] = {
@@ -333,7 +333,7 @@
   });
 }
 
-TEST_P(WaylandDataDragControllerTest, StartDragWithText) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithText) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
   // The client starts dragging offering text mime type.
@@ -349,7 +349,7 @@
   ReadAndCheckData(kMimeTypeText, kSampleTextForDragAndDrop);
 }
 
-TEST_P(WaylandDataDragControllerTest, StartDragWithFileContents) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithFileContents) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
   // The client starts dragging offering text mime type.
@@ -375,7 +375,7 @@
   return arg.IsWithinDistance(n, 0.01f);
 }
 
-TEST_P(WaylandDataDragControllerTest, ReceiveDrag) {
+TEST_F(WaylandDataDragControllerTest, ReceiveDrag) {
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
 
   // Consume the move event from pointer enter.
@@ -428,7 +428,7 @@
   ASSERT_FALSE(data_device()->drag_delegate_);
 }
 
-TEST_P(WaylandDataDragControllerTest, ReceiveDragPixelSurface) {
+TEST_F(WaylandDataDragControllerTest, ReceiveDragPixelSurface) {
   constexpr int32_t kTripleScale = 3;
 
   // Set connection to use pixel coordinates.
@@ -495,7 +495,7 @@
   SendMotionEvent(top_left);
 }
 
-TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
+TEST_F(WaylandDataDragControllerTest, DropSeveralMimeTypes) {
   EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
   PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) {
@@ -539,7 +539,7 @@
 
 // Tests URI validation for text/uri-list MIME type.  Log warnings rendered in
 // the console when this test is running are the expected and valid side effect.
-TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) {
+TEST_F(WaylandDataDragControllerTest, ValidateDroppedUriList) {
   const struct {
     std::string content;
     base::flat_set<std::string> expected_uris;
@@ -600,7 +600,7 @@
 
 // Tests URI validation for text/x-moz-url MIME type.  Log warnings rendered in
 // the console when this test is running are the expected and valid side effect.
-TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
+TEST_F(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
   const struct {
     std::u16string content;
     std::string expected_url;
@@ -663,7 +663,7 @@
 
 // Verifies the correct delegate functions are called when a drag session is
 // started and cancelled within the same surface.
-TEST_P(WaylandDataDragControllerTest, StartAndCancel) {
+TEST_F(WaylandDataDragControllerTest, StartAndCancel) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
   ScheduleDataDeviceAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
@@ -674,7 +674,7 @@
   RunMouseDragWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
 }
 
-TEST_P(WaylandDataDragControllerTest, ForeignDragHandleAskAction) {
+TEST_F(WaylandDataDragControllerTest, ForeignDragHandleAskAction) {
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
   PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) {
     auto* data_offer =
@@ -721,7 +721,7 @@
 
 // Verifies entered surface destruction is properly handled.
 // Regression test for https://crbug.com/1143707.
-TEST_P(WaylandDataDragControllerTest, DestroyEnteredSurface) {
+TEST_F(WaylandDataDragControllerTest, DestroyEnteredSurface) {
   auto* window_1 = window_.get();
   FocusAndPressLeftPointerButton(window_1, &delegate_);
 
@@ -758,7 +758,7 @@
 
 // Verifies that early origin surface destruction is properly handled.
 // Regression test for https://crbug.com/1143707.
-TEST_P(WaylandDataDragControllerTest, DestroyOriginSurface) {
+TEST_F(WaylandDataDragControllerTest, DestroyOriginSurface) {
   auto* window_1 = window_.get();
   SetPointerFocusedWindow(nullptr);
 
@@ -802,7 +802,7 @@
 }
 
 // Ensures drag/drop events are properly propagated to non-toplevel windows.
-TEST_P(WaylandDataDragControllerTest, DragToNonToplevelWindows) {
+TEST_F(WaylandDataDragControllerTest, DragToNonToplevelWindows) {
   auto* origin_window = window_.get();
   FocusAndPressLeftPointerButton(origin_window, &delegate_);
 
@@ -860,7 +860,7 @@
 
 // Ensures that requests to create a |PlatformWindowType::kPopup| during drag
 // sessions return xdg_popup-backed windows.
-TEST_P(WaylandDataDragControllerTest, PopupRequestCreatesPopupWindow) {
+TEST_F(WaylandDataDragControllerTest, PopupRequestCreatesPopupWindow) {
   auto* origin_window = window_.get();
   FocusAndPressLeftPointerButton(origin_window, &delegate_);
 
@@ -892,7 +892,7 @@
 
 // Ensures that requests to create a |PlatformWindowType::kMenu| during drag
 // sessions return xdg_popup-backed windows.
-TEST_P(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) {
+TEST_F(WaylandDataDragControllerTest, MenuRequestCreatesPopupWindow) {
   auto* origin_window = window_.get();
   FocusAndPressLeftPointerButton(origin_window, &delegate_);
 
@@ -933,7 +933,7 @@
 // browser <=> renderer IPC, etc. In both cases, drag controller is expected to
 // gracefully reset state and quit drag loop as if the drag session was
 // cancelled as usual.
-TEST_P(WaylandDataDragControllerTest, AsyncNoopStartDrag) {
+TEST_F(WaylandDataDragControllerTest, AsyncNoopStartDrag) {
   OSExchangeData os_exchange_data;
   os_exchange_data.SetString(sample_text_for_dnd());
 
@@ -988,7 +988,7 @@
 }
 
 // Regression test for https://crbug.com/1175083.
-TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerial) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithCorrectSerial) {
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
   absl::optional<wl::Serial> mouse_press_serial =
       connection()->serial_tracker().GetSerial(wl::SerialType::kMousePress);
@@ -1038,7 +1038,7 @@
 
 // Check drag session is correctly started when there are both mouse button and
 // a touch point pressed.
-TEST_P(WaylandDataDragControllerTest, StartDragWithCorrectSerialForDragSource) {
+TEST_F(WaylandDataDragControllerTest, StartDragWithCorrectSerialForDragSource) {
   OSExchangeData os_exchange_data;
   os_exchange_data.SetString(sample_text_for_dnd());
 
@@ -1093,8 +1093,4 @@
   });
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandDataDragControllerTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc b/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
index 3a3c834..06020a1 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_event_source_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/memory/raw_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_seat.h"
 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/test_keyboard.h"
@@ -25,45 +26,27 @@
 
 }  // namespace
 
-class WaylandEventSourceTest : public WaylandTest {
+class WaylandEventSourceTest : public WaylandTestSimple {
  public:
-  WaylandEventSourceTest() {}
-
-  WaylandEventSourceTest(const WaylandEventSourceTest&) = delete;
-  WaylandEventSourceTest& operator=(const WaylandEventSourceTest&) = delete;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     pointer_delegate_ = connection_->event_source();
     ASSERT_TRUE(pointer_delegate_);
   }
 
  protected:
-  std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
-      PlatformWindowType type,
-      const gfx::Rect bounds,
-      MockPlatformWindowDelegate* delegate) {
-    PlatformWindowInitProperties properties;
-    properties.bounds = bounds;
-    properties.type = type;
-    auto window = WaylandWindow::Create(delegate, connection_.get(),
-                                        std::move(properties));
-    if (window)
-      window->Show(false);
-    return window;
-  }
-
   raw_ptr<WaylandPointer::Delegate> pointer_delegate_ = nullptr;
 };
 
 // Verify WaylandEventSource properly manages its internal state as pointer
 // button events are sent. More specifically - pointer flags.
-TEST_P(WaylandEventSourceTest, CheckPointerButtonHandling) {
-  MockPlatformWindowDelegate delegate;
-  wl_seat_send_capabilities(server_.seat()->resource(),
-                            WL_SEAT_CAPABILITY_POINTER);
-  Sync();
+TEST_F(WaylandEventSourceTest, CheckPointerButtonHandling) {
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    wl_seat_send_capabilities(server->seat()->resource(),
+                              WL_SEAT_CAPABILITY_POINTER);
+  });
+  ASSERT_TRUE(connection_->seat()->pointer());
 
   EXPECT_FALSE(pointer_delegate_->IsPointerButtonPressed(EF_LEFT_MOUSE_BUTTON));
   EXPECT_FALSE(
@@ -74,46 +57,51 @@
   EXPECT_FALSE(
       pointer_delegate_->IsPointerButtonPressed(EF_FORWARD_MOUSE_BUTTON));
 
-  auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
-                                               kDefaultBounds, &delegate);
-  Sync();
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(2);
 
-  ASSERT_TRUE(server_.seat()->pointer());
+  PostToServerAndWait([surface_id = window_->root_surface()->get_surface_id()](
+                          wl::TestWaylandServerThread* server) {
+    auto* const surface =
+        server->GetObject<wl::MockSurface>(surface_id)->resource();
+    auto* const pointer = server->seat()->pointer()->resource();
 
-  uint32_t serial = 0;
-  uint32_t tstamp = 0;
-  wl_resource* surface_res =
-      server_
-          .GetObject<wl::MockSurface>(window1->root_surface()->get_surface_id())
-          ->resource();
-  wl_resource* pointer_res = server_.seat()->pointer()->resource();
-
-  wl_pointer_send_enter(pointer_res, serial++, surface_res, 0, 0);
-  wl_pointer_send_frame(pointer_res);
-  wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_LEFT,
-                         WL_POINTER_BUTTON_STATE_PRESSED);
-  wl_pointer_send_frame(pointer_res);
-  EXPECT_CALL(delegate, DispatchEvent(_)).Times(2);
-  Sync();
+    wl_pointer_send_enter(pointer, server->GetNextSerial(), surface, 0, 0);
+    wl_pointer_send_frame(pointer);
+    wl_pointer_send_button(pointer, server->GetNextSerial(),
+                           server->GetNextTime(), BTN_LEFT,
+                           WL_POINTER_BUTTON_STATE_PRESSED);
+    wl_pointer_send_frame(pointer);
+  });
 
   EXPECT_TRUE(pointer_delegate_->IsPointerButtonPressed(EF_LEFT_MOUSE_BUTTON));
 
-  wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_RIGHT,
-                         WL_POINTER_BUTTON_STATE_PRESSED);
-  wl_pointer_send_frame(pointer_res);
-  EXPECT_CALL(delegate, DispatchEvent(_)).Times(1);
-  Sync();
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    auto* const pointer = server->seat()->pointer()->resource();
+
+    wl_pointer_send_button(pointer, server->GetNextSerial(),
+                           server->GetNextTime(), BTN_RIGHT,
+                           WL_POINTER_BUTTON_STATE_PRESSED);
+    wl_pointer_send_frame(pointer);
+  });
 
   EXPECT_TRUE(pointer_delegate_->IsPointerButtonPressed(EF_RIGHT_MOUSE_BUTTON));
 
-  wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_LEFT,
-                         WL_POINTER_BUTTON_STATE_RELEASED);
-  wl_pointer_send_frame(pointer_res);
-  wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_RIGHT,
-                         WL_POINTER_BUTTON_STATE_RELEASED);
-  wl_pointer_send_frame(pointer_res);
-  EXPECT_CALL(delegate, DispatchEvent(_)).Times(2);
-  Sync();
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(2);
+  PostToServerAndWait([surface_id = window_->root_surface()->get_surface_id()](
+                          wl::TestWaylandServerThread* server) {
+    auto* const pointer = server->seat()->pointer()->resource();
+
+    wl_pointer_send_button(pointer, server->GetNextSerial(),
+                           server->GetNextTime(), BTN_LEFT,
+                           WL_POINTER_BUTTON_STATE_RELEASED);
+    wl_pointer_send_frame(pointer);
+    wl_pointer_send_button(pointer, server->GetNextSerial(),
+                           server->GetNextTime(), BTN_RIGHT,
+                           WL_POINTER_BUTTON_STATE_RELEASED);
+    wl_pointer_send_frame(pointer);
+  });
 
   EXPECT_FALSE(pointer_delegate_->IsPointerButtonPressed(EF_LEFT_MOUSE_BUTTON));
   EXPECT_FALSE(
@@ -122,76 +110,67 @@
 
 // Verify WaylandEventSource properly manages its internal state as pointer
 // button events are sent. More specifically - pointer flags.
-TEST_P(WaylandEventSourceTest, DeleteBeforeTouchFrame) {
-  MockPlatformWindowDelegate delegate;
-  wl_seat_send_capabilities(server_.seat()->resource(),
-                            WL_SEAT_CAPABILITY_TOUCH);
+TEST_F(WaylandEventSourceTest, DeleteBeforeTouchFrame) {
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    wl_seat_send_capabilities(server->seat()->resource(),
+                              WL_SEAT_CAPABILITY_TOUCH);
+  });
+  ASSERT_TRUE(connection_->seat()->touch());
 
+  MockWaylandPlatformWindowDelegate delegate;
   auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
                                                kDefaultBounds, &delegate);
-  Sync();
 
-  ASSERT_TRUE(server_.seat()->touch());
+  PostToServerAndWait([surface_id = window1->root_surface()->get_surface_id()](
+                          wl::TestWaylandServerThread* server) {
+    auto* const surface =
+        server->GetObject<wl::MockSurface>(surface_id)->resource();
+    auto* const touch = server->seat()->touch()->resource();
 
-  uint32_t serial = 0;
-  uint32_t tstamp = 0;
-  wl_resource* surface_res =
-      server_
-          .GetObject<wl::MockSurface>(window1->root_surface()->get_surface_id())
-          ->resource();
-  wl_resource* touch_res = server_.seat()->touch()->resource();
-
-  wl_touch_send_down(touch_res, serial++, tstamp++, surface_res, /*id=*/0, 0,
-                     0);
-  wl_touch_send_down(touch_res, serial++, tstamp++, surface_res, /*id=*/1, 0,
-                     0);
-
-  Sync();
+    wl_touch_send_down(touch, server->GetNextSerial(), server->GetNextTime(),
+                       surface, /*id=*/0, 0, 0);
+    wl_touch_send_down(touch, server->GetNextSerial(), server->GetNextTime(),
+                       surface, /*id=*/1, 0, 0);
+  });
 
   // Removing the target during touch event sequence should not cause crash.
   window1.reset();
 
-  wl_touch_send_frame(touch_res);
   EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
 
-  Sync();
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    auto* const touch = server->seat()->touch()->resource();
+
+    wl_touch_send_frame(touch);
+  });
 }
 
 // Verify WaylandEventSource ignores release events for mouse buttons that
 // aren't pressed. Regression test for crbug.com/1376393.
-TEST_P(WaylandEventSourceTest, IgnoreReleaseWithoutPress) {
-  MockPlatformWindowDelegate delegate;
-  wl_seat_send_capabilities(server_.seat()->resource(),
-                            WL_SEAT_CAPABILITY_POINTER);
+TEST_F(WaylandEventSourceTest, IgnoreReleaseWithoutPress) {
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    wl_seat_send_capabilities(server->seat()->resource(),
+                              WL_SEAT_CAPABILITY_POINTER);
+  });
+  ASSERT_TRUE(connection_->seat()->pointer());
 
-  auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
-                                               kDefaultBounds, &delegate);
-  Sync();
+  // The only event the delegate should capture is when the pointer enters the
+  // surface.
+  EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
+  PostToServerAndWait([surface_id = window_->root_surface()->get_surface_id()](
+                          wl::TestWaylandServerThread* server) {
+    auto* const surface =
+        server->GetObject<wl::MockSurface>(surface_id)->resource();
+    auto* const pointer = server->seat()->pointer()->resource();
 
-  ASSERT_TRUE(server_.seat()->pointer());
+    wl_pointer_send_enter(pointer, server->GetNextSerial(), surface, 0, 0);
+    wl_pointer_send_frame(pointer);
 
-  uint32_t serial = 0;
-  uint32_t tstamp = 0;
-  wl_resource* surface_res =
-      server_
-          .GetObject<wl::MockSurface>(window1->root_surface()->get_surface_id())
-          ->resource();
-  wl_resource* pointer_res = server_.seat()->pointer()->resource();
-
-  wl_pointer_send_enter(pointer_res, serial++, surface_res, 0, 0);
-  wl_pointer_send_frame(pointer_res);
-  EXPECT_CALL(delegate, DispatchEvent(_)).Times(1);
-  Sync();
-
-  wl_pointer_send_button(pointer_res, serial++, tstamp++, BTN_LEFT,
-                         WL_POINTER_BUTTON_STATE_RELEASED);
-  wl_pointer_send_frame(pointer_res);
-  EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
-  Sync();
+    wl_pointer_send_button(pointer, server->GetNextSerial(),
+                           server->GetNextTime(), BTN_LEFT,
+                           WL_POINTER_BUTTON_STATE_RELEASED);
+    wl_pointer_send_frame(pointer);
+  });
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandEventSourceTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc b/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
index 5454edf..9d528cb 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc
@@ -38,24 +38,18 @@
 // the sync on the test tear down.  To ensure that the error message is caught
 // by the crash reporter, we wait until idle in the end of each test before
 // checking the crash key value.
-class WaylandEventWatcherTest : public WaylandTest {
- public:
-  WaylandEventWatcherTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandEventWatcherTest(const WaylandEventWatcherTest&) = delete;
-  WaylandEventWatcherTest& operator=(const WaylandEventWatcherTest&) = delete;
-  ~WaylandEventWatcherTest() override = default;
-
+class WaylandEventWatcherTest : public WaylandTestSimple {
  protected:
   void TearDown() override {
     // All tests in this suite terminate the client-server connection by posting
     // various errors.  We cannot sync the connection on tear down.
     DisableSyncOnTearDown();
 
-    WaylandTest::TearDown();
+    WaylandTestSimple::TearDown();
   }
 };
 
-TEST_P(WaylandEventWatcherTest, CrashKeyResourceError) {
+TEST_F(WaylandEventWatcherTest, CrashKeyResourceError) {
   const std::string kTestErrorString = "This is a nice error.";
 
   std::string text;
@@ -88,7 +82,7 @@
   EXPECT_EQ(text, crash_reporter::GetCrashKeyValue("wayland_error"));
 }
 
-TEST_P(WaylandEventWatcherTest, CrashKeyResourceNoMemory) {
+TEST_F(WaylandEventWatcherTest, CrashKeyResourceNoMemory) {
   // Prepare the expectation error string.
   const std::string expected_error_code = base::StrCat(
       {"wl_display: error ",
@@ -111,7 +105,7 @@
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
 
-TEST_P(WaylandEventWatcherTest, CrashKeyClientNoMemoryError) {
+TEST_F(WaylandEventWatcherTest, CrashKeyClientNoMemoryError) {
   const std::string expected_error_code = base::StrCat(
       {"wl_display: error ",
        NumberToString(static_cast<uint32_t>(WL_DISPLAY_ERROR_NO_MEMORY)),
@@ -128,7 +122,7 @@
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
 
-TEST_P(WaylandEventWatcherTest, CrashKeyClientImplementationError) {
+TEST_F(WaylandEventWatcherTest, CrashKeyClientImplementationError) {
   const std::string kError = "A nice error.";
   const std::string expected_error_code = base::StrCat(
       {"wl_display: error ",
@@ -147,7 +141,7 @@
             crash_reporter::GetCrashKeyValue("wayland_error"));
 }
 
-TEST_P(WaylandEventWatcherTest, CrashKeyCompositorNameSet) {
+TEST_F(WaylandEventWatcherTest, CrashKeyCompositorNameSet) {
   const std::string kTestWaylandCompositor = "OzoneWaylandTestCompositor";
   base::Environment::Create()->SetVar(base::nix::kXdgCurrentDesktopEnvVar,
                                       kTestWaylandCompositor);
@@ -164,7 +158,7 @@
             crash_reporter::GetCrashKeyValue("wayland_compositor"));
 }
 
-TEST_P(WaylandEventWatcherTest, CrashKeyCompositorNameUnset) {
+TEST_F(WaylandEventWatcherTest, CrashKeyCompositorNameUnset) {
   base::Environment::Create()->UnSetVar(base::nix::kXdgCurrentDesktopEnvVar);
 
   server_.RunAndWait(
@@ -178,8 +172,4 @@
   EXPECT_EQ("Unknown", crash_reporter::GetCrashKeyValue("wayland_compositor"));
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandEventWatcherTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
index 10d8f80..9304d56 100644
--- a/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
@@ -20,6 +20,7 @@
 #include "ui/gfx/range/range.h"
 #include "ui/ozone/platform/wayland/host/wayland_event_source.h"
 #include "ui/ozone/platform/wayland/host/wayland_input_method_context.h"
+#include "ui/ozone/platform/wayland/host/wayland_seat.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/mock_zcr_extended_text_input.h"
@@ -35,7 +36,6 @@
 using ::testing::Values;
 
 namespace ui {
-namespace {
 
 // Returns the number of grapheme clusters in the text.
 absl::optional<size_t> CountGraphemeCluster(base::StringPiece16 text) {
@@ -229,19 +229,10 @@
   absl::optional<gfx::Rect> virtual_keyboard_bounds_;
 };
 
-class WaylandInputMethodContextTest : public WaylandTest {
+class WaylandInputMethodContextTest : public WaylandTestSimple {
  public:
-  // TODO(crbug.com/1365887): TestServerMode::kAsync must be removed once all
-  // tests switch to asynchronous mode.
-  WaylandInputMethodContextTest()
-      : WaylandTest(WaylandTest::TestServerMode::kAsync) {}
-  ~WaylandInputMethodContextTest() override = default;
-  WaylandInputMethodContextTest(const WaylandInputMethodContextTest&) = delete;
-  WaylandInputMethodContextTest& operator=(
-      const WaylandInputMethodContextTest&) = delete;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     surface_id_ = window_->root_surface()->get_surface_id();
 
@@ -251,6 +242,7 @@
       wl_seat_send_capabilities(server->seat()->resource(),
                                 WL_SEAT_CAPABILITY_KEYBOARD);
     });
+    ASSERT_TRUE(connection_->seat()->keyboard());
 
     SetUpInternal();
   }
@@ -288,7 +280,7 @@
   uint32_t surface_id_ = 0u;
 };
 
-TEST_P(WaylandInputMethodContextTest, ActivateDeactivate) {
+TEST_F(WaylandInputMethodContextTest, ActivateDeactivate) {
   // Activate is called only when both InputMethod's TextInputClient focus and
   // Wayland's keyboard focus is met.
 
@@ -403,7 +395,7 @@
   });
 }
 
-TEST_P(WaylandInputMethodContextTest, Reset) {
+TEST_F(WaylandInputMethodContextTest, Reset) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(*server->text_input_manager_v1()->text_input(), Reset());
   });
@@ -411,7 +403,7 @@
   connection_->Flush();
 }
 
-TEST_P(WaylandInputMethodContextTest, SetCursorLocation) {
+TEST_F(WaylandInputMethodContextTest, SetCursorLocation) {
   constexpr gfx::Rect cursor_location(50, 0, 1, 1);
   PostToServerAndWait([cursor_location](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(
@@ -423,7 +415,7 @@
   connection_->Flush();
 }
 
-TEST_P(WaylandInputMethodContextTest, SetSurroundingTextForShortText) {
+TEST_F(WaylandInputMethodContextTest, SetSurroundingTextForShortText) {
   const std::u16string text(50, u'あ');
   constexpr gfx::Range range(20, 30);
 
@@ -458,7 +450,7 @@
       (std::pair<size_t, size_t>(0, 0)));
 }
 
-TEST_P(WaylandInputMethodContextTest, SetSurroundingTextForLongText) {
+TEST_F(WaylandInputMethodContextTest, SetSurroundingTextForLongText) {
   const std::u16string text(5000, u'あ');
   constexpr gfx::Range range(2800, 3200);
 
@@ -495,7 +487,7 @@
       (std::pair<size_t, size_t>(0, 0)));
 }
 
-TEST_P(WaylandInputMethodContextTest, SetSurroundingTextForLongTextInLeftEdge) {
+TEST_F(WaylandInputMethodContextTest, SetSurroundingTextForLongTextInLeftEdge) {
   const std::u16string text(5000, u'あ');
   constexpr gfx::Range range(0, 500);
 
@@ -532,7 +524,7 @@
       (std::pair<size_t, size_t>(0, 0)));
 }
 
-TEST_P(WaylandInputMethodContextTest,
+TEST_F(WaylandInputMethodContextTest,
        SetSurroundingTextForLongTextInRightEdge) {
   const std::u16string text(5000, u'あ');
   constexpr gfx::Range range(4500, 5000);
@@ -570,7 +562,7 @@
       (std::pair<size_t, size_t>(0, 0)));
 }
 
-TEST_P(WaylandInputMethodContextTest, SetSurroundingTextForLongRange) {
+TEST_F(WaylandInputMethodContextTest, SetSurroundingTextForLongRange) {
   const std::u16string text(5000, u'あ');
   constexpr gfx::Range range(1000, 4000);
 
@@ -591,7 +583,7 @@
   });
 }
 
-TEST_P(WaylandInputMethodContextTest, DeleteSurroundingTextWithExtendedRange) {
+TEST_F(WaylandInputMethodContextTest, DeleteSurroundingTextWithExtendedRange) {
   const std::u16string text(50, u'あ');
   const gfx::Range range(20, 30);
 
@@ -626,7 +618,7 @@
       (std::pair<size_t, size_t>(1, 1)));
 }
 
-TEST_P(WaylandInputMethodContextTest, SetContentType) {
+TEST_F(WaylandInputMethodContextTest, SetContentType) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(
         *server->text_input_extension_v1()->extended_text_input(),
@@ -648,7 +640,7 @@
   });
 }
 
-TEST_P(WaylandInputMethodContextTest, SetContentTypeWithoutLearning) {
+TEST_F(WaylandInputMethodContextTest, SetContentTypeWithoutLearning) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(
         *server->text_input_extension_v1()->extended_text_input(),
@@ -670,7 +662,7 @@
   });
 }
 
-TEST_P(WaylandInputMethodContextTest, OnPreeditChanged) {
+TEST_F(WaylandInputMethodContextTest, OnPreeditChanged) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     zwp_text_input_v1_send_preedit_string(
         server->text_input_manager_v1()->text_input()->resource(),
@@ -679,7 +671,7 @@
   EXPECT_TRUE(input_method_context_delegate_->was_on_preedit_changed_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnCommit) {
+TEST_F(WaylandInputMethodContextTest, OnCommit) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     zwp_text_input_v1_send_commit_string(
         server->text_input_manager_v1()->text_input()->resource(),
@@ -697,7 +689,7 @@
 #define MAYBE(x) DISABLED_##x
 #endif
 
-TEST_P(WaylandInputMethodContextTest, MAYBE(OnConfirmCompositionText)) {
+TEST_F(WaylandInputMethodContextTest, MAYBE(OnConfirmCompositionText)) {
   constexpr char16_t text[] = u"ab😀cあdef";
   constexpr gfx::Range range(5, 6);  // あ is selected.
 
@@ -722,7 +714,7 @@
       input_method_context_delegate_->was_on_confirm_composition_text_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnSetPreeditRegion_Success) {
+TEST_F(WaylandInputMethodContextTest, OnSetPreeditRegion_Success) {
   constexpr char16_t text[] = u"abcあdef";
   const gfx::Range range(3, 4);  // あ is selected.
 
@@ -749,7 +741,7 @@
       input_method_context_delegate_->was_on_set_preedit_region_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnSetPreeditRegion_NoSurroundingText) {
+TEST_F(WaylandInputMethodContextTest, OnSetPreeditRegion_NoSurroundingText) {
   // If no surrounding text is set yet, set_preedit_region would fail.
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     zcr_extended_text_input_v1_send_set_preedit_region(
@@ -762,7 +754,7 @@
 
 // The range is represented in UTF-16 code points, so it is independent from
 // grapheme clusters.
-TEST_P(WaylandInputMethodContextTest,
+TEST_F(WaylandInputMethodContextTest,
        OnSetPreeditRegion_GraphemeClusterIndependeceSimple) {
   // Single code point representation of é.
   constexpr char16_t u16_text[] = u"\u00E9";
@@ -797,7 +789,7 @@
       input_method_context_delegate_->was_on_set_preedit_region_called());
 }
 
-TEST_P(WaylandInputMethodContextTest,
+TEST_F(WaylandInputMethodContextTest,
        OnSetPreeditRegion_GraphemeClusterIndependeceCombined) {
   // Decomposed code point representation of é.
   constexpr char16_t u16_text[] = u"\u0065\u0301";
@@ -832,14 +824,14 @@
       input_method_context_delegate_->was_on_set_preedit_region_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnClearGrammarFragments) {
+TEST_F(WaylandInputMethodContextTest, OnClearGrammarFragments) {
   input_method_context_->OnClearGrammarFragments(gfx::Range(1, 5));
   SyncDisplay();
   EXPECT_TRUE(
       input_method_context_delegate_->was_on_clear_grammar_fragments_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnAddGrammarFragments) {
+TEST_F(WaylandInputMethodContextTest, OnAddGrammarFragments) {
   input_method_context_->OnAddGrammarFragment(
       ui::GrammarFragment(gfx::Range(1, 5), "test"));
   SyncDisplay();
@@ -847,21 +839,21 @@
       input_method_context_delegate_->was_on_add_grammar_fragment_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnSetAutocorrectRange) {
+TEST_F(WaylandInputMethodContextTest, OnSetAutocorrectRange) {
   input_method_context_->OnSetAutocorrectRange(gfx::Range(1, 5));
   SyncDisplay();
   EXPECT_TRUE(
       input_method_context_delegate_->was_on_set_autocorrect_range_called());
 }
 
-TEST_P(WaylandInputMethodContextTest, OnSetVirtualKeyboardOccludedBounds) {
+TEST_F(WaylandInputMethodContextTest, OnSetVirtualKeyboardOccludedBounds) {
   constexpr gfx::Rect kBounds(10, 20, 300, 400);
   input_method_context_->OnSetVirtualKeyboardOccludedBounds(kBounds);
   SyncDisplay();
   EXPECT_EQ(input_method_context_delegate_->virtual_keyboard_bounds(), kBounds);
 }
 
-TEST_P(WaylandInputMethodContextTest,
+TEST_F(WaylandInputMethodContextTest,
        OnSetVirtualKeyboardOccludedBoundsUpdatesPastTextInputClients) {
   auto client1 = std::make_unique<MockTextInputClient>(TEXT_INPUT_TYPE_TEXT);
   auto client2 = std::make_unique<MockTextInputClient>(TEXT_INPUT_TYPE_URL);
@@ -901,7 +893,7 @@
   Mock::VerifyAndClearExpectations(client2.get());
 }
 
-TEST_P(WaylandInputMethodContextTest,
+TEST_F(WaylandInputMethodContextTest,
        OnSetVirtualKeyboardOccludedBoundsWithDeletedPastTextInputClient) {
   auto client = std::make_unique<MockTextInputClient>(TEXT_INPUT_TYPE_TEXT);
 
@@ -920,7 +912,7 @@
   SyncDisplay();
 }
 
-TEST_P(WaylandInputMethodContextTest, DisplayVirtualKeyboard) {
+TEST_F(WaylandInputMethodContextTest, DisplayVirtualKeyboard) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(*server->text_input_manager_v1()->text_input(),
                 ShowInputPanel())
@@ -931,7 +923,7 @@
   SyncDisplay();
 }
 
-TEST_P(WaylandInputMethodContextTest, DismissVirtualKeyboard) {
+TEST_F(WaylandInputMethodContextTest, DismissVirtualKeyboard) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     EXPECT_CALL(*server->text_input_manager_v1()->text_input(),
                 HideInputPanel());
@@ -941,7 +933,7 @@
   SyncDisplay();
 }
 
-TEST_P(WaylandInputMethodContextTest, UpdateVirtualKeyboardState) {
+TEST_F(WaylandInputMethodContextTest, UpdateVirtualKeyboardState) {
   EXPECT_FALSE(input_method_context_->IsKeyboardVisible());
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     zwp_text_input_v1_send_input_panel_state(
@@ -961,16 +953,17 @@
 class WaylandInputMethodContextNoKeyboardTest
     : public WaylandInputMethodContextTest {
  public:
-  WaylandInputMethodContextNoKeyboardTest() = default;
-  ~WaylandInputMethodContextNoKeyboardTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    // Call the skip base implementation to avoid setting up the keyboard.
+    WaylandTestSimple::SetUp();
+
+    ASSERT_FALSE(connection_->seat()->keyboard());
+
     SetUpInternal();
   }
 };
 
-TEST_P(WaylandInputMethodContextNoKeyboardTest, ActivateDeactivate) {
+TEST_F(WaylandInputMethodContextNoKeyboardTest, ActivateDeactivate) {
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
 
   // Because there is no keyboard, Activate is called as soon as InputMethod's
@@ -1005,7 +998,7 @@
   });
 }
 
-TEST_P(WaylandInputMethodContextNoKeyboardTest, UpdateFocusBetweenTextFields) {
+TEST_F(WaylandInputMethodContextNoKeyboardTest, UpdateFocusBetweenTextFields) {
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
 
   // Because there is no keyboard, Activate is called as soon as InputMethod's
@@ -1045,13 +1038,4 @@
   });
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandInputMethodContextTest,
-                         Values(wl::ServerConfig{}));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandInputMethodContextNoKeyboardTest,
-                         Values(wl::ServerConfig{}));
-
-}  // namespace
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
index 70b1fe6..7d079e7 100644
--- a/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_keyboard_unittest.cc
@@ -34,15 +34,10 @@
 
 namespace ui {
 
-class WaylandKeyboardTest : public WaylandTest {
+class WaylandKeyboardTest : public WaylandTestSimple {
  public:
-  WaylandKeyboardTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandKeyboardTest(const WaylandKeyboardTest&) = delete;
-  WaylandKeyboardTest& operator=(const WaylandKeyboardTest&) = delete;
-  ~WaylandKeyboardTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
       wl_seat_send_capabilities(server->seat()->resource(),
@@ -96,7 +91,7 @@
     closure.Run();
 }
 
-TEST_P(WaylandKeyboardTest, Keypress) {
+TEST_F(WaylandKeyboardTest, Keypress) {
   SendEnter();
 
   std::unique_ptr<Event> event;
@@ -135,7 +130,7 @@
   });
 }
 
-TEST_P(WaylandKeyboardTest, ControlShiftModifiers) {
+TEST_F(WaylandKeyboardTest, ControlShiftModifiers) {
   SendEnter();
 
   std::vector<std::unique_ptr<Event>> events;
@@ -183,7 +178,7 @@
 }
 
 #if BUILDFLAG(USE_XKBCOMMON)
-TEST_P(WaylandKeyboardTest, CapsLockModifier) {
+TEST_F(WaylandKeyboardTest, CapsLockModifier) {
   SendEnter();
 
   std::vector<std::unique_ptr<Event>> events;
@@ -231,7 +226,7 @@
 }
 #endif
 
-TEST_P(WaylandKeyboardTest, EventAutoRepeat) {
+TEST_F(WaylandKeyboardTest, EventAutoRepeat) {
   constexpr int32_t rate = 5;    // num key events per second.
   constexpr int32_t delay = 60;  // in milliseconds.
 
@@ -288,7 +283,7 @@
   EXPECT_EQ(second_repeat_delay.InMilliseconds(), 1000 / rate);
 }
 
-TEST_P(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) {
+TEST_F(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) {
   constexpr int32_t rate = 5;    // num key events per second.
   constexpr int32_t delay = 60;  // in milliseconds.
 
@@ -343,8 +338,4 @@
   });
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandKeyboardTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_output_unittest.cc b/ui/ozone/platform/wayland/host/wayland_output_unittest.cc
index 2c6506b8..c5137ec 100644
--- a/ui/ozone/platform/wayland/host/wayland_output_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output_unittest.cc
@@ -13,19 +13,11 @@
 
 namespace ui {
 
-// TODO(crbug.com/1365887): revert this to using WaylandOutputTest = WaylandTest
-// once the default mode becomes asynchronous.
-class WaylandOutputTest : public WaylandTest {
- public:
-  WaylandOutputTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandOutputTest(const WaylandOutputTest&) = delete;
-  WaylandOutputTest& operator=(const WaylandOutputTest&) = delete;
-  ~WaylandOutputTest() override = default;
-};
+using WaylandOutputTest = WaylandTestSimple;
 
 // Tests that name and description fall back to ones in the WaylandOutput if
 // XDGOutput is not created.
-TEST_P(WaylandOutputTest, NameAndDescriptionFallback) {
+TEST_F(WaylandOutputTest, NameAndDescriptionFallback) {
   constexpr char kWlOutputName[] = "kWlOutputName";
   constexpr char kWlOutputDescription[] = "kWlOutputDescription";
   constexpr char kXDGOutputName[] = "kXDGOutputName";
@@ -55,8 +47,4 @@
   EXPECT_EQ(wl_output->description(), kWlOutputDescription);
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandOutputTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
index 9659930..183387717 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer_unittest.cc
@@ -37,15 +37,10 @@
 
 namespace ui {
 
-class WaylandPointerTest : public WaylandTest {
+class WaylandPointerTest : public WaylandTestSimple {
  public:
-  WaylandPointerTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandPointerTest(const WaylandPointerTest&) = delete;
-  WaylandPointerTest& operator=(const WaylandPointerTest&) = delete;
-  ~WaylandPointerTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
       wl_seat_send_capabilities(server->seat()->resource(),
@@ -172,7 +167,7 @@
   *ptr = arg0->Clone();
 }
 
-TEST_P(WaylandPointerTest, Enter) {
+TEST_F(WaylandPointerTest, Enter) {
   std::unique_ptr<Event> event;
   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
 
@@ -187,7 +182,7 @@
   EXPECT_EQ(gfx::PointF(0, 0), mouse_event->location_f());
 }
 
-TEST_P(WaylandPointerTest, Leave) {
+TEST_F(WaylandPointerTest, Leave) {
   MockPlatformWindowDelegate other_delegate;
   gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget;
   EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_))
@@ -233,7 +228,7 @@
   *ptr = arg0->Clone();
 }
 
-TEST_P(WaylandPointerTest, Motion) {
+TEST_F(WaylandPointerTest, Motion) {
   SendEnter();
 
   std::unique_ptr<Event> event;
@@ -257,7 +252,7 @@
   EXPECT_EQ(gfx::PointF(10.75, 20.375), mouse_event->root_location_f());
 }
 
-TEST_P(WaylandPointerTest, MotionDragged) {
+TEST_F(WaylandPointerTest, MotionDragged) {
   SendEnter();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -290,7 +285,7 @@
   EXPECT_EQ(gfx::PointF(400, 500), mouse_event->root_location_f());
 }
 
-TEST_P(WaylandPointerTest, MotionDraggedWithStylus) {
+TEST_F(WaylandPointerTest, MotionDraggedWithStylus) {
   SendEnter();
 
   std::unique_ptr<Event> event;
@@ -339,7 +334,7 @@
 
 // Verifies whether the platform event source handles all types of axis sources.
 // The actual behaviour of each axis source is not tested here.
-TEST_P(WaylandPointerTest, AxisSourceTypes) {
+TEST_F(WaylandPointerTest, AxisSourceTypes) {
   SendEnter();
 
   std::unique_ptr<Event> event1, event2, event3, event4;
@@ -377,7 +372,7 @@
 // to a pointer clicking event.
 // In practice, this might happen with specific compositors, eg Exo, when a
 // device wakes up from sleeping.
-TEST_P(WaylandPointerTest, SpuriousAxisSourceAndStylusToolEvents) {
+TEST_F(WaylandPointerTest, SpuriousAxisSourceAndStylusToolEvents) {
   SendEnter();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -409,7 +404,7 @@
   // Do not validate anything, this test only ensures that no crash occurred.
 }
 
-TEST_P(WaylandPointerTest, Axis) {
+TEST_F(WaylandPointerTest, Axis) {
   SendEnter();
 
   for (uint32_t axis :
@@ -446,7 +441,7 @@
   }
 }
 
-TEST_P(WaylandPointerTest, SetBitmap) {
+TEST_F(WaylandPointerTest, SetBitmap) {
   SendEnter();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -485,7 +480,7 @@
 
 // Tests that bitmap is set on pointer focus and the pointer surface respects
 // provided scale of the surface image.
-TEST_P(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) {
+TEST_F(WaylandPointerTest, SetBitmapAndScaleOnPointerFocus) {
   for (int32_t scale = 1; scale < 5; scale++) {
     gfx::Size size = {10 * scale, 10 * scale};
     SkBitmap dummy_cursor;
@@ -551,7 +546,7 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-TEST_P(WaylandPointerTest, FlingVertical) {
+TEST_F(WaylandPointerTest, FlingVertical) {
   SendEnter(50, 75);
 
   SendRightButtonPress();
@@ -602,7 +597,7 @@
   EXPECT_GT(0.0f, scroll_event->y_offset_ordinal());
 }
 
-TEST_P(WaylandPointerTest, FlingHorizontal) {
+TEST_F(WaylandPointerTest, FlingHorizontal) {
   SendEnter(50, 75);
 
   SendRightButtonPress();
@@ -653,7 +648,7 @@
   EXPECT_GT(0.0f, scroll_event->x_offset_ordinal());
 }
 
-TEST_P(WaylandPointerTest, FlingCancel) {
+TEST_F(WaylandPointerTest, FlingCancel) {
   SendEnter(50, 75);
 
   SendRightButtonPress();
@@ -722,7 +717,7 @@
   EXPECT_EQ(0.0f, scroll_event->y_offset_ordinal());
 }
 
-TEST_P(WaylandPointerTest, FlingDiagonal) {
+TEST_F(WaylandPointerTest, FlingDiagonal) {
   SendEnter(50, 75);
 
   SendRightButtonPress();
@@ -777,8 +772,4 @@
 }
 #endif
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandPointerTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index 4bfbb77a5..504cdcb 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -92,19 +92,10 @@
 
 }  // namespace
 
-class WaylandScreenTest : public WaylandTest {
+class WaylandScreenTest : public WaylandTestSimple {
  public:
-  // TODO(crbug.com/1365887): TestServerMode::kAsync must be removed once all
-  // tests switch to asynchronous mode.
-  WaylandScreenTest() : WaylandTest(WaylandTest::TestServerMode::kAsync) {}
-
-  WaylandScreenTest(const WaylandScreenTest&) = delete;
-  WaylandScreenTest& operator=(const WaylandScreenTest&) = delete;
-
-  ~WaylandScreenTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
       auto* output = server->output();
@@ -150,7 +141,7 @@
 
 // Tests whether a primary output has been initialized before PlatformScreen is
 // created.
-TEST_P(WaylandScreenTest, OutputBaseTest) {
+TEST_F(WaylandScreenTest, OutputBaseTest) {
   // IsPrimaryOutputReady and PlatformScreen creation is done in the
   // initialization part of the tests.
 
@@ -165,7 +156,7 @@
 
 // In multi-monitor setup, the `entered_outputs_` list should be updated when
 // the display is unplugged or switched off.
-TEST_P(WaylandScreenTest, EnteredOutputListAfterDisplayRemoval) {
+TEST_F(WaylandScreenTest, EnteredOutputListAfterDisplayRemoval) {
   // These have to be stored on the client thread, but must be used only on the
   // server thread.
   wl::TestOutput* output1 = nullptr;
@@ -275,7 +266,7 @@
   EXPECT_EQ(2u, entered_outputs.size());
 }
 
-TEST_P(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
+TEST_F(WaylandScreenTest, MultipleOutputsAddedAndRemoved) {
   // This has to be stored on the client thread, but must be used only on the
   // server thread.
   wl::TestOutput* output2 = nullptr;
@@ -369,7 +360,7 @@
   platform_screen_->RemoveObserver(&observer);
 }
 
-TEST_P(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) {
+TEST_F(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -404,7 +395,7 @@
   platform_screen_->RemoveObserver(&observer);
 }
 
-TEST_P(WaylandScreenTest, OutputPropertyChangesPrimaryDisplayChanged) {
+TEST_F(WaylandScreenTest, OutputPropertyChangesPrimaryDisplayChanged) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -446,7 +437,7 @@
   platform_screen_->RemoveObserver(&observer);
 }
 
-TEST_P(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) {
+TEST_F(WaylandScreenTest, GetAcceleratedWidgetAtScreenPoint) {
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
   PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) {
     // Now, send enter event for the surface, which was created before.
@@ -520,7 +511,7 @@
   EXPECT_EQ(widget_at_screen_point, menu_window->GetWidget());
 }
 
-TEST_P(WaylandScreenTest, GetLocalProcessWidgetAtPoint) {
+TEST_F(WaylandScreenTest, GetLocalProcessWidgetAtPoint) {
   gfx::Point point(10, 10);
   EXPECT_EQ(platform_screen_->GetLocalProcessWidgetAtPoint(point, {}),
             gfx::kNullAcceleratedWidget);
@@ -538,7 +529,7 @@
       gfx::kNullAcceleratedWidget);
 }
 
-TEST_P(WaylandScreenTest, GetDisplayMatching) {
+TEST_F(WaylandScreenTest, GetDisplayMatching) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -625,7 +616,7 @@
 }
 
 // Regression test for https://crbug.com/1362872.
-TEST_P(WaylandScreenTest, GetPrimaryDisplayAfterRemoval) {
+TEST_F(WaylandScreenTest, GetPrimaryDisplayAfterRemoval) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -649,7 +640,7 @@
   platform_screen_->RemoveObserver(&observer);
 }
 
-TEST_P(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
+TEST_F(WaylandScreenTest, GetDisplayForAcceleratedWidget) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -732,7 +723,7 @@
   });
 }
 
-TEST_P(WaylandScreenTest, GetCursorScreenPoint) {
+TEST_F(WaylandScreenTest, GetCursorScreenPoint) {
   MockWaylandPlatformWindowDelegate delegate;
   std::unique_ptr<WaylandWindow> second_window =
       CreateWaylandWindowWithProperties(gfx::Rect(0, 0, 1920, 1080),
@@ -928,7 +919,7 @@
 
 // Checks that the surface that backs the window receives new scale of the
 // output that it is in.
-TEST_P(WaylandScreenTest, SetWindowScale) {
+TEST_F(WaylandScreenTest, SetWindowScale) {
   constexpr int32_t kTripleScale = 3;
 
   const uint32_t surface_id = window_->root_surface()->get_surface_id();
@@ -980,7 +971,7 @@
 // which implies in its scale being set to the primary output's scale at its
 // initialization, any primary output scale update (or other properties that
 // lead to scale change) must be propagated to the window.
-TEST_P(WaylandScreenTest, SetWindowScaleWithoutEnteredOutput) {
+TEST_F(WaylandScreenTest, SetWindowScaleWithoutEnteredOutput) {
   // Test pre-conditions: single output setup whereas |output_| is the primary
   // output managed by |output_manager_|, with initial scale == 1.
   ASSERT_EQ(1u, output_manager_->GetAllOutputs().size());
@@ -1012,7 +1003,7 @@
 
 // Checks that output transform is properly translated into Display orientation.
 // The first one is counter-clockwise, while the latter is clockwise.
-TEST_P(WaylandScreenTest, Transform) {
+TEST_F(WaylandScreenTest, Transform) {
   constexpr std::pair<wl_output_transform, display::Display::Rotation>
       kTestData[] = {
           {WL_OUTPUT_TRANSFORM_NORMAL, display::Display::ROTATE_0},
@@ -1041,30 +1032,21 @@
 namespace {
 
 class LazilyConfiguredScreenTest
-    : public WaylandTest,
+    : public WaylandTestSimple,
       public wl::TestWaylandServerThread::OutputDelegate {
  public:
-  // TODO(crbug.com/1365887): TestServerMode::kAsync must be removed once all
-  // tests switch to asynchronous mode.
-  LazilyConfiguredScreenTest()
-      : WaylandTest(WaylandTest::TestServerMode::kAsync) {}
-  LazilyConfiguredScreenTest(const LazilyConfiguredScreenTest&) = delete;
-  LazilyConfiguredScreenTest& operator=(const LazilyConfiguredScreenTest&) =
-      delete;
-  ~LazilyConfiguredScreenTest() override = default;
-
   void SetUp() override {
     // This can be set on the client thread as the server is not running yet.
     ASSERT_FALSE(server_.IsRunning());
     server_.set_output_delegate(this);
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     output_manager_ = connection_->wayland_output_manager();
     ASSERT_TRUE(output_manager_);
   }
 
   void TearDown() override {
-    WaylandTest::TearDown();
+    WaylandTestSimple::TearDown();
 
     PostToServerAndWait(
         [output = aux_output_](wl::TestWaylandServerThread* server) {
@@ -1105,7 +1087,7 @@
 // Ensures WaylandOutputManager and WaylandScreen properly handle scenarios
 // where multiple wl_output objects are announced but not "configured" (ie:
 // size, position, mode, etc sent to client) at bind time.
-TEST_P(LazilyConfiguredScreenTest, DualOutput) {
+TEST_F(LazilyConfiguredScreenTest, DualOutput) {
   // Ensure WaylandScreen got properly created and fed with a single display
   // object, ie: |aux_output_| at server side.
   EXPECT_TRUE(output_manager_->IsOutputReady());
@@ -1128,7 +1110,7 @@
 
 using WaylandAuraShellScreenTest = WaylandScreenTest;
 
-TEST_P(WaylandAuraShellScreenTest, OutputPropertyChanges) {
+TEST_F(WaylandAuraShellScreenTest, OutputPropertyChanges) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
@@ -1221,7 +1203,7 @@
 // in landscape orientation. Thus their physical bounds are in portrait
 // orientation along with an offset transform, which differs from the usual
 // landscape oriented bounds.
-TEST_P(WaylandAuraShellScreenTest,
+TEST_F(WaylandAuraShellScreenTest,
        OutputPropertyChangesWithPortraitPanelRotation) {
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
@@ -1308,16 +1290,4 @@
   platform_screen_->RemoveObserver(&observer);
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandScreenTest,
-                         Values(wl::ServerConfig{}));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandAuraShellScreenTest,
-                         Values(wl::ServerConfig{}));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         LazilyConfiguredScreenTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_surface_unittest.cc b/ui/ozone/platform/wayland/host/wayland_surface_unittest.cc
index 9577ab0..2520339 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface_unittest.cc
@@ -15,19 +15,12 @@
 #include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 namespace ui {
-namespace {
 
 using ::testing::ElementsAre;
 
-class WaylandSurfaceTest : public WaylandTest {
- public:
-  WaylandSurfaceTest() : WaylandTest(WaylandTest::TestServerMode::kAsync) {}
-  WaylandSurfaceTest(const WaylandSurfaceTest&) = delete;
-  WaylandSurfaceTest& operator=(const WaylandSurfaceTest&) = delete;
-  ~WaylandSurfaceTest() override = default;
-};
+using WaylandSurfaceTest = WaylandTestSimple;
 
-TEST_P(WaylandSurfaceTest, SurfaceReenterOutput) {
+TEST_F(WaylandSurfaceTest, SurfaceReenterOutput) {
   WaylandSurface* wayland_surface = window_->root_surface();
   EXPECT_TRUE(wayland_surface->entered_outputs().empty());
 
@@ -58,9 +51,4 @@
   EXPECT_THAT(wayland_surface->entered_outputs(), ElementsAre(output_id));
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandSurfaceTest,
-                         ::testing::Values(wl::ServerConfig{}));
-
-}  // namespace
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
index 83f175c..2dc92f0 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch_unittest.cc
@@ -46,15 +46,10 @@
 
 }  // namespace
 
-class WaylandTouchTest : public WaylandTest {
+class WaylandTouchTest : public WaylandTestSimple {
  public:
-  WaylandTouchTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandTouchTest(const WaylandTouchTest&) = delete;
-  WaylandTouchTest& operator=(const WaylandTouchTest&) = delete;
-  ~WaylandTouchTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
       wl_seat_send_capabilities(
@@ -98,7 +93,7 @@
   }
 };
 
-TEST_P(WaylandTouchTest, TouchPressAndMotion) {
+TEST_F(WaylandTouchTest, TouchPressAndMotion) {
   std::unique_ptr<Event> event;
   EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event));
 
@@ -138,7 +133,7 @@
 }
 
 // Tests that touch events with stylus pen work.
-TEST_P(WaylandTouchTest, TouchPressAndMotionWithStylus) {
+TEST_F(WaylandTouchTest, TouchPressAndMotionWithStylus) {
   std::unique_ptr<Event> event;
   EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event));
 
@@ -185,7 +180,7 @@
 // Tests that touch events with stylus pen work. This variant of the test sends
 // the tool information after the touch down event, and ensures that
 // wl_touch::frame event handles it correctly.
-TEST_P(WaylandTouchTest, TouchPressAndMotionWithStylus2) {
+TEST_F(WaylandTouchTest, TouchPressAndMotionWithStylus2) {
   std::unique_ptr<Event> event;
   EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event));
 
@@ -236,7 +231,7 @@
 }
 
 // Tests that touch focus is correctly set and released.
-TEST_P(WaylandTouchTest, CheckTouchFocus) {
+TEST_F(WaylandTouchTest, CheckTouchFocus) {
   constexpr uint32_t touch_id1 = 1;
   constexpr uint32_t touch_id2 = 2;
   constexpr uint32_t touch_id3 = 3;
@@ -365,7 +360,7 @@
 
 // Verifies keyboard modifier flags are set in touch events while modifier keys
 // are pressed. Regression test for https://crbug.com/1298604.
-TEST_P(WaylandTouchTest, KeyboardFlagsSet) {
+TEST_F(WaylandTouchTest, KeyboardFlagsSet) {
   std::unique_ptr<Event> event;
 
   MaybeSetUpXkb();
@@ -468,8 +463,4 @@
   EXPECT_FALSE(event->flags() & ui::EF_CONTROL_DOWN);
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandTouchTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index bdc1056..6b34826 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -153,7 +153,7 @@
 // 1. With a single 1 window open,
 // 2. Move pointer into it, press left button, move cursor a bit (drag),
 // 3. Run move loop, drag it within the window bounds and drop.
-TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) {
+TEST_F(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) {
   // Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
   EXPECT_EQ(gfx::kNullAcceleratedWidget,
@@ -244,7 +244,7 @@
 // 1. With a single window open,
 // 2. Touch down and move the touch point a bit (drag),
 // 3. Run move loop, drag it within the window bounds and drop.
-TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop_TOUCH) {
+TEST_F(WaylandWindowDragControllerTest, DragInsideWindowAndDrop_TOUCH) {
   ASSERT_TRUE(GetWmMoveLoopHandler(*window_));
   ASSERT_TRUE(GetWaylandExtension(*window_));
 
@@ -333,7 +333,7 @@
 //
 // NOTE: This bug isn't noticed on DUT, but seems to be frequent on ash/chrome
 // linux desktop builds (with ozone/x11 underneath).
-TEST_P(WaylandWindowDragControllerTest,
+TEST_F(WaylandWindowDragControllerTest,
        DragAndDropWithExtraneousPointerEnterEvent_TOUCH) {
   // Init and open |target_window|.
   PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
@@ -384,7 +384,7 @@
 // 4. Drag pointer to outside the window and release the mouse button, and make
 //    sure RELEASE and EXIT mouse events are delivered even when the drop
 //    happens outside the bounds of any surface.
-TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
+TEST_F(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
   // Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
   EXPECT_EQ(gfx::kNullAcceleratedWidget,
@@ -480,7 +480,7 @@
 // 5. Drag it a bit more (within window 2) and then calls EndMoveLoop(),
 //    emulating a window snap), and then
 // 6. With the window in "snapped" state, drag it further and then drop.
-TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
+TEST_F(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
   // Init and open |target_window|.
   PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
   properties.type = PlatformWindowType::kWindow;
@@ -635,7 +635,7 @@
 // 5. Drag it a bit more (within window 2) and then calls EndMoveLoop(),
 //    emulating a window snap), and then
 // 6. With the window in "snapped" state, drag it further and then drop.
-TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop_TOUCH) {
+TEST_F(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop_TOUCH) {
   // Init and open |target_window|.
   PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
   properties.type = PlatformWindowType::kWindow;
@@ -760,7 +760,7 @@
 
 // Verifies wl_data_device::leave events are properly handled and propagated
 // while in window dragging "attached" mode.
-TEST_P(WaylandWindowDragControllerTest, DragExitAttached) {
+TEST_F(WaylandWindowDragControllerTest, DragExitAttached) {
   // Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
   EXPECT_EQ(gfx::kNullAcceleratedWidget,
@@ -804,7 +804,7 @@
 
 // Verifies wl_data_device::leave events are properly handled and propagated
 // while in window dragging "attached" mode.
-TEST_P(WaylandWindowDragControllerTest, DragExitAttached_TOUCH) {
+TEST_F(WaylandWindowDragControllerTest, DragExitAttached_TOUCH) {
   // Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
   EXPECT_EQ(gfx::kNullAcceleratedWidget,
@@ -839,7 +839,7 @@
 
 using BoundsChange = PlatformWindowDelegate::BoundsChange;
 
-TEST_P(WaylandWindowDragControllerTest, RestoreDuringWindowDragSession) {
+TEST_F(WaylandWindowDragControllerTest, RestoreDuringWindowDragSession) {
   const gfx::Rect original_bounds = window_->GetBoundsInDIP();
   wl::ScopedWlArray states({XDG_TOPLEVEL_STATE_ACTIVATED});
 
@@ -885,7 +885,7 @@
 //
 // Verifies window drag controller is resistant to issues such as
 // https://crbug.com/1148021.
-TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) {
+TEST_F(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) {
   // Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
   EXPECT_EQ(gfx::kNullAcceleratedWidget,
@@ -1018,7 +1018,7 @@
 }
 
 // Regression test for https://crbug.com/1169446.
-TEST_P(WaylandWindowDragControllerTest, MotionEventsSkippedWhileReattaching) {
+TEST_F(WaylandWindowDragControllerTest, MotionEventsSkippedWhileReattaching) {
   auto* dragged_window = window_.get();
   EXPECT_TRUE(dragged_window);
 
@@ -1084,7 +1084,7 @@
 
 // Test that cursor position is using DIP coordinates and is updated correctly
 // on DragMotion event.
-TEST_P(WaylandWindowDragControllerTest, CursorPositionIsUpdatedOnMotion) {
+TEST_F(WaylandWindowDragControllerTest, CursorPositionIsUpdatedOnMotion) {
   const gfx::Rect output_bounds(0, 0, 1920, 1080);
   PostToServerAndWait([output_bounds](wl::TestWaylandServerThread* server) {
     // Configure the first output with scale 1.
@@ -1202,7 +1202,7 @@
 // after quitting the move loop. Regression test for crbug.com/1267791 and
 // should be caught in both regular and ASAN builds, where more details about
 // the actual memory issue is provided.
-TEST_P(WaylandWindowDragControllerTest,
+TEST_F(WaylandWindowDragControllerTest,
        HandleDraggedWindowDestructionAfterMoveLoop) {
   // 1. Ensure there is no window currently focused
   EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
@@ -1247,7 +1247,7 @@
 
 // Ensure no memory issues happen when the dragged and/or events grabber windows
 // get destroyed while the move loop is running.
-TEST_P(WaylandWindowDragControllerTest,
+TEST_F(WaylandWindowDragControllerTest,
        HandleWindowsDestructionDuringMoveLoop) {
   // 1. Send some initial pointer events to |window_|.
   ASSERT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow());
@@ -1332,7 +1332,7 @@
 //    Wayland Compositor.
 //
 //  Regression test for https://crbug.com/1366504.
-TEST_P(WaylandWindowDragControllerTest, ExtendedDragUnavailable) {
+TEST_F(WaylandWindowDragControllerTest, ExtendedDragUnavailable) {
   ASSERT_TRUE(GetWmMoveLoopHandler(*window_));
   ASSERT_TRUE(GetWaylandExtension(*window_));
   drag_controller()->set_extended_drag_available_for_testing(false);
@@ -1391,8 +1391,4 @@
             window_manager()->GetCurrentPointerOrTouchFocusedWindow());
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandWindowDragControllerTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
index 96c044df..6fdd811 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_manager_unittests.cc
@@ -22,40 +22,21 @@
 
 }  // namespace
 
-class WaylandWindowManagerTest : public WaylandTest {
+class WaylandWindowManagerTest : public WaylandTestSimple {
  public:
-  WaylandWindowManagerTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandWindowManagerTest(const WaylandWindowManagerTest&) = delete;
-  WaylandWindowManagerTest& operator=(const WaylandWindowManagerTest&) = delete;
-  ~WaylandWindowManagerTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     manager_ = connection_->wayland_window_manager();
     ASSERT_TRUE(manager_);
   }
 
  protected:
-  std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
-      PlatformWindowType type,
-      const gfx::Rect bounds,
-      MockPlatformWindowDelegate* delegate) {
-    PlatformWindowInitProperties properties;
-    properties.bounds = bounds;
-    properties.type = type;
-    auto window = WaylandWindow::Create(delegate, connection_.get(),
-                                        std::move(properties));
-    if (window)
-      window->Show(false);
-    return window;
-  }
-
   raw_ptr<WaylandWindowManager> manager_ = nullptr;
 };
 
-TEST_P(WaylandWindowManagerTest, GetWindow) {
-  MockPlatformWindowDelegate delegate;
+TEST_F(WaylandWindowManagerTest, GetWindow) {
+  MockWaylandPlatformWindowDelegate delegate;
 
   auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
                                                kDefaultBounds, &delegate);
@@ -72,8 +53,8 @@
   EXPECT_FALSE(manager_->GetWindow(window1_widget));
 }
 
-TEST_P(WaylandWindowManagerTest, GetWindowWithLargestBounds) {
-  MockPlatformWindowDelegate delegate;
+TEST_F(WaylandWindowManagerTest, GetWindowWithLargestBounds) {
+  MockWaylandPlatformWindowDelegate delegate;
 
   auto window1 = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
                                                kDefaultBounds, &delegate);
@@ -85,8 +66,8 @@
   EXPECT_TRUE(window2.get() == manager_->GetWindowWithLargestBounds());
 }
 
-TEST_P(WaylandWindowManagerTest, GetCurrentFocusedWindow) {
-  MockPlatformWindowDelegate delegate;
+TEST_F(WaylandWindowManagerTest, GetCurrentFocusedWindow) {
+  MockWaylandPlatformWindowDelegate delegate;
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
@@ -136,8 +117,8 @@
   EXPECT_FALSE(manager_->GetCurrentPointerFocusedWindow());
 }
 
-TEST_P(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) {
-  MockPlatformWindowDelegate delegate;
+TEST_F(WaylandWindowManagerTest, GetCurrentKeyboardFocusedWindow) {
+  MockWaylandPlatformWindowDelegate delegate;
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
@@ -181,8 +162,8 @@
   EXPECT_FALSE(manager_->GetCurrentKeyboardFocusedWindow());
 }
 
-TEST_P(WaylandWindowManagerTest, GetAllWindows) {
-  MockPlatformWindowDelegate delegate;
+TEST_F(WaylandWindowManagerTest, GetAllWindows) {
+  MockWaylandPlatformWindowDelegate delegate;
 
   // There is a default window created by WaylandTest.
   auto windows = manager_->GetAllWindows();
@@ -200,8 +181,4 @@
   EXPECT_EQ(2u, windows.size());
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandWindowManagerTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index e86931e..e6f4fcf1 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -151,11 +151,10 @@
 
 }  // namespace
 
-class WaylandWindowTest : public WaylandTest {
+class WaylandWindowTest : public WaylandTestSimple {
  public:
   WaylandWindowTest()
-      : WaylandTest(WaylandTest::TestServerMode::kAsync),
-        test_mouse_event_(ET_MOUSE_PRESSED,
+      : test_mouse_event_(ET_MOUSE_PRESSED,
                           gfx::Point(10, 15),
                           gfx::Point(10, 15),
                           ui::EventTimeStampFromSeconds(123456),
@@ -164,9 +163,10 @@
 
   WaylandWindowTest(const WaylandWindowTest&) = delete;
   WaylandWindowTest& operator=(const WaylandWindowTest&) = delete;
+  ~WaylandWindowTest() override = default;
 
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     surface_id_ = window_->root_surface()->get_surface_id();
     PostToServerAndWait(
@@ -189,25 +189,6 @@
         });
   }
 
-  std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
-      PlatformWindowType type,
-      gfx::AcceleratedWidget parent_widget,
-      const gfx::Rect& bounds,
-      MockWaylandPlatformWindowDelegate* delegate) {
-    PlatformWindowInitProperties properties;
-    // TODO(msisov): use a fancy method to calculate position of a popup window.
-    properties.bounds = bounds;
-    properties.type = type;
-    properties.parent_widget = parent_widget;
-
-    auto window = delegate->CreateWaylandWindow(
-        connection_.get(), std::move(properties), true, true);
-
-    if (window)
-      window->Show(false);
-    return window;
-  }
-
   void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) {
     hit_tests->push_back(static_cast<int>(HTBOTTOM));
     hit_tests->push_back(static_cast<int>(HTBOTTOMLEFT));
@@ -329,7 +310,7 @@
   MouseEvent test_mouse_event_;
 };
 
-TEST_P(WaylandWindowTest, SetTitle) {
+TEST_F(WaylandWindowTest, SetTitle) {
   window_->SetTitle(u"hello");
   PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) {
     auto* surface = server->GetObject<wl::MockSurface>(id);
@@ -338,7 +319,7 @@
   });
 }
 
-TEST_P(WaylandWindowTest, UpdateVisualSizeConfiguresWaylandWindow) {
+TEST_F(WaylandWindowTest, UpdateVisualSizeConfiguresWaylandWindow) {
   constexpr gfx::Rect kNormalBounds{500, 300};
   window_->set_update_visual_size_immediately_for_testing(false);
 
@@ -378,7 +359,7 @@
 
 // WaylandSurface state changes are sent to wayland compositor when
 // ApplyPendingState() is called.
-TEST_P(WaylandWindowTest, ApplyPendingStatesAndCommit) {
+TEST_F(WaylandWindowTest, ApplyPendingStatesAndCommit) {
   window_->set_update_visual_size_immediately_for_testing(false);
   window_->set_apply_pending_state_on_update_visual_size_for_testing(false);
 
@@ -416,7 +397,7 @@
 // Checks that decoration insets do not change final bounds and that
 // WaylandToplevelWindow::HandleToplevelConfigure does correct rounding when
 // some sides of insets divides by 2 with remainder.
-TEST_P(WaylandWindowTest, SetDecorationInsets) {
+TEST_F(WaylandWindowTest, SetDecorationInsets) {
   constexpr gfx::Rect kNormalBounds{956, 556};
   constexpr auto kHiDpiScale = 2;
   const gfx::Size kHiDpiSize =
@@ -519,7 +500,7 @@
 
 // Checks that when the window gets some of its edges tiled, it notifies the
 // delegate appropriately.
-TEST_P(WaylandWindowTest, HandleTiledEdges) {
+TEST_F(WaylandWindowTest, HandleTiledEdges) {
   constexpr gfx::Rect kWindowBounds{800, 600};
 
   struct {
@@ -559,7 +540,7 @@
   }
 }
 
-TEST_P(WaylandWindowTest, DisregardUnpassedWindowConfigure) {
+TEST_F(WaylandWindowTest, DisregardUnpassedWindowConfigure) {
   constexpr gfx::Rect kNormalBounds1{500, 300};
   constexpr gfx::Rect kNormalBounds2{800, 600};
   constexpr gfx::Rect kNormalBounds3{700, 400};
@@ -599,7 +580,7 @@
   window_->UpdateVisualSize(kNormalBounds3.size());
 }
 
-TEST_P(WaylandWindowTest, MismatchUpdateVisualSize) {
+TEST_F(WaylandWindowTest, MismatchUpdateVisualSize) {
   constexpr gfx::Rect kNormalBounds1{500, 300};
   constexpr gfx::Rect kNormalBounds2{800, 600};
   constexpr gfx::Rect kNormalBounds3{700, 400};
@@ -629,7 +610,7 @@
   window_->UpdateVisualSize({100, 100});
 }
 
-TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) {
+TEST_F(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) {
   constexpr gfx::Rect kNormalBounds1{500, 300};
   constexpr gfx::Rect kNormalBounds2{800, 600};
   constexpr gfx::Rect kNormalBounds3{700, 400};
@@ -680,7 +661,7 @@
   window_->UpdateVisualSize(kNormalBounds3.size());
 }
 
-TEST_P(WaylandWindowTest, MaximizeAndRestore) {
+TEST_F(WaylandWindowTest, MaximizeAndRestore) {
   constexpr gfx::Rect kNormalBounds{500, 300};
   constexpr gfx::Rect kMaximizedBounds{800, 600};
 
@@ -777,7 +758,7 @@
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 
 // Tests the event sequence where a minimize request is initiated by the client.
-TEST_P(WaylandWindowTest, ClientInitiatedMinimize) {
+TEST_F(WaylandWindowTest, ClientInitiatedMinimize) {
   wl::ScopedWlArray states({});
 
   // Make sure the window is initialized to normal state from the beginning.
@@ -805,7 +786,7 @@
 
 // Tests the event sequence where a minimize event is initiated by the server
 // and the client's window is in a non-minimized state.
-TEST_P(WaylandWindowTest, ServerInitiatedMinimize) {
+TEST_F(WaylandWindowTest, ServerInitiatedMinimize) {
   wl::ScopedWlArray states({});
 
   // Make sure the window is initialized to normal state from the beginning.
@@ -823,7 +804,7 @@
 
 #else
 
-TEST_P(WaylandWindowTest, Minimize) {
+TEST_F(WaylandWindowTest, Minimize) {
   wl::ScopedWlArray states({});
 
   // Make sure the window is initialized to normal state from the beginning.
@@ -868,7 +849,7 @@
 
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
-TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
+TEST_F(WaylandWindowTest, SetFullscreenAndRestore) {
   // Make sure the window is initialized to normal state from the beginning.
   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
 
@@ -907,7 +888,7 @@
   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
 }
 
-TEST_P(WaylandWindowTest, StartWithFullscreen) {
+TEST_F(WaylandWindowTest, StartWithFullscreen) {
   MockWaylandPlatformWindowDelegate delegate;
   PlatformWindowInitProperties properties;
   properties.bounds = gfx::Rect(100, 100);
@@ -965,7 +946,7 @@
   Mock::VerifyAndClearExpectations(&delegate);
 }
 
-TEST_P(WaylandWindowTest, StartMaximized) {
+TEST_F(WaylandWindowTest, StartMaximized) {
   MockWaylandPlatformWindowDelegate delegate;
   PlatformWindowInitProperties properties;
   properties.bounds = gfx::Rect(100, 100);
@@ -1026,7 +1007,7 @@
   Mock::VerifyAndClearExpectations(&delegate);
 }
 
-TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
+TEST_F(WaylandWindowTest, CompositorSideStateChanges) {
   // Real insets used by default on HiDPI.
   const auto kInsets = gfx::Insets::TLBR(38, 44, 55, 44);
   const auto kNormalBounds = window_->GetBoundsInDIP();
@@ -1150,7 +1131,7 @@
   SendConfigureEvent(surface_id_, {0, 0}, states);
 }
 
-TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
+TEST_F(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
   constexpr gfx::Rect kNormalBounds{500, 300};
   constexpr gfx::Rect kMaximizedBounds{800, 600};
 
@@ -1224,7 +1205,7 @@
   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
 }
 
-TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
+TEST_F(WaylandWindowTest, RestoreBoundsAfterMaximize) {
   const gfx::Rect current_bounds = window_->GetBoundsInDIP();
 
   wl::ScopedWlArray states = InitializeWlArrayWithActivatedState();
@@ -1263,7 +1244,7 @@
   EXPECT_EQ(restored_bounds, gfx::Rect());
 }
 
-TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
+TEST_F(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
   const gfx::Rect current_bounds = window_->GetBoundsInDIP();
 
   wl::ScopedWlArray states = InitializeWlArrayWithActivatedState();
@@ -1303,7 +1284,7 @@
   EXPECT_EQ(restored_bounds, gfx::Rect());
 }
 
-TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
+TEST_F(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
   const gfx::Rect current_bounds = window_->GetBoundsInDIP();
 
   wl::ScopedWlArray states = InitializeWlArrayWithActivatedState();
@@ -1359,7 +1340,7 @@
   EXPECT_EQ(restored_bounds, gfx::Rect());
 }
 
-TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
+TEST_F(WaylandWindowTest, SendsBoundsOnRequest) {
   const gfx::Rect initial_bounds = window_->GetBoundsInDIP();
 
   const gfx::Rect new_bounds =
@@ -1395,7 +1376,7 @@
   EXPECT_EQ(restored_bounds, gfx::Rect());
 }
 
-TEST_P(WaylandWindowTest, UpdateWindowRegion) {
+TEST_F(WaylandWindowTest, UpdateWindowRegion) {
   // Change bounds.
   const gfx::Rect initial_bounds = window_->GetBoundsInDIP();
   const gfx::Rect new_bounds =
@@ -1460,7 +1441,7 @@
       });
 }
 
-TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) {
+TEST_F(WaylandWindowTest, CanDispatchMouseEventFocus) {
   // SetPointerFocusedWindow requires a WaylandPointer.
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
@@ -1472,7 +1453,7 @@
   EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_));
 }
 
-TEST_P(WaylandWindowTest, SetCursorUsesZcrCursorShapesForCommonTypes) {
+TEST_F(WaylandWindowTest, SetCursorUsesZcrCursorShapesForCommonTypes) {
   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
 
   // Verify some commonly-used cursors.
@@ -1495,7 +1476,7 @@
   window_->SetCursor(ibeam_cursor.get());
 }
 
-TEST_P(WaylandWindowTest, SetCursorCallsZcrCursorShapesOncePerCursor) {
+TEST_F(WaylandWindowTest, SetCursorCallsZcrCursorShapesOncePerCursor) {
   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
   auto hand_cursor = base::MakeRefCounted<BitmapCursor>(
       mojom::CursorType::kHand, kDefaultCursorScale);
@@ -1505,7 +1486,7 @@
   window_->SetCursor(hand_cursor.get());
 }
 
-TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForNoneCursor) {
+TEST_F(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForNoneCursor) {
   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
   EXPECT_CALL(*mock_cursor_shapes, SetCursorShape(_)).Times(0);
   auto none_cursor = base::MakeRefCounted<BitmapCursor>(
@@ -1513,7 +1494,7 @@
   window_->SetCursor(none_cursor.get());
 }
 
-TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForCustomCursors) {
+TEST_F(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForCustomCursors) {
   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
 
   // Custom cursors require bitmaps, so they do not use server-side cursors.
@@ -1528,7 +1509,7 @@
   *ptr = arg0->Clone();
 }
 
-TEST_P(WaylandWindowTest, DispatchEvent) {
+TEST_F(WaylandWindowTest, DispatchEvent) {
   std::unique_ptr<Event> event;
   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
   window_->DispatchEvent(&test_mouse_event_);
@@ -1544,7 +1525,7 @@
             test_mouse_event_.changed_button_flags());
 }
 
-TEST_P(WaylandWindowTest, ConfigureEvent) {
+TEST_F(WaylandWindowTest, ConfigureEvent) {
   wl::ScopedWlArray states({});
 
   // The surface must react on each configure event and send bounds to its
@@ -1582,7 +1563,7 @@
   SendConfigureEvent(surface_id_, kNewSize, states, ++serial);
 }
 
-TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
+TEST_F(WaylandWindowTest, ConfigureEventWithNulledSize) {
   wl::ScopedWlArray states({});
 
   // |xdg_surface| must receive the following calls in both xdg_shell_v5 and
@@ -1602,7 +1583,7 @@
   SendConfigureEvent(surface_id_, {0, 0}, states, 14u);
 }
 
-TEST_P(WaylandWindowTest, OnActivationChanged) {
+TEST_F(WaylandWindowTest, OnActivationChanged) {
   uint32_t serial = 0;
 
   // Deactivate the surface.
@@ -1620,11 +1601,11 @@
   SendConfigureEvent(surface_id_, {0, 0}, states, ++serial);
 }
 
-TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) {
+TEST_F(WaylandWindowTest, OnAcceleratedWidgetDestroy) {
   window_.reset();
 }
 
-TEST_P(WaylandWindowTest, CanCreateMenuWindow) {
+TEST_F(WaylandWindowTest, CanCreateMenuWindow) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillRepeatedly(Return(MenuType::kRootContextMenu));
@@ -1640,8 +1621,7 @@
   SetPointerFocusedWindow(window_.get());
 
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10), &menu_window_delegate);
   EXPECT_TRUE(menu_window);
 
   SetPointerFocusedWindow(window_.get());
@@ -1650,19 +1630,17 @@
   // Given that there is no parent passed and we don't have any focused windows,
   // Wayland must still create a window.
   menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10), &menu_window_delegate);
   EXPECT_TRUE(menu_window);
 
   window_->set_touch_focus(true);
 
   menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget, gfx::Rect(10, 10),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10), &menu_window_delegate);
   EXPECT_TRUE(menu_window);
 }
 
-TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) {
+TEST_F(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   gfx::AcceleratedWidget menu_window_widget;
   EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
@@ -1670,27 +1648,27 @@
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillRepeatedly(Return(MenuType::kRootContextMenu));
 
-  std::unique_ptr<WaylandWindow> menu_window =
-      CreateWaylandWindowWithParams(PlatformWindowType::kMenu, widget_,
-                                    gfx::Rect(10, 10), &menu_window_delegate);
+  std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+      PlatformWindowType::kMenu, gfx::Rect(10, 10), &menu_window_delegate,
+      widget_);
   EXPECT_TRUE(menu_window);
   ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget);
 
   MockWaylandPlatformWindowDelegate nested_menu_window_delegate;
   std::unique_ptr<WaylandWindow> nested_menu_window =
       CreateWaylandWindowWithParams(
-          PlatformWindowType::kMenu, menu_window_widget,
-          gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
+          PlatformWindowType::kMenu, gfx::Rect(20, 0, 10, 10),
+          &nested_menu_window_delegate, menu_window_widget);
   EXPECT_TRUE(nested_menu_window);
 }
 
-TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) {
+TEST_F(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, widget_, gfx::Rect(10, 10, 10, 10),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10, 10, 10),
+      &menu_window_delegate, widget_);
   EXPECT_TRUE(menu_window);
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -1766,8 +1744,8 @@
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> nested_menu_window =
       CreateWaylandWindowWithParams(
-          PlatformWindowType::kMenu, menu_window->GetWidget(),
-          gfx::Rect(15, 18, 10, 10), &nested_menu_window_delegate);
+          PlatformWindowType::kMenu, gfx::Rect(15, 18, 10, 10),
+          &nested_menu_window_delegate, menu_window->GetWidget());
   EXPECT_TRUE(nested_menu_window);
 
   SetPointerFocusedWindow(nested_menu_window.get());
@@ -1802,7 +1780,7 @@
 // Verify that located events are translated correctly when the windows have
 // geometry with non-zero offset.
 // See https://crbug.com/1292486.
-TEST_P(WaylandWindowTest, ConvertEventToTarget) {
+TEST_F(WaylandWindowTest, ConvertEventToTarget) {
   // This first section repeats a part of SetDecorationInsets that sets
   // decoration insets and ensures that they have been applied.
   constexpr gfx::Rect kMainWindowBounds{956, 556};
@@ -1831,7 +1809,7 @@
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, widget_, kMenuBounds, &menu_window_delegate);
+      PlatformWindowType::kMenu, kMenuBounds, &menu_window_delegate, widget_);
   EXPECT_TRUE(menu_window);
 
   // Now translate the event located at (0, 0) in the parent window into the
@@ -1854,22 +1832,22 @@
 // Tests that the event grabber gets the events processed by its toplevel parent
 // window iff they belong to the same "family". Otherwise, events mustn't be
 // rerouted from another toplevel window to the event grabber.
-TEST_P(WaylandWindowTest,
+TEST_F(WaylandWindowTest,
        DispatchesLocatedEventsToCapturedWindowInTheSameStack) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, widget_, gfx::Rect(30, 40, 20, 50),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(30, 40, 20, 50),
+      &menu_window_delegate, widget_);
   EXPECT_TRUE(menu_window);
 
   // Second toplevel window has the same bounds as the |window_|.
   MockWaylandPlatformWindowDelegate toplevel_window2_delegate;
   std::unique_ptr<WaylandWindow> toplevel_window2 =
-      CreateWaylandWindowWithParams(
-          PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
-          window_->GetBoundsInDIP(), &toplevel_window2_delegate);
+      CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
+                                    window_->GetBoundsInDIP(),
+                                    &toplevel_window2_delegate);
   EXPECT_TRUE(toplevel_window2);
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -1930,13 +1908,13 @@
   EXPECT_EQ(event->AsLocatedEvent()->location(), gfx::Point(10, 20));
 }
 
-TEST_P(WaylandWindowTest, DispatchesKeyboardEventToToplevelWindow) {
+TEST_F(WaylandWindowTest, DispatchesKeyboardEventToToplevelWindow) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, widget_, gfx::Rect(10, 10, 10, 10),
-      &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10, 10, 10),
+      &menu_window_delegate, widget_);
   EXPECT_TRUE(menu_window);
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -2001,7 +1979,7 @@
 
 // Tests that event is processed by the surface that has the focus. More
 // extensive tests are located in wayland touch/keyboard/pointer unittests.
-TEST_P(WaylandWindowTest, CanDispatchEvent) {
+TEST_F(WaylandWindowTest, CanDispatchEvent) {
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   gfx::AcceleratedWidget menu_window_widget;
   EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
@@ -2009,9 +1987,9 @@
   EXPECT_CALL(menu_window_delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
 
-  std::unique_ptr<WaylandWindow> menu_window =
-      CreateWaylandWindowWithParams(PlatformWindowType::kMenu, widget_,
-                                    gfx::Rect(10, 10), &menu_window_delegate);
+  std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+      PlatformWindowType::kMenu, gfx::Rect(10, 10), &menu_window_delegate,
+      widget_);
   EXPECT_TRUE(menu_window);
 
   MockWaylandPlatformWindowDelegate nested_menu_window_delegate;
@@ -2019,8 +1997,8 @@
       .WillOnce(Return(MenuType::kRootContextMenu));
   std::unique_ptr<WaylandWindow> nested_menu_window =
       CreateWaylandWindowWithParams(
-          PlatformWindowType::kMenu, menu_window_widget,
-          gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
+          PlatformWindowType::kMenu, gfx::Rect(20, 0, 10, 10),
+          &nested_menu_window_delegate, menu_window_widget);
   EXPECT_TRUE(nested_menu_window);
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -2140,7 +2118,7 @@
       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
 }
 
-TEST_P(WaylandWindowTest, DispatchWindowMove) {
+TEST_F(WaylandWindowTest, DispatchWindowMove) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
                               WL_SEAT_CAPABILITY_POINTER);
@@ -2168,7 +2146,7 @@
 }
 
 // Makes sure hit tests are converted into right edges.
-TEST_P(WaylandWindowTest, DispatchWindowResize) {
+TEST_F(WaylandWindowTest, DispatchWindowResize) {
   std::vector<int> hit_test_values;
   InitializeWithSupportedHitTestValues(&hit_test_values);
 
@@ -2206,7 +2184,7 @@
   }
 }
 
-TEST_P(WaylandWindowTest, ToplevelWindowUpdateWindowScale) {
+TEST_F(WaylandWindowTest, ToplevelWindowUpdateWindowScale) {
   VerifyAndClearExpectations();
 
   // Surface scale must be 1 when no output has been entered by the window.
@@ -2268,7 +2246,7 @@
   EXPECT_EQ(gfx::Rect(800, 600), window_->GetBoundsInDIP());
 }
 
-TEST_P(WaylandWindowTest, WaylandPopupSurfaceScale) {
+TEST_F(WaylandWindowTest, WaylandPopupSurfaceScale) {
   VerifyAndClearExpectations();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -2307,7 +2285,7 @@
     SetPointerFocusedWindow(window_.get());
     gfx::Rect wayland_popup_bounds(15, 15, 10, 10);
     auto wayland_popup = CreateWaylandWindowWithParams(
-        type, window_->GetWidget(), wayland_popup_bounds, &delegate_);
+        type, wayland_popup_bounds, &delegate_, window_->GetWidget());
     EXPECT_TRUE(wayland_popup);
     wayland_popup->Show(false);
 
@@ -2359,7 +2337,7 @@
 // PlatformWindowProperties using buffer scale it's going to use that the client
 // is not able to determine before PlatformWindow is created. See
 // WaylandPopup::OnInitialize for more details.
-TEST_P(WaylandWindowTest, WaylandPopupInitialBufferScale) {
+TEST_F(WaylandWindowTest, WaylandPopupInitialBufferScale) {
   VerifyAndClearExpectations();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -2431,9 +2409,8 @@
         gfx::Rect wayland_popup_bounds = transform.MapRect(bounds_dip);
 
         std::unique_ptr<WaylandWindow> wayland_popup =
-            CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                          window_->GetWidget(), bounds_dip,
-                                          &delegate_);
+            CreateWaylandWindowWithParams(PlatformWindowType::kMenu, bounds_dip,
+                                          &delegate_, window_->GetWidget());
         EXPECT_TRUE(wayland_popup);
 
         wayland_popup->Show(false);
@@ -2462,7 +2439,7 @@
   }
 }
 
-TEST_P(WaylandWindowTest, WaylandPopupInitialBufferUsesParentScale) {
+TEST_F(WaylandWindowTest, WaylandPopupInitialBufferUsesParentScale) {
   VerifyAndClearExpectations();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -2499,7 +2476,7 @@
       gfx::ScaleToCeiledSize(kBoundsDip.size(), 2);
 
   std::unique_ptr<WaylandWindow> wayland_popup = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, window_->GetWidget(), kBoundsDip, &delegate_);
+      PlatformWindowType::kMenu, kBoundsDip, &delegate_, window_->GetWidget());
   EXPECT_TRUE(wayland_popup);
 
   wayland_popup->Show(false);
@@ -2519,7 +2496,7 @@
 // Tests that a WaylandWindow uses the entered output with largest scale
 // factor as the preferred output. If scale factors are equal, the very first
 // entered display is used.
-TEST_P(WaylandWindowTest, GetPreferredOutput) {
+TEST_F(WaylandWindowTest, GetPreferredOutput) {
   VerifyAndClearExpectations();
 
   // Buffer scale must be 1 when no output has been entered by the window.
@@ -2649,7 +2626,7 @@
   EXPECT_EQ(window_->GetPreferredEnteredOutputId(), output1_id);
 }
 
-TEST_P(WaylandWindowTest, GetChildrenPreferredOutput) {
+TEST_F(WaylandWindowTest, GetChildrenPreferredOutput) {
   VerifyAndClearExpectations();
 
   // Buffer scale must be 1 when no output has been entered by the window.
@@ -2657,8 +2634,8 @@
 
   MockWaylandPlatformWindowDelegate menu_window_delegate;
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, window_->GetWidget(),
-      gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
+      PlatformWindowType::kMenu, gfx::Rect(10, 10, 10, 10),
+      &menu_window_delegate, window_->GetWidget());
 
   menu_window->Show(false);
 
@@ -2764,7 +2741,7 @@
 
 // Tests that xdg_popup is configured with default anchor properties and bounds
 // if delegate doesn't have anchor properties set.
-TEST_P(WaylandWindowTest, PopupPassesDefaultAnchorInformation) {
+TEST_F(WaylandWindowTest, PopupPassesDefaultAnchorInformation) {
   PopupPosition menu_window_positioner, nested_menu_window_positioner;
 
   menu_window_positioner = {gfx::Rect(439, 46, 1, 1), gfx::Size(287, 409),
@@ -2790,8 +2767,8 @@
   gfx::Rect menu_window_bounds(gfx::Point(439, 46),
                                menu_window_positioner.size);
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, toplevel_window->GetWidget(),
-      menu_window_bounds, &menu_window_delegate);
+      PlatformWindowType::kMenu, menu_window_bounds, &menu_window_delegate,
+      toplevel_window->GetWidget());
   EXPECT_TRUE(menu_window);
 
   VerifyXdgPopupPosition(menu_window.get(), menu_window_positioner);
@@ -2809,8 +2786,8 @@
                                       nested_menu_window_positioner.size);
   std::unique_ptr<WaylandWindow> nested_menu_window =
       CreateWaylandWindowWithParams(
-          PlatformWindowType::kMenu, menu_window->GetWidget(),
-          nested_menu_window_bounds, &nested_menu_window_delegate);
+          PlatformWindowType::kMenu, nested_menu_window_bounds,
+          &nested_menu_window_delegate, menu_window->GetWidget());
   EXPECT_TRUE(nested_menu_window);
 
   VerifyXdgPopupPosition(nested_menu_window.get(),
@@ -2819,7 +2796,7 @@
 
 // Tests that xdg_popup is configured with anchor properties received from
 // delegate.
-TEST_P(WaylandWindowTest, PopupPassesSetAnchorInformation) {
+TEST_F(WaylandWindowTest, PopupPassesSetAnchorInformation) {
   PopupPosition menu_window_positioner, nested_menu_window_positioner;
 
   menu_window_positioner = {gfx::Rect(468, 46, 28, 28), gfx::Size(320, 404),
@@ -2848,8 +2825,8 @@
   gfx::Rect menu_window_bounds(gfx::Point(176, 74),
                                menu_window_positioner.size);
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, toplevel_window->GetWidget(),
-      menu_window_bounds, &menu_window_delegate);
+      PlatformWindowType::kMenu, menu_window_bounds, &menu_window_delegate,
+      toplevel_window->GetWidget());
   EXPECT_TRUE(menu_window);
 
   VerifyXdgPopupPosition(menu_window.get(), menu_window_positioner);
@@ -2868,15 +2845,15 @@
                                       nested_menu_window_positioner.size);
   std::unique_ptr<WaylandWindow> nested_menu_window =
       CreateWaylandWindowWithParams(
-          PlatformWindowType::kMenu, menu_window->GetWidget(),
-          nested_menu_window_bounds, &nested_menu_window_delegate);
+          PlatformWindowType::kMenu, nested_menu_window_bounds,
+          &nested_menu_window_delegate, menu_window->GetWidget());
   EXPECT_TRUE(nested_menu_window);
 
   VerifyXdgPopupPosition(nested_menu_window.get(),
                          nested_menu_window_positioner);
 }
 
-TEST_P(WaylandWindowTest, SetOpaqueRegion) {
+TEST_F(WaylandWindowTest, SetOpaqueRegion) {
   gfx::Rect new_bounds(500, 600);
   SkIRect rect =
       SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height());
@@ -2904,7 +2881,7 @@
       });
 }
 
-TEST_P(WaylandWindowTest, OnCloseRequest) {
+TEST_F(WaylandWindowTest, OnCloseRequest) {
   EXPECT_CALL(delegate_, OnCloseRequest());
 
   PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) {
@@ -2915,7 +2892,7 @@
   });
 }
 
-TEST_P(WaylandWindowTest, WaylandPopupSimpleParent) {
+TEST_F(WaylandWindowTest, WaylandPopupSimpleParent) {
   VerifyAndClearExpectations();
 
   EXPECT_CALL(delegate_, GetMenuType())
@@ -2924,8 +2901,8 @@
   // use focused window instead.
   gfx::Rect wayland_popup_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
   std::unique_ptr<WaylandWindow> wayland_popup = CreateWaylandWindowWithParams(
-      PlatformWindowType::kTooltip, window_->GetWidget(), wayland_popup_bounds,
-      &delegate_);
+      PlatformWindowType::kTooltip, wayland_popup_bounds, &delegate_,
+      window_->GetWidget());
   EXPECT_TRUE(wayland_popup);
 
   wayland_popup->Show(false);
@@ -2945,13 +2922,13 @@
   wayland_popup->Hide();
 }
 
-TEST_P(WaylandWindowTest, WaylandPopupNestedParent) {
+TEST_F(WaylandWindowTest, WaylandPopupNestedParent) {
   VerifyAndClearExpectations();
 
   gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100));
   auto menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds, &delegate_,
+      window_->GetWidget());
   EXPECT_TRUE(menu_window);
 
   VerifyAndClearExpectations();
@@ -2963,8 +2940,8 @@
     gfx::Rect nested_wayland_popup_bounds(gfx::Point(15, 15),
                                           gfx::Size(10, 10));
     auto nested_wayland_popup =
-        CreateWaylandWindowWithParams(type, menu_window->GetWidget(),
-                                      nested_wayland_popup_bounds, &delegate_);
+        CreateWaylandWindowWithParams(type, nested_wayland_popup_bounds,
+                                      &delegate_, menu_window->GetWidget());
     EXPECT_TRUE(nested_wayland_popup);
 
     VerifyAndClearExpectations();
@@ -2994,7 +2971,7 @@
 // Tests that size constraints returned by the `ui::PlatformWindowDelegate` are
 // obeyed by the window when its bounds are set internally via its
 // SetBoundsInDIP() implementation.
-TEST_P(WaylandWindowTest, SizeConstraintsInternal) {
+TEST_F(WaylandWindowTest, SizeConstraintsInternal) {
   constexpr gfx::Size kMinSize{100, 100};
   constexpr gfx::Size kMaxSize{300, 300};
 
@@ -3024,7 +3001,7 @@
 // Tests that size constraints returned by the `ui::PlatformWindowDelegate` are
 // obeyed by the window when its bounds are set externally via the configure
 // event sent by the compositor.
-TEST_P(WaylandWindowTest, SizeConstraintsExternal) {
+TEST_F(WaylandWindowTest, SizeConstraintsExternal) {
   constexpr gfx::Size kMinSize{100, 100};
   constexpr gfx::Size kMaxSize{300, 300};
 
@@ -3060,7 +3037,7 @@
   SendConfigureEvent(surface_id_, even_greater_bounds.size(), state);
 }
 
-TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) {
+TEST_F(WaylandWindowTest, OnSizeConstraintsChanged) {
   const bool kBooleans[] = {false, true};
   for (bool has_min_size : kBooleans) {
     for (bool has_max_size : kBooleans) {
@@ -3091,10 +3068,9 @@
   }
 }
 
-TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) {
+TEST_F(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) {
   MockWaylandPlatformWindowDelegate delegate;
   auto window = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
-                                              gfx::kNullAcceleratedWidget,
                                               gfx::Rect(100, 100), &delegate);
   ASSERT_TRUE(window);
 
@@ -3121,13 +3097,13 @@
   });
 }
 
-TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) {
+TEST_F(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) {
   MockWaylandPlatformWindowDelegate delegate;
   EXPECT_CALL(delegate, GetMenuType())
       .WillRepeatedly(Return(MenuType::kRootContextMenu));
   auto window = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                              window_->GetWidget(),
-                                              gfx::Rect(50, 50), &delegate);
+                                              gfx::Rect(50, 50), &delegate,
+                                              window_->GetWidget());
   ASSERT_TRUE(window);
 
   const uint32_t surface_id = window->root_surface()->get_surface_id();
@@ -3153,7 +3129,7 @@
   });
 }
 
-TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) {
+TEST_F(WaylandWindowTest, ReattachesBackgroundOnShow) {
   EXPECT_TRUE(connection_->buffer_manager_host());
 
   auto interface_ptr = connection_->buffer_manager_host()->BindInterface();
@@ -3175,7 +3151,6 @@
   // Create window.
   MockWaylandPlatformWindowDelegate delegate;
   auto window = CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
-                                              gfx::kNullAcceleratedWidget,
                                               gfx::Rect(100, 100), &delegate);
   ASSERT_TRUE(window);
   auto states = InitializeWlArrayWithActivatedState();
@@ -3245,7 +3220,7 @@
 
 // Tests that if the window gets hidden and shown again, the title, app id and
 // size constraints remain the same.
-TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
+TEST_F(WaylandWindowTest, SetsPropertiesOnShow) {
   constexpr char kAppId[] = "wayland_test";
   const std::u16string kTitle(u"WaylandWindowTest");
 
@@ -3322,7 +3297,7 @@
 
 // Tests that a popup window is created using the serial of button press
 // events as required by the Wayland protocol spec.
-TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) {
+TEST_F(WaylandWindowTest, CreatesPopupOnButtonPressSerial) {
   for (bool use_explicit_grab : {false, true}) {
     base::test::ScopedCommandLine command_line_;
     if (use_explicit_grab) {
@@ -3368,28 +3343,28 @@
     EXPECT_CALL(delegate, GetMenuType())
         .WillOnce(Return(MenuType::kRootContextMenu));
     auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                               window_->GetWidget(),
-                                               gfx::Rect(50, 50), &delegate);
+                                               gfx::Rect(50, 50), &delegate,
+                                               window_->GetWidget());
     ASSERT_TRUE(popup);
 
     const uint32_t surface_id = popup->root_surface()->get_surface_id();
     // Unfortunately, everything has to be captured as |use_explicit_grab| may
     // not be used and |maybe_unused| doesn't work with lambda captures.
     PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
-      auto* test_popup = GetTestXdgPopupByWindow(server, surface_id);
-      ASSERT_TRUE(test_popup);
+      auto* TEST_Fopup = GetTestXdgPopupByWindow(server, surface_id);
+      ASSERT_TRUE(TEST_Fopup);
 
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
       if (use_explicit_grab) {
-        EXPECT_NE(test_popup->grab_serial(), button_release_serial);
-        EXPECT_EQ(test_popup->grab_serial(), button_press_serial);
+        EXPECT_NE(TEST_Fopup->grab_serial(), button_release_serial);
+        EXPECT_EQ(TEST_Fopup->grab_serial(), button_press_serial);
       } else {
-        EXPECT_EQ(test_popup->grab_serial(), 0U);
+        EXPECT_EQ(TEST_Fopup->grab_serial(), 0U);
       }
 #else
       // crbug.com/1320528: Lacros uses explicit grab always.
-      EXPECT_NE(test_popup->grab_serial(), button_release_serial);
-      EXPECT_EQ(test_popup->grab_serial(), button_press_serial);
+      EXPECT_NE(TEST_Fopup->grab_serial(), button_release_serial);
+      EXPECT_EQ(TEST_Fopup->grab_serial(), button_press_serial);
 #endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
     });
   }
@@ -3397,7 +3372,7 @@
 
 // Tests that a popup window is created using the serial of touch down events
 // as required by the Wayland protocol spec.
-TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
+TEST_F(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
   for (bool use_explicit_grab : {false, true}) {
     base::test::ScopedCommandLine command_line_;
     if (use_explicit_grab) {
@@ -3439,16 +3414,16 @@
     EXPECT_CALL(delegate, GetMenuType())
         .WillRepeatedly(Return(MenuType::kRootContextMenu));
     auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                               window_->GetWidget(),
-                                               gfx::Rect(50, 50), &delegate);
+                                               gfx::Rect(50, 50), &delegate,
+                                               window_->GetWidget());
     ASSERT_TRUE(popup);
 
     const uint32_t surface_id = popup->root_surface()->get_surface_id();
     // Unfortunately, everything has to be captured as |use_explicit_grab| may
     // not be used and |maybe_unused| doesn't work with lambda captures.
     PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
-      auto* test_popup = GetTestXdgPopupByWindow(server, surface_id);
-      ASSERT_TRUE(test_popup);
+      auto* TEST_Fopup = GetTestXdgPopupByWindow(server, surface_id);
+      ASSERT_TRUE(TEST_Fopup);
       // crbug.com/1320528: Lacros uses explicit grab always.
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
       // Unless the use-wayland-explicit-grab switch is set, touch events
@@ -3456,7 +3431,7 @@
       // (latest) cannot be used, otherwise, some compositors may dismiss
       // popups.
       if (!use_explicit_grab)
-        EXPECT_EQ(test_popup->grab_serial(), 0U);
+        EXPECT_EQ(TEST_Fopup->grab_serial(), 0U);
 #endif
     });
 
@@ -3478,8 +3453,8 @@
     // Unfortunately, everything has to be captured as |use_explicit_grab| may
     // not be used and |maybe_unused| doesn't work with lambda captures.
     PostToServerAndWait([&](wl::TestWaylandServerThread* server) {
-      auto* test_popup = GetTestXdgPopupByWindow(server, surface_id);
-      ASSERT_TRUE(test_popup);
+      auto* TEST_Fopup = GetTestXdgPopupByWindow(server, surface_id);
+      ASSERT_TRUE(TEST_Fopup);
 
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
       uint32_t expected_serial = touch_down_serial;
@@ -3490,13 +3465,13 @@
         expected_serial = 0u;
       }
       if (use_explicit_grab) {
-        EXPECT_EQ(test_popup->grab_serial(), expected_serial);
+        EXPECT_EQ(TEST_Fopup->grab_serial(), expected_serial);
       } else {
-        EXPECT_EQ(test_popup->grab_serial(), 0U);
+        EXPECT_EQ(TEST_Fopup->grab_serial(), 0U);
       }
 #else
       // crbug.com/1320528: Lacros uses explicit grab always.
-      EXPECT_EQ(test_popup->grab_serial(), touch_down_serial);
+      EXPECT_EQ(TEST_Fopup->grab_serial(), touch_down_serial);
 #endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
     });
   }
@@ -3504,62 +3479,62 @@
 
 // Tests nested menu windows get the topmost window in the stack of windows
 // within the same family/tree.
-TEST_P(WaylandWindowTest, NestedPopupWindowsGetCorrectParent) {
+TEST_F(WaylandWindowTest, NestedPopupWindowsGetCorrectParent) {
   VerifyAndClearExpectations();
 
   gfx::Rect menu_window_bounds(gfx::Rect(10, 20, 20, 20));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds, &delegate_,
+      window_->GetWidget());
   EXPECT_TRUE(menu_window);
 
   EXPECT_TRUE(menu_window->parent_window() == window_.get());
 
   gfx::Rect menu_window_bounds2(gfx::Rect(20, 40, 30, 20));
   std::unique_ptr<WaylandWindow> menu_window2 = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, menu_window->GetWidget(), menu_window_bounds2,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds2, &delegate_,
+      menu_window->GetWidget());
   EXPECT_TRUE(menu_window2);
 
   EXPECT_TRUE(menu_window2->parent_window() == menu_window.get());
 
   gfx::Rect menu_window_bounds3(gfx::Rect(30, 40, 30, 20));
   std::unique_ptr<WaylandWindow> menu_window3 = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, menu_window2->GetWidget(), menu_window_bounds3,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds3, &delegate_,
+      menu_window2->GetWidget());
   EXPECT_TRUE(menu_window3);
 
   EXPECT_TRUE(menu_window3->parent_window() == menu_window2.get());
 
   gfx::Rect menu_window_bounds4(gfx::Rect(40, 40, 30, 20));
   std::unique_ptr<WaylandWindow> menu_window4 = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, menu_window3->GetWidget(), menu_window_bounds4,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds4, &delegate_,
+      menu_window3->GetWidget());
   EXPECT_TRUE(menu_window4);
 
   EXPECT_TRUE(menu_window4->parent_window() == menu_window3.get());
 }
 
-TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) {
+TEST_F(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) {
   // Create a popup window and verify the grab serial is not set.
   MockWaylandPlatformWindowDelegate delegate;
   EXPECT_CALL(delegate, GetMenuType())
       .WillOnce(Return(MenuType::kRootContextMenu));
   auto popup = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                             window_->GetWidget(),
-                                             gfx::Rect(50, 50), &delegate);
+                                             gfx::Rect(50, 50), &delegate,
+                                             window_->GetWidget());
   ASSERT_TRUE(popup);
 
   PostToServerAndWait([surface_id = popup->root_surface()->get_surface_id()](
                           wl::TestWaylandServerThread* server) {
-    auto* test_popup = GetTestXdgPopupByWindow(server, surface_id);
-    ASSERT_TRUE(test_popup);
-    EXPECT_EQ(test_popup->grab_serial(), 0u);
+    auto* TEST_Fopup = GetTestXdgPopupByWindow(server, surface_id);
+    ASSERT_TRUE(TEST_Fopup);
+    EXPECT_EQ(TEST_Fopup->grab_serial(), 0u);
   });
 }
 
 // Regression test for https://crbug.com/1247799.
-TEST_P(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) {
+TEST_F(WaylandWindowTest, DoesNotGrabPopupUnlessParentHasGrab) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
                               WL_SEAT_CAPABILITY_POINTER);
@@ -3575,8 +3550,8 @@
   std::unique_ptr<WaylandWindow> root_menu;
   EXPECT_CALL(delegate, GetMenuType()).WillOnce(Return(MenuType::kRootMenu));
   root_menu = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                            window_->GetWidget(),
-                                            gfx::Rect(50, 50), &delegate);
+                                            gfx::Rect(50, 50), &delegate,
+                                            window_->GetWidget());
   VerifyAndClearExpectations();
   Mock::VerifyAndClearExpectations(&delegate);
   ASSERT_TRUE(root_menu);
@@ -3613,8 +3588,8 @@
   std::unique_ptr<WaylandWindow> child_menu;
   EXPECT_CALL(delegate_2, GetMenuType()).WillOnce(Return(MenuType::kChildMenu));
   child_menu = CreateWaylandWindowWithParams(PlatformWindowType::kMenu,
-                                             root_menu->GetWidget(),
-                                             gfx::Rect(10, 10), &delegate_2);
+                                             gfx::Rect(10, 10), &delegate_2,
+                                             root_menu->GetWidget());
   VerifyAndClearExpectations();
   Mock::VerifyAndClearExpectations(&delegate_2);
   ASSERT_TRUE(child_menu);
@@ -3636,20 +3611,20 @@
       });
 }
 
-TEST_P(WaylandWindowTest, InitialBounds) {
+TEST_F(WaylandWindowTest, InitialBounds) {
   testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
   auto toplevel = CreateWaylandWindowWithParams(
-      PlatformWindowType::kWindow, 0, gfx::Rect(10, 10, 200, 200), &delegate_2);
+      PlatformWindowType::kWindow, gfx::Rect(10, 10, 200, 200), &delegate_2);
   toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, {false, false, true});
   toplevel->HandleSurfaceConfigure(2);
   static_cast<WaylandToplevelWindow*>(toplevel.get())->ApplyPendingBounds();
   EXPECT_EQ(gfx::Rect(10, 10, 200, 200), toplevel->GetBoundsInDIP());
 }
 
-TEST_P(WaylandWindowTest, PrimarySnappedState) {
+TEST_F(WaylandWindowTest, PrimarySnappedState) {
   testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
   auto toplevel = CreateWaylandWindowWithParams(
-      PlatformWindowType::kWindow, 0, gfx::Rect(0, 0, 200, 200), &delegate_2);
+      PlatformWindowType::kWindow, gfx::Rect(0, 0, 200, 200), &delegate_2);
   toplevel->HandleAuraToplevelConfigure(0, 0, 100, 200,
                                         {.is_maximized = false,
                                          .is_fullscreen = false,
@@ -3660,10 +3635,10 @@
   EXPECT_EQ(gfx::Rect(0, 0, 100, 200), toplevel->GetBoundsInDIP());
 }
 
-TEST_P(WaylandWindowTest, SecondarySnappedState) {
+TEST_F(WaylandWindowTest, SecondarySnappedState) {
   testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
   auto toplevel = CreateWaylandWindowWithParams(
-      PlatformWindowType::kWindow, 0, gfx::Rect(0, 0, 200, 200), &delegate_2);
+      PlatformWindowType::kWindow, gfx::Rect(0, 0, 200, 200), &delegate_2);
   toplevel->HandleAuraToplevelConfigure(100, 0, 100, 200,
                                         {.is_maximized = false,
                                          .is_fullscreen = false,
@@ -3688,8 +3663,7 @@
     VerifyAndClearExpectations();
 
     std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams(
-        PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
-        gfx::Rect(640, 480), &delegate_);
+        PlatformWindowType::kWindow, gfx::Rect(640, 480), &delegate_);
     EXPECT_TRUE(window);
 
     bool result = window->RequestSubsurface();
@@ -3756,7 +3730,7 @@
 
 // Tests integer and non integer size/position support with and without surface
 // augmenter.
-TEST_P(WaylandSubsurfaceTest, OneWaylandSubsurfaceInteger) {
+TEST_F(WaylandSubsurfaceTest, OneWaylandSubsurfaceInteger) {
   ASSERT_FALSE(connection_->surface_augmenter());
 
   constexpr gfx::RectF test_data[2][2] = {
@@ -3775,7 +3749,7 @@
   };
 }
 
-TEST_P(WaylandSubsurfaceTest, OneWaylandSubsurfaceNonInteger) {
+TEST_F(WaylandSubsurfaceTest, OneWaylandSubsurfaceNonInteger) {
   ASSERT_FALSE(connection_->surface_augmenter());
 
   constexpr gfx::RectF test_data[2][2] = {
@@ -3792,7 +3766,7 @@
   }
 }
 
-TEST_P(WaylandSubsurfaceTest, NoDuplicateSubsurfaceRequests) {
+TEST_F(WaylandSubsurfaceTest, NoDuplicateSubsurfaceRequests) {
   auto subsurfaces = RequestWaylandSubsurface(3);
   for (auto* subsurface : subsurfaces) {
     subsurface->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f),
@@ -3838,7 +3812,7 @@
   VerifyAndClearExpectations();
 }
 
-TEST_P(WaylandWindowTest, NoDuplicateViewporterRequests) {
+TEST_F(WaylandWindowTest, NoDuplicateViewporterRequests) {
   EXPECT_TRUE(connection_->buffer_manager_host());
 
   auto interface_ptr = connection_->buffer_manager_host()->BindInterface();
@@ -3940,15 +3914,15 @@
 }
 
 // Tests that WaylandPopups can be repositioned.
-TEST_P(WaylandWindowTest, RepositionPopups) {
+TEST_F(WaylandWindowTest, RepositionPopups) {
   VerifyAndClearExpectations();
 
   EXPECT_CALL(delegate_, GetMenuType())
       .WillRepeatedly(Return(MenuType::kRootContextMenu));
   gfx::Rect menu_window_bounds(gfx::Rect(6, 20, 8, 20));
   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
-      PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
-      &delegate_);
+      PlatformWindowType::kMenu, menu_window_bounds, &delegate_,
+      window_->GetWidget());
   EXPECT_TRUE(menu_window);
   EXPECT_TRUE(menu_window->IsVisible());
 
@@ -3999,13 +3973,13 @@
 // If buffers are not attached (aka WaylandBufferManagerHost is not used for
 // buffer management), WaylandSurface::Commit mustn't result in creation of
 // surface sync.
-TEST_P(WaylandWindowTest, DoesNotCreateSurfaceSyncOnCommitWithoutBuffers) {
+TEST_F(WaylandWindowTest, DoesNotCreateSurfaceSyncOnCommitWithoutBuffers) {
   EXPECT_THAT(window_->root_surface()->surface_sync_, nullptr);
   window_->root_surface()->Commit();
   EXPECT_THAT(window_->root_surface()->surface_sync_, nullptr);
 }
 
-TEST_P(WaylandWindowTest, StartWithMinimized) {
+TEST_F(WaylandWindowTest, StartWithMinimized) {
   // Make sure the window is initialized to normal state from the beginning.
   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
 
@@ -4101,7 +4075,7 @@
 // the first touch down/up action, and blocks the original flow, before it gets
 // handled completely.
 // The test is flaky. https://crbug.com/1305272.
-TEST_P(WaylandWindowTest, DISABLED_BlockingTouchDownUp_NoCrash) {
+TEST_F(WaylandWindowTest, DISABLED_BlockingTouchDownUp_NoCrash) {
   window_.reset();
 
   MockWaylandPlatformWindowDelegate delegate;
@@ -4162,7 +4136,7 @@
 #else
 #define MAYBE_ChangeFocusDuringDispatch ChangeFocusDuringDispatch
 #endif
-TEST_P(WaylandWindowTest, MAYBE_ChangeFocusDuringDispatch) {
+TEST_F(WaylandWindowTest, MAYBE_ChangeFocusDuringDispatch) {
   MockPlatformWindowDelegate other_delegate;
   gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget;
   EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_))
@@ -4223,7 +4197,7 @@
   EXPECT_EQ(count, 3);
 }
 
-TEST_P(WaylandWindowTest, WindowMovedResized) {
+TEST_F(WaylandWindowTest, WindowMovedResized) {
   const gfx::Rect initial_bounds = window_->GetBoundsInDIP();
 
   gfx::Rect new_bounds(initial_bounds);
@@ -4267,7 +4241,7 @@
 
 // Make sure that creating a window with DIP bounds creates a window with
 // the same DIP bounds with various fractional scales.
-TEST_P(WaylandWindowTest, NoRoundingErrorInDIP) {
+TEST_F(WaylandWindowTest, NoRoundingErrorInDIP) {
   VerifyAndClearExpectations();
   auto* primary_output =
       connection_->wayland_output_manager()->GetPrimaryOutput();
@@ -4281,7 +4255,6 @@
     testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate;
     std::unique_ptr<WaylandWindow> wayland_window =
         CreateWaylandWindowWithParams(PlatformWindowType::kWindow,
-                                      gfx::kNullAcceleratedWidget,
                                       gfx::Rect(20, 0, 100, 100), &delegate);
     for (int i = 100; i < 3000; i++) {
       const gfx::Rect kBoundsDip{20, 0, i, 3000 - i};
@@ -4294,12 +4267,4 @@
   VerifyAndClearExpectations();
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandWindowTest,
-                         Values(wl::ServerConfig{}));
-
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandSubsurfaceTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc b/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc
index 2c6afbf..6f506b9 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc
@@ -15,17 +15,10 @@
 
 namespace ui {
 
-using ::testing::Values;
-namespace {
-class WaylandZAuraOutputTest : public WaylandTest {
+class WaylandZAuraOutputTest : public WaylandTestSimple {
  public:
-  WaylandZAuraOutputTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandZAuraOutputTest(const WaylandZAuraOutputTest&) = delete;
-  WaylandZAuraOutputTest& operator=(const WaylandZAuraOutputTest&) = delete;
-  ~WaylandZAuraOutputTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     // Set default values for the output.
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -50,9 +43,7 @@
   std::unique_ptr<WaylandScreen> platform_screen_;
 };
 
-}  // namespace
-
-TEST_P(WaylandZAuraOutputTest, HandleInsets) {
+TEST_F(WaylandZAuraOutputTest, HandleInsets) {
   WaylandOutput* wayland_output = output_manager_->GetPrimaryOutput();
   ASSERT_TRUE(wayland_output);
   EXPECT_TRUE(wayland_output->IsReady());
@@ -79,7 +70,7 @@
   EXPECT_EQ(wayland_output->insets(), insets);
 }
 
-TEST_P(WaylandZAuraOutputTest, HandleLogicalTransform) {
+TEST_F(WaylandZAuraOutputTest, HandleLogicalTransform) {
   WaylandOutput* wayland_output = output_manager_->GetPrimaryOutput();
   ASSERT_TRUE(wayland_output);
   EXPECT_TRUE(wayland_output->IsReady());
@@ -98,7 +89,7 @@
 }
 
 // Test edge case display ids are converted correctly.
-TEST_P(WaylandZAuraOutputTest, DisplayIdConversions) {
+TEST_F(WaylandZAuraOutputTest, DisplayIdConversions) {
   const int64_t kTestIds[] = {
       std::numeric_limits<int64_t>::min(),
       std::numeric_limits<int64_t>::min() + 1,
@@ -122,8 +113,4 @@
   }
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandZAuraOutputTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc b/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
index 625d94af..7c627f95 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_shell_unittest.cc
@@ -13,18 +13,9 @@
 
 namespace ui {
 
-// TODO(crbug.com/1365887): change this to
-// `using WaylandZAuraShellTest = WaylandTest`
-// once the default mode becomes asynchronous.
-class WaylandZAuraShellTest : public WaylandTest {
- public:
-  WaylandZAuraShellTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandZAuraShellTest(const WaylandZAuraShellTest&) = delete;
-  WaylandZAuraShellTest& operator=(const WaylandZAuraShellTest&) = delete;
-  ~WaylandZAuraShellTest() override = default;
-};
+using WaylandZAuraShellTest = WaylandTestSimple;
 
-TEST_P(WaylandZAuraShellTest, BugFix) {
+TEST_F(WaylandZAuraShellTest, BugFix) {
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     auto* const zaura_shell = server->zaura_shell()->resource();
     zaura_shell_send_bug_fix(zaura_shell, 1);
@@ -36,8 +27,4 @@
   ASSERT_FALSE(connection_->zaura_shell()->HasBugFix(2));
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandZAuraShellTest,
-                         Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc
index f845ad87..5cd9c0ee 100644
--- a/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures_unittest.cc
@@ -56,16 +56,10 @@
 
 }  // namespace
 
-class WaylandPointerGesturesTest : public WaylandTest {
+class WaylandPointerGesturesTest : public WaylandTestSimple {
  public:
-  WaylandPointerGesturesTest() : WaylandTest(TestServerMode::kAsync) {}
-  WaylandPointerGesturesTest(const WaylandPointerGesturesTest&) = delete;
-  WaylandPointerGesturesTest& operator=(const WaylandPointerGesturesTest&) =
-      delete;
-  ~WaylandPointerGesturesTest() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     // Pointer capability is required for gesture objects to be initialised.
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
@@ -89,7 +83,7 @@
 // WaylandZwpPointerGestures methods.
 //
 // See https://crbug.com/1283652
-TEST_P(WaylandPointerGesturesTest, PinchZoomScale) {
+TEST_F(WaylandPointerGesturesTest, PinchZoomScale) {
   PostToServerAndWait([surface_id = window_->root_surface()->get_surface_id()](
                           wl::TestWaylandServerThread* server) {
     auto* const pointer = server->seat()->pointer()->resource();
@@ -140,8 +134,4 @@
   }
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         WaylandPointerGesturesTest,
-                         testing::Values(wl::ServerConfig{}));
-
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1_unittest.cc b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1_unittest.cc
index b18e51a..159489b 100644
--- a/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1_unittest.cc
+++ b/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1_unittest.cc
@@ -4,12 +4,9 @@
 
 #include "ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.h"
 
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
-#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
 #include "ui/ozone/platform/wayland/test/mock_zcr_extended_text_input.h"
 #include "ui/ozone/platform/wayland/test/mock_zwp_text_input.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
@@ -17,99 +14,89 @@
 #include "ui/ozone/platform/wayland/test/wayland_test.h"
 
 using ::testing::InSequence;
-using ::testing::Values;
+using ::testing::Mock;
 
 namespace ui {
-namespace {
 
-class ZWPTextInputWrapperV1Test : public WaylandTest {
+class ZWPTextInputWrapperV1Test : public WaylandTestSimple {
  public:
-  ZWPTextInputWrapperV1Test() = default;
-  ZWPTextInputWrapperV1Test(const ZWPTextInputWrapperV1Test&) = delete;
-  ZWPTextInputWrapperV1Test& operator=(const ZWPTextInputWrapperV1Test&) =
-      delete;
-  ~ZWPTextInputWrapperV1Test() override = default;
-
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandTestSimple::SetUp();
 
     wrapper_ = std::make_unique<ZWPTextInputWrapperV1>(
         connection_.get(), nullptr, connection_->text_input_manager_v1(),
         connection_->text_input_extension_v1());
-
-    connection_->Flush();
-    Sync();
-
-    mock_text_input_ = server_.text_input_manager_v1()->text_input();
-    ASSERT_TRUE(mock_text_input_);
-    mock_ext_text_input_ =
-        server_.text_input_extension_v1()->extended_text_input();
-    ASSERT_TRUE(mock_ext_text_input_);
   }
 
  protected:
   std::unique_ptr<ZWPTextInputWrapperV1> wrapper_;
-  wl::MockZwpTextInput* mock_text_input_ = nullptr;
-  wl::MockZcrExtendedTextInput* mock_ext_text_input_ = nullptr;
 };
 
-TEST_P(ZWPTextInputWrapperV1Test,
+TEST_F(ZWPTextInputWrapperV1Test,
        FinalizeVirtualKeyboardChangesShowInputPanel) {
-  InSequence s;
-  EXPECT_CALL(*mock_text_input_, ShowInputPanel());
-  EXPECT_CALL(*mock_ext_text_input_, FinalizeVirtualKeyboardChanges());
-  wrapper_->ShowInputPanel();
-  connection_->Flush();
-  Sync();
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    InSequence s;
+    EXPECT_CALL(*server->text_input_manager_v1()->text_input(),
+                ShowInputPanel());
+    EXPECT_CALL(*server->text_input_extension_v1()->extended_text_input(),
+                FinalizeVirtualKeyboardChanges());
+  });
 
-  // Flush again after sync, so the scheduled finalize request is processed.
-  connection_->Flush();
-  Sync();
+  wrapper_->ShowInputPanel();
+
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    Mock::VerifyAndClearExpectations(
+        server->text_input_manager_v1()->text_input());
+    Mock::VerifyAndClearExpectations(server->text_input_extension_v1());
+  });
 }
 
-TEST_P(ZWPTextInputWrapperV1Test,
+TEST_F(ZWPTextInputWrapperV1Test,
        FinalizeVirtualKeyboardChangesHideInputPanel) {
-  InSequence s;
-  EXPECT_CALL(*mock_text_input_, HideInputPanel());
-  EXPECT_CALL(*mock_ext_text_input_, FinalizeVirtualKeyboardChanges());
-  wrapper_->HideInputPanel();
-  connection_->Flush();
-  Sync();
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    InSequence s;
+    EXPECT_CALL(*server->text_input_manager_v1()->text_input(),
+                HideInputPanel());
+    EXPECT_CALL(*server->text_input_extension_v1()->extended_text_input(),
+                FinalizeVirtualKeyboardChanges());
+  });
 
-  // Flush again after sync, so the scheduled finalize request is processed.
-  connection_->Flush();
-  Sync();
+  wrapper_->HideInputPanel();
+
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    Mock::VerifyAndClearExpectations(
+        server->text_input_manager_v1()->text_input());
+    Mock::VerifyAndClearExpectations(
+        server->text_input_extension_v1()->extended_text_input());
+  });
 }
 
-TEST_P(ZWPTextInputWrapperV1Test,
+TEST_F(ZWPTextInputWrapperV1Test,
        FinalizeVirtualKeyboardChangesMultipleInputPanelChanges) {
-  InSequence s;
-  EXPECT_CALL(*mock_text_input_, ShowInputPanel());
-  EXPECT_CALL(*mock_text_input_, HideInputPanel());
-  EXPECT_CALL(*mock_text_input_, ShowInputPanel());
-  EXPECT_CALL(*mock_text_input_, HideInputPanel());
-  EXPECT_CALL(*mock_text_input_, ShowInputPanel());
-  EXPECT_CALL(*mock_ext_text_input_, FinalizeVirtualKeyboardChanges());
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    auto* const mock_text_input = server->text_input_manager_v1()->text_input();
+    InSequence s;
+    EXPECT_CALL(*mock_text_input, ShowInputPanel());
+    EXPECT_CALL(*mock_text_input, HideInputPanel());
+    EXPECT_CALL(*mock_text_input, ShowInputPanel());
+    EXPECT_CALL(*mock_text_input, HideInputPanel());
+    EXPECT_CALL(*mock_text_input, ShowInputPanel());
+    EXPECT_CALL(*server->text_input_extension_v1()->extended_text_input(),
+                FinalizeVirtualKeyboardChanges());
+  });
+
   wrapper_->ShowInputPanel();
   wrapper_->HideInputPanel();
   wrapper_->ShowInputPanel();
   wrapper_->HideInputPanel();
   wrapper_->ShowInputPanel();
-  connection_->Flush();
-  Sync();
 
-  // Flush again after sync, so the scheduled finalize request is processed.
-  connection_->Flush();
-  Sync();
-
-  // Flush and sync again to make sure no extra finalize request.
-  connection_->Flush();
-  Sync();
+  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
+    Mock::VerifyAndClearExpectations(
+        server->text_input_manager_v1()->text_input());
+    Mock::VerifyAndClearExpectations(
+        server->text_input_extension_v1()->extended_text_input());
+  });
 }
 
-INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
-                         ZWPTextInputWrapperV1Test,
-                         Values(wl::ServerConfig{}));
-
-}  // namespace
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
index e0baa3b..a525a6c 100644
--- a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
@@ -43,9 +43,7 @@
   return std::make_unique<WaylandExchangeDataProvider>();
 }
 
-WaylandDragDropTest::WaylandDragDropTest()
-    : WaylandTest(WaylandTest::TestServerMode::kAsync) {}
-
+WaylandDragDropTest::WaylandDragDropTest() = default;
 WaylandDragDropTest::~WaylandDragDropTest() = default;
 
 void WaylandDragDropTest::SendDndEnter(WaylandWindow* window,
@@ -214,7 +212,7 @@
 }
 
 void WaylandDragDropTest::SetUp() {
-  WaylandTest::SetUp();
+  WaylandTestSimple::SetUp();
 
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     wl_seat_send_capabilities(server->seat()->resource(),
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
index 8591d78b..61d078b 100644
--- a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
@@ -33,7 +33,7 @@
 // Base class for Wayland drag-and-drop tests. Public methods allow test code to
 // emulate dnd-related events from the test compositor and can be used in both
 // data and window dragging test cases.
-class WaylandDragDropTest : public WaylandTest {
+class WaylandDragDropTest : public WaylandTestSimple {
  public:
   WaylandDragDropTest();
   WaylandDragDropTest(const WaylandDragDropTest&) = delete;
diff --git a/ui/ozone/platform/wayland/test/wayland_test.cc b/ui/ozone/platform/wayland/test/wayland_test.cc
index 338d443..f63748f 100644
--- a/ui/ozone/platform/wayland/test/wayland_test.cc
+++ b/ui/ozone/platform/wayland/test/wayland_test.cc
@@ -32,10 +32,12 @@
 
 namespace ui {
 
-WaylandTest::WaylandTest(TestServerMode server_mode)
+WaylandTestBase::WaylandTestBase(wl::ServerConfig config,
+                                 TestServerMode server_mode)
     : task_environment_(base::test::TaskEnvironment::MainThreadType::UI,
                         base::test::TaskEnvironment::TimeSource::MOCK_TIME),
-      server_mode_(server_mode) {
+      server_mode_(server_mode),
+      config_(config) {
 #if BUILDFLAG(USE_XKBCOMMON)
   auto keyboard_layout_engine =
       std::make_unique<XkbKeyboardLayoutEngine>(xkb_evdev_code_converter_);
@@ -50,9 +52,9 @@
       connection_.get(), buffer_manager_gpu_.get());
 }
 
-WaylandTest::~WaylandTest() {}
+WaylandTestBase::~WaylandTestBase() = default;
 
-void WaylandTest::SetUp() {
+void WaylandTestBase::SetUp() {
   disabled_features_.push_back(ui::kWaylandSurfaceSubmissionInPixelCoordinates);
   disabled_features_.push_back(features::kWaylandScreenCoordinatesEnabled);
 
@@ -65,7 +67,7 @@
     DeviceDataManager::CreateInstance();
   }
 
-  ASSERT_TRUE(server_.Start(GetParam()));
+  ASSERT_TRUE(server_.Start(config_));
   ASSERT_TRUE(connection_->Initialize());
   screen_ = connection_->wayland_output_manager()->CreateWaylandScreen();
   connection_->wayland_output_manager()->InitWaylandScreen(screen_.get());
@@ -109,7 +111,7 @@
     server_.SetServerAsync();
 }
 
-void WaylandTest::TearDown() {
+void WaylandTestBase::TearDown() {
   if (initialized_) {
     if (server_mode_ != TestServerMode::kAsync)
       Sync();
@@ -118,7 +120,7 @@
   }
 }
 
-void WaylandTest::Sync() {
+void WaylandTestBase::Sync() {
   // Resume the server, flushing its pending events.
   server_.Resume();
 
@@ -130,7 +132,7 @@
   server_.Pause();
 }
 
-void WaylandTest::PostToServerAndWait(
+void WaylandTestBase::PostToServerAndWait(
     base::OnceCallback<void(wl::TestWaylandServerThread* server)> callback) {
   // Sync with the display to ensure client's requests are processed.
   SyncDisplay();
@@ -141,7 +143,7 @@
   SyncDisplay();
 }
 
-void WaylandTest::PostToServerAndWait(base::OnceClosure closure) {
+void WaylandTestBase::PostToServerAndWait(base::OnceClosure closure) {
   // Sync with the display to ensure client's requests are processed.
   SyncDisplay();
 
@@ -151,22 +153,22 @@
   SyncDisplay();
 }
 
-void WaylandTest::DisableSyncOnTearDown() {
+void WaylandTestBase::DisableSyncOnTearDown() {
   initialized_ = false;
 }
 
-void WaylandTest::SetPointerFocusedWindow(WaylandWindow* window) {
+void WaylandTestBase::SetPointerFocusedWindow(WaylandWindow* window) {
   connection_->wayland_window_manager()->SetPointerFocusedWindow(window);
 }
 
-void WaylandTest::SetKeyboardFocusedWindow(WaylandWindow* window) {
+void WaylandTestBase::SetKeyboardFocusedWindow(WaylandWindow* window) {
   connection_->wayland_window_manager()->SetKeyboardFocusedWindow(window);
 }
 
-void WaylandTest::SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
-                                     const gfx::Size& size,
-                                     uint32_t serial,
-                                     struct wl_array* states) {
+void WaylandTestBase::SendConfigureEvent(wl::MockXdgSurface* xdg_surface,
+                                         const gfx::Size& size,
+                                         uint32_t serial,
+                                         struct wl_array* states) {
   const int32_t width = size.width();
   const int32_t height = size.height();
   // Please note that toplevel surfaces may not exist if the surface was created
@@ -182,10 +184,10 @@
   xdg_surface_send_configure(xdg_surface->resource(), serial);
 }
 
-void WaylandTest::SendConfigureEvent(uint32_t surface_id,
-                                     const gfx::Size& size,
-                                     const wl::ScopedWlArray& states,
-                                     absl::optional<uint32_t> serial) {
+void WaylandTestBase::SendConfigureEvent(uint32_t surface_id,
+                                         const gfx::Size& size,
+                                         const wl::ScopedWlArray& states,
+                                         absl::optional<uint32_t> serial) {
   ASSERT_EQ(server_mode_, TestServerMode::kAsync);
   PostToServerAndWait([size, surface_id, states,
                        serial](wl::TestWaylandServerThread* server) {
@@ -215,18 +217,18 @@
   });
 }
 
-void WaylandTest::ActivateSurface(wl::MockXdgSurface* xdg_surface) {
+void WaylandTestBase::ActivateSurface(wl::MockXdgSurface* xdg_surface) {
   wl::ScopedWlArray state({XDG_TOPLEVEL_STATE_ACTIVATED});
   SendConfigureEvent(xdg_surface, {0, 0}, 1, state.get());
 }
 
-void WaylandTest::ActivateSurface(uint32_t surface_id) {
+void WaylandTestBase::ActivateSurface(uint32_t surface_id) {
   ASSERT_EQ(server_mode_, TestServerMode::kAsync);
   wl::ScopedWlArray state({XDG_TOPLEVEL_STATE_ACTIVATED});
   SendConfigureEvent(surface_id, {0, 0}, state);
 }
 
-void WaylandTest::InitializeSurfaceAugmenter() {
+void WaylandTestBase::InitializeSurfaceAugmenter() {
   if (server_mode_ == TestServerMode::kAsync) {
     PostToServerAndWait([](wl::TestWaylandServerThread* server) {
       server->EnsureSurfaceAugmenter();
@@ -237,7 +239,7 @@
   }
 }
 
-void WaylandTest::SyncDisplay() {
+void WaylandTestBase::SyncDisplay() {
   ASSERT_EQ(server_mode_, TestServerMode::kAsync);
   DCHECK(initialized_);
   base::RunLoop run_loop;
@@ -252,7 +254,7 @@
   run_loop.Run();
 }
 
-void WaylandTest::MaybeSetUpXkb() {
+void WaylandTestBase::MaybeSetUpXkb() {
 #if BUILDFLAG(USE_XKBCOMMON)
   PostToServerAndWait([](wl::TestWaylandServerThread* server) {
     // Set up XKB bits and set the keymap to the client.
@@ -290,4 +292,48 @@
 #endif
 }
 
+std::unique_ptr<WaylandWindow> WaylandTestBase::CreateWaylandWindowWithParams(
+    PlatformWindowType type,
+    const gfx::Rect bounds,
+    MockWaylandPlatformWindowDelegate* delegate,
+    gfx::AcceleratedWidget parent_widget) {
+  PlatformWindowInitProperties properties;
+  properties.bounds = bounds;
+  properties.type = type;
+  properties.parent_widget = parent_widget;
+
+  auto window = delegate->CreateWaylandWindow(
+      connection_.get(), std::move(properties), true, true);
+  if (window)
+    window->Show(false);
+  return window;
+}
+
+WaylandTest::WaylandTest(WaylandTestBase::TestServerMode server_mode)
+    : WaylandTestBase(GetParam(), server_mode) {}
+
+WaylandTest::~WaylandTest() = default;
+
+void WaylandTest::SetUp() {
+  WaylandTestBase::SetUp();
+}
+
+void WaylandTest::TearDown() {
+  WaylandTestBase::TearDown();
+}
+
+WaylandTestSimple::WaylandTestSimple(
+    WaylandTestBase::TestServerMode server_mode)
+    : WaylandTestBase({}, server_mode) {}
+
+WaylandTestSimple::~WaylandTestSimple() = default;
+
+void WaylandTestSimple::SetUp() {
+  WaylandTestBase::SetUp();
+}
+
+void WaylandTestSimple::TearDown() {
+  WaylandTestBase::TearDown();
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/test/wayland_test.h b/ui/ozone/platform/wayland/test/wayland_test.h
index fed9a7d..ed24458 100644
--- a/ui/ozone/platform/wayland/test/wayland_test.h
+++ b/ui/ozone/platform/wayland/test/wayland_test.h
@@ -40,7 +40,7 @@
 
 // WaylandTest is a base class that sets up a display, window, and test server,
 // and allows easy synchronization between them.
-class WaylandTest : public ::testing::TestWithParam<wl::ServerConfig> {
+class WaylandTestBase {
  public:
   // Specifies how the server should run.
   // TODO(crbug.com/1365887): this must be removed once all tests switch to
@@ -54,15 +54,13 @@
     kSync
   };
 
-  explicit WaylandTest(TestServerMode server_mode = TestServerMode::kSync);
+  WaylandTestBase(wl::ServerConfig config, TestServerMode server_mode);
+  WaylandTestBase(const WaylandTestBase&) = delete;
+  WaylandTestBase& operator=(const WaylandTestBase&) = delete;
+  ~WaylandTestBase();
 
-  WaylandTest(const WaylandTest&) = delete;
-  WaylandTest& operator=(const WaylandTest&) = delete;
-
-  ~WaylandTest() override;
-
-  void SetUp() override;
-  void TearDown() override;
+  void SetUp();
+  void TearDown();
 
   void Sync();
 
@@ -125,6 +123,13 @@
   // Does nothing if XkbCommon is not used.
   void MaybeSetUpXkb();
 
+  // Creates a Wayland window with the specified delegate, type, and bounds.
+  std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
+      PlatformWindowType type,
+      const gfx::Rect bounds,
+      MockWaylandPlatformWindowDelegate* delegate,
+      gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget);
+
   base::test::TaskEnvironment task_environment_;
 
   wl::TestWaylandServerThread server_;
@@ -154,6 +159,33 @@
 
   // The server will be set to asynchronous mode once started.
   const TestServerMode server_mode_;
+  const wl::ServerConfig config_;
+};
+
+// Version of WaylandTestBase that uses parametrised tests (TEST_P).
+class WaylandTest : public WaylandTestBase,
+                    public ::testing::TestWithParam<wl::ServerConfig> {
+ public:
+  explicit WaylandTest(TestServerMode server_mode = TestServerMode::kSync);
+  WaylandTest(const WaylandTest&) = delete;
+  WaylandTest& operator=(const WaylandTest&) = delete;
+  ~WaylandTest() override;
+
+  void SetUp() override;
+  void TearDown() override;
+};
+
+// Version of WaylandTest that uses simple test fixtures (TEST_F).
+class WaylandTestSimple : public WaylandTestBase, public ::testing::Test {
+ public:
+  explicit WaylandTestSimple(WaylandTestBase::TestServerMode server_mode =
+                                 WaylandTestBase::TestServerMode::kAsync);
+  WaylandTestSimple(const WaylandTestSimple&) = delete;
+  WaylandTestSimple& operator=(const WaylandTestSimple&) = delete;
+  ~WaylandTestSimple() override;
+
+  void SetUp() override;
+  void TearDown() override;
 };
 
 }  // namespace ui