diff --git a/DEPS b/DEPS
index 6c9c911..67970e9 100644
--- a/DEPS
+++ b/DEPS
@@ -280,11 +280,11 @@
   # 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': '0983009ddc2e3b10310f8f5b382751dc64041840',
+  'skia_revision': 'c1373396b85792ee6cf7fcc16870bd3d7e9d0c93',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'c55e2af970bcc5dfee0165c7b5aeccad62666fd6',
+  'v8_revision': '15d9040b367b37cc643215aa9913d989c5bf115e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -292,7 +292,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'ff5356238d869af9293da75a846acb8a773311ca',
+  'swiftshader_revision': 'e78a7dd5ec0b9acad25c9b7c4656cee935c8149c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -331,7 +331,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '4b6f92e6b3d0d99a839448bc897673b849981997',
+  'freetype_revision': '2848378be56ea26376e3aff68b1b4b8aa8f8611b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -359,7 +359,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': '451dff4f370af90746b0cf8e9af8bf066cc8376d',
+  'devtools_frontend_revision': 'd3ba5cbbb58405bf03ee6a7d9db6bad5f737418b',
   # 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.
@@ -395,7 +395,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': '3b3ef3624120551e2599c6a02bee1e8de3b01b0f',
+  'dawn_revision': '79e90e5f3b35be7b654fc717ff8ef3a02ab004b4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -439,7 +439,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    '2dba7d2cc46a25cd67fb990826179e0c159c5b5c',
+  'libcxxabi_revision':    '92ef8d47d097facc2b119ee0172767cb786fcf79',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1122,7 +1122,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '138813d186eb3836de2db4978cb4e8a229cb1f88',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '3962004b853661caed21f3eba051805a4acc14a3',
       'condition': 'checkout_chromeos',
   },
 
@@ -1140,7 +1140,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'a97789ca4417e1a4943f8349a6d06690f5e6b8df',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '13944455f2056bcbe2a888974b40eeb7da52ed0c',
       'condition': 'checkout_linux',
   },
 
@@ -1542,7 +1542,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '5c85522e6e4c1670e58b341f05b68892df56a3c7',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '3d3f58658fdecc553543e801076e44febf5490b5',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1673,7 +1673,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@1765af41ecf526b13ef5d478766264eed41f7349',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@955b22833ec40a749c3d718087cf16ed89332d1c',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1712,7 +1712,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f8000b0ea82de00b3cc7d337e7521d1e94fed587',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '573b145ab51ea59394b4763dece7b54751eea424',
+    Var('webrtc_git') + '/src.git' + '@' + '7edbf237004164bb1ba38638fc2f055a57953b02',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1815,7 +1815,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'fwkIAE88f7UHiGVjACvfUwo-MWl7eQYwEwJ_x1Of8gMC',
+        'version': '-UEm5uU3XGHjQkKjF-UqjE18vqRqoaMj074Ix_a8nmsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index be11e92..0133cff 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -282,6 +282,9 @@
     // WebView.
     features.DisableIfNotSet(blink::features::kUserAgentClientHint);
 
+    // Disable Reducing User Agent minor version on WebView.
+    features.DisableIfNotSet(blink::features::kReduceUserAgentMinorVersion);
+
     // Disabled until viz scheduling can be improved.
     features.DisableIfNotSet(::features::kUseSurfaceLayerForVideoDefault);
 
diff --git a/ash/components/login/auth/auth_session_authenticator.cc b/ash/components/login/auth/auth_session_authenticator.cc
index 6030478..a82417e 100644
--- a/ash/components/login/auth/auth_session_authenticator.cc
+++ b/ash/components/login/auth/auth_session_authenticator.cc
@@ -15,6 +15,8 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/notreached.h"
 #include "chromeos/dbus/cryptohome/UserDataAuth.pb.h"
 #include "chromeos/dbus/userdataauth/userdataauth_client.h"
@@ -603,10 +605,12 @@
     case user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED:
     case user_data_auth::CRYPTOHOME_ERROR_KEY_LABEL_EXISTS:
     case user_data_auth::CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID:
+    case user_data_auth::CRYPTOHOME_ERROR_UNKNOWN_LEGACY:
       // Assumptions about key are not correct
       error.failure_reason = default_error;
       break;
     case user_data_auth::CRYPTOHOME_INVALID_AUTH_SESSION_TOKEN:
+    case user_data_auth::CRYPTOHOME_ERROR_UNAUTHENTICATED_AUTH_SESSION:
       // Auth session expired, might need to handle it separately later.
       error.failure_reason = default_error;
       break;
@@ -630,6 +634,7 @@
       error.failure_reason = AuthFailure::TPM_UPDATE_REQUIRED;
       break;
     case user_data_auth::CRYPTOHOME_ERROR_VAULT_UNRECOVERABLE:
+    case user_data_auth::CRYPTOHOME_ERROR_UNUSABLE_VAULT:
       error.failure_reason = AuthFailure::UNRECOVERABLE_CRYPTOHOME;
       break;
     case user_data_auth::CryptohomeErrorCode_INT_MIN_SENTINEL_DO_NOT_USE_:
@@ -665,7 +670,13 @@
     return;
   }
   bool handled = ResolveCryptohomeError(default_error, error);
-  CHECK(handled);
+  if (!handled) {
+    NOTREACHED() << "Unhandled cryptohome error: " << error.error_code;
+    SCOPED_CRASH_KEY_NUMBER("Cryptohome", "error_code", error.error_code);
+    base::debug::DumpWithoutCrashing();
+    error.failure_reason = default_error;
+  }
+
   NotifyFailure(error.failure_reason, std::move(context));
 }
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index c3ffd127..d108753 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -897,6 +897,9 @@
 const base::Feature kInstantTethering{"InstantTethering",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables Jelly features.
+const base::Feature kJelly{"kJelly", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables to use lacros-chrome as the only web browser on ChromeOS.
 // This works only when both LacrosSupport and LacrosPrimary below are enabled.
 // NOTE: Use crosapi::browser_util::IsAshWebBrowserEnabled() instead of checking
@@ -1949,6 +1952,10 @@
       kInstantTetheringBackgroundAdvertisementSupport);
 }
 
+bool IsJellyEnabled() {
+  return base::FeatureList::IsEnabled(kJelly);
+}
+
 bool IsKeyboardBacklightToggleEnabled() {
   return base::FeatureList::IsEnabled(kEnableKeyboardBacklightToggle);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 876cc3b..685ba00 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -363,6 +363,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kImprovedLoginErrorHandling;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kInstantTethering;
+COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kJelly;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kLacrosOnly;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kLacrosPrimary;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kLacrosSupport;
@@ -718,6 +719,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsInputNoiseCancellationUiEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsInstantTetheringBackgroundAdvertisingSupported();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsJellyEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsKeyboardBacklightToggleEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsLanguagePacksEnabled();
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index f20c544a..1a3aa8b 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -439,14 +439,22 @@
     launch_app_callback_.Run(kiosk_apps_[command_id]);
   }
 
-  void OnMenuWillShow(SimpleMenuModel* source) override { on_show_menu_.Run(); }
+  void OnMenuWillShow(SimpleMenuModel* source) override {
+    is_menu_opened_ = true;
+    on_show_menu_.Run();
+  }
 
-  void MenuClosed(SimpleMenuModel* source) override { on_close_menu_.Run(); }
+  void MenuClosed(SimpleMenuModel* source) override {
+    on_close_menu_.Run();
+    is_menu_opened_ = false;
+  }
 
   bool IsCommandIdChecked(int command_id) const override { return false; }
 
   bool IsCommandIdEnabled(int command_id) const override { return true; }
 
+  bool IsMenuOpened() { return is_menu_opened_; }
+
  private:
   base::RepeatingCallback<void(const KioskAppMenuEntry&)> launch_app_callback_;
   base::RepeatingClosure on_show_menu_;
@@ -455,6 +463,7 @@
   std::vector<KioskAppMenuEntry> kiosk_apps_;
 
   bool is_launch_enabled_ = true;
+  bool is_menu_opened_ = false;
 };
 
 // Class that temporarily disables Guest login buttin on shelf.
@@ -969,11 +978,14 @@
           shelf->shelf_widget()->GetShelfBackgroundColor());
     }
     if (kiosk_instruction_bubble_) {
-      // Show kiosk instructions if the kiosk app button is visible.
-      if (kiosk_apps_button_->GetVisible())
+      // Show kiosk instructions if the kiosk app button is visible and the menu
+      // is not opened.
+      if (kiosk_apps_button_->GetVisible() &&
+          !kiosk_apps_button_->IsMenuOpened()) {
         kiosk_instruction_bubble_->GetWidget()->Show();
-      else
+      } else {
         kiosk_instruction_bubble_->GetWidget()->Hide();
+      }
     }
   }
 
diff --git a/ash/shelf/window_preview.cc b/ash/shelf/window_preview.cc
index fd2549b..b1e7edd 100644
--- a/ash/shelf/window_preview.cc
+++ b/ash/shelf/window_preview.cc
@@ -46,7 +46,7 @@
   title_ = new views::Label(window->GetTitle());
   close_button_ = new views::ImageButton(base::BindRepeating(
       &WindowPreview::CloseButtonPressed, base::Unretained(this)));
-  close_button_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
+  close_button_->SetFocusBehavior(FocusBehavior::NEVER);
 
   AddChildView(preview_container_view_);
   AddChildView(preview_view_);
@@ -135,6 +135,7 @@
 }
 
 void WindowPreview::OnThemeChanged() {
+  views::View::OnThemeChanged();
   const auto* color_provider = GetColorProvider();
   SkColor background_color =
       color_provider->GetColor(ui::kColorTooltipBackground);
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc
index cf7cd0c..74b97d3 100644
--- a/ash/style/ash_color_provider.cc
+++ b/ash/style/ash_color_provider.cc
@@ -215,6 +215,14 @@
       state != session_manager::SessionState::LOGIN_PRIMARY) {
     oobe_state_ = OobeDialogState::HIDDEN;
   }
+
+  // Disable dark mode for Shimless RMA
+  if (features::IsShimlessRMADarkModeDisabled() &&
+      state == session_manager::SessionState::RMA) {
+    RefreshColorsOnColorMode(/*is_dark_mode_enabled=*/false);
+    return;
+  }
+
   RefreshColorsOnColorMode(IsDarkModeEnabled());
 }
 
diff --git a/ash/wallpaper/wallpaper_pref_manager_unittest.cc b/ash/wallpaper/wallpaper_pref_manager_unittest.cc
index cbac8cc..6517ef1 100644
--- a/ash/wallpaper/wallpaper_pref_manager_unittest.cc
+++ b/ash/wallpaper/wallpaper_pref_manager_unittest.cc
@@ -230,7 +230,6 @@
 }
 
 TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoSynced) {
-  base::test::ScopedFeatureList scoped_features(features::kWallpaperWebUI);
   profile_helper_->RegisterPrefsForAccount(account_id_1);
 
   WallpaperInfo info = InfoWithType(WallpaperType::kOnline);
@@ -241,9 +240,6 @@
 }
 
 TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoSyncDisabled) {
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(features::kWallpaperWebUI);
-
   profile_helper_->RegisterPrefsForAccount(account_id_1);
   // This needs to be saved before sync is disabled or we can't get a pref
   // service.
diff --git a/ash/webui/os_feedback_ui/resources/feedback_flow.js b/ash/webui/os_feedback_ui/resources/feedback_flow.js
index 9b6120b..e694510 100644
--- a/ash/webui/os_feedback_ui/resources/feedback_flow.js
+++ b/ash/webui/os_feedback_ui/resources/feedback_flow.js
@@ -140,8 +140,7 @@
   handleGoBackClick_(event) {
     switch (event.detail.currentState) {
       case FeedbackFlowState.SHARE_DATA:
-        this.currentState_ = FeedbackFlowState.SEARCH;
-        this.shadowRoot.querySelector('search-page').focusInputElement();
+        this.navigateToSearchPage_();
         break;
       case FeedbackFlowState.CONFIRMATION:
         // Remove the text from previous search.
@@ -152,13 +151,19 @@
         const shareDataPage = this.shadowRoot.querySelector('share-data-page');
         shareDataPage.reEnableSendReportButton();
 
-        this.currentState_ = FeedbackFlowState.SEARCH;
+        this.navigateToSearchPage_();
         break;
       default:
         console.warn('unexpected state: ', event.detail.currentState);
     }
   }
 
+  /** @private */
+  navigateToSearchPage_() {
+    this.currentState_ = FeedbackFlowState.SEARCH;
+    this.shadowRoot.querySelector('search-page').focusInputElement();
+  }
+
   /**
    * @param {!FeedbackFlowState} newState
    */
diff --git a/ash/webui/personalization_app/test/personalization_app_browsertest.js b/ash/webui/personalization_app/test/personalization_app_browsertest.js
index 4495809..7a64510 100644
--- a/ash/webui/personalization_app/test/personalization_app_browsertest.js
+++ b/ash/webui/personalization_app/test/personalization_app_browsertest.js
@@ -26,7 +26,6 @@
   get featureList() {
     return {
       enabled: [
-        'ash::features::kWallpaperWebUI',
         'ash::features::kPersonalizationHub',
         'chromeos::features::kDarkLightMode',
       ]
diff --git a/ash/webui/shimless_rma/backend/version_updater.cc b/ash/webui/shimless_rma/backend/version_updater.cc
index 4ac1d5e..f7065c0 100644
--- a/ash/webui/shimless_rma/backend/version_updater.cc
+++ b/ash/webui/shimless_rma/backend/version_updater.cc
@@ -5,7 +5,6 @@
 #include "ash/webui/shimless_rma/backend/version_updater.h"
 
 #include "base/logging.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine/update_engine.pb.h"
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_state.h"
@@ -51,11 +50,11 @@
 }  // namespace
 
 VersionUpdater::VersionUpdater() {
-  DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
 }
 
 VersionUpdater::~VersionUpdater() {
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void VersionUpdater::SetOsUpdateStatusCallback(
@@ -119,11 +118,8 @@
   check_update_available_ = CHECKING;
   // RequestUpdateCheckWithoutApplying() will check if an update is available
   // without installing it.
-  DBusThreadManager::Get()
-      ->GetUpdateEngineClient()
-      ->RequestUpdateCheckWithoutApplying(
-          base::BindOnce(&VersionUpdater::OnRequestUpdateCheck,
-                         weak_ptr_factory_.GetWeakPtr()));
+  UpdateEngineClient::Get()->RequestUpdateCheckWithoutApplying(base::BindOnce(
+      &VersionUpdater::OnRequestUpdateCheck, weak_ptr_factory_.GetWeakPtr()));
 }
 
 bool VersionUpdater::UpdateOs() {
@@ -138,17 +134,14 @@
   // checked after using RequestUpdateCheckWithoutApplying.
 
   // RequestUpdateCheck will check if an update is available and install it.
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck(
-      base::BindOnce(&VersionUpdater::OnRequestUpdateCheck,
-                     weak_ptr_factory_.GetWeakPtr()));
+  UpdateEngineClient::Get()->RequestUpdateCheck(base::BindOnce(
+      &VersionUpdater::OnRequestUpdateCheck, weak_ptr_factory_.GetWeakPtr()));
   return true;
 }
 
 bool VersionUpdater::IsUpdateEngineIdle() {
-  return DBusThreadManager::Get()
-             ->GetUpdateEngineClient()
-             ->GetLastStatus()
-             .current_operation() == update_engine::Operation::IDLE;
+  return UpdateEngineClient::Get()->GetLastStatus().current_operation() ==
+         update_engine::Operation::IDLE;
 }
 
 void VersionUpdater::UpdateStatusChanged(
@@ -156,7 +149,7 @@
   if (status.current_operation() == update_engine::UPDATED_NEED_REBOOT) {
     // During RMA there are no other critical processes running so we can
     // automatically reboot.
-    DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate();
+    UpdateEngineClient::Get()->RebootAfterUpdate();
   }
   switch (status.current_operation()) {
     // If IDLE is received when there is a callback it means no update is
diff --git a/ash/webui/shimless_rma/resources/onboarding_select_components_page.js b/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
index cd6618f5..f71d926 100644
--- a/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
@@ -87,6 +87,18 @@
     this.setReworkFlowLink_();
     this.getComponents_();
     enableNextButton(this);
+
+    // Hide the gradient when the list is scrolled to the end.
+    this.shadowRoot.querySelector('.scroll-container')
+        .addEventListener('scroll', (event) => {
+          const gradient = this.shadowRoot.querySelector('.gradient');
+          if (event.target.scrollHeight - event.target.scrollTop ===
+              event.target.clientHeight) {
+            gradient.style.setProperty('visibility', 'hidden');
+          } else {
+            gradient.style.setProperty('visibility', 'visible');
+          }
+        });
   }
 
   /** @private */
diff --git a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
index 042e5ce7..aaca3d1 100644
--- a/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
+++ b/ash/webui/shimless_rma/resources/reimaging_calibration_failed_page.js
@@ -105,6 +105,18 @@
     super.ready();
     this.getInitialComponentsList_();
     enableNextButton(this);
+
+    // Hide the gradient when the list is scrolled to the end.
+    this.shadowRoot.querySelector('.scroll-container')
+        .addEventListener('scroll', (event) => {
+          const gradient = this.shadowRoot.querySelector('.gradient');
+          if (event.target.scrollHeight - event.target.scrollTop ===
+              event.target.clientHeight) {
+            gradient.style.setProperty('visibility', 'hidden');
+          } else {
+            gradient.style.setProperty('visibility', 'visible');
+          }
+        });
   }
 
   /** @private */
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
index c2531fbb..37553f75 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
+++ b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
@@ -162,6 +162,7 @@
         rgba(255,255,255,0), rgba(255,255,255,1));
       bottom: calc(var(--header-footer-height) + var(--container-vertical-padding));
       height: 40px;
+      pointer-events: none;
       position: fixed;
     }
 
diff --git a/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.js b/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.js
index b68576ff..c6d51c8 100644
--- a/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.js
+++ b/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.js
@@ -234,6 +234,8 @@
     // This is necessary because after the timeout "this" will be the window,
     // and not WrapupRepairCompletePage.
     const cutoffBattery = function(wrapupRepairCompletePage) {
+      wrapupRepairCompletePage.shadowRoot.querySelector('#batteryCutoffDialog')
+          .close();
       executeThenTransitionState(
           wrapupRepairCompletePage,
           () => wrapupRepairCompletePage.shimlessRmaService_.endRma(
@@ -248,6 +250,7 @@
 
   /** @private */
   cutoffBattery_() {
+    this.shadowRoot.querySelector('#batteryCutoffDialog').close();
     executeThenTransitionState(
         this,
         () => this.shimlessRmaService_.endRma(ShutdownMethod.kBatteryCutoff));
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 891a4cbd..73f2994 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3412,6 +3412,7 @@
       "file_version_info_win_unittest.cc",
       "process/launch_unittest_win.cc",
       "test/fake_iasync_operation_win_unittest.cc",
+      "test/test_file_util_win_unittest.cc",
       "test/test_reg_util_win_unittest.cc",
       "threading/platform_thread_win_unittest.cc",
       "time/time_win_unittest.cc",
diff --git a/base/allocator/partition_allocator/partition_alloc_base/bits.h b/base/allocator/partition_allocator/partition_alloc_base/bits.h
index f047afa..93e1a29 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/bits.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/bits.h
@@ -17,10 +17,6 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
 
-#if defined(COMPILER_MSVC)
-#include <intrin.h>
-#endif
-
 namespace partition_alloc::internal::base::bits {
 
 // Returns true iff |value| is a power of 2.
@@ -75,85 +71,6 @@
 //
 // C does not have an operator to do this, but fortunately the various
 // compilers have built-ins that map to fast underlying processor instructions.
-//
-// Prefer the clang path on Windows, as _BitScanReverse() and friends are not
-// constexpr.
-#if defined(COMPILER_MSVC) && !defined(__clang__)
-
-template <typename T, int bits = sizeof(T) * 8>
-PA_ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
-                            int>::type
-    CountLeadingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-  return PA_LIKELY(_BitScanReverse(&index, static_cast<uint32_t>(x)))
-             ? (31 - index - (32 - bits))
-             : bits;
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-PA_ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
-                            int>::type
-    CountLeadingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-// MSVC only supplies _BitScanReverse64 when building for a 64-bit target.
-#if defined(ARCH_CPU_64_BITS)
-  return PA_LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
-             ? (63 - index)
-             : 64;
-#else
-  uint32_t left = static_cast<uint32_t>(x >> 32);
-  if (PA_LIKELY(_BitScanReverse(&index, left)))
-    return 31 - index;
-
-  uint32_t right = static_cast<uint32_t>(x);
-  if (PA_LIKELY(_BitScanReverse(&index, right)))
-    return 63 - index;
-
-  return 64;
-#endif
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-PA_ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
-                            int>::type
-    CountTrailingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-  return PA_LIKELY(_BitScanForward(&index, static_cast<uint32_t>(x))) ? index
-                                                                      : bits;
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-PA_ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
-                            int>::type
-    CountTrailingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
-#if defined(ARCH_CPU_64_BITS)
-  return PA_LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
-                                                                        : 64;
-#else
-  uint32_t right = static_cast<uint32_t>(x);
-  if (PA_LIKELY(_BitScanForward(&index, right)))
-    return index;
-
-  uint32_t left = static_cast<uint32_t>(x >> 32);
-  if (PA_LIKELY(_BitScanForward(&index, left)))
-    return 32 + index;
-
-  return 64;
-#endif
-}
-
-#elif defined(COMPILER_GCC) || defined(__clang__)
-
 // __builtin_clz has undefined behaviour for an input of 0, even though there's
 // clearly a return value that makes sense, and even though some processor clz
 // instructions have defined behaviour for 0. We could drop to raw __asm__ to
@@ -182,8 +99,6 @@
                           : bits;
 }
 
-#endif
-
 // Returns the integer i such as 2^i <= n < 2^(i+1).
 //
 // There is a common `BitLength` function, which returns the number of bits
diff --git a/base/bits.h b/base/bits.h
index 51c8e894..e4622a5 100644
--- a/base/bits.h
+++ b/base/bits.h
@@ -17,10 +17,6 @@
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
 
-#if defined(COMPILER_MSVC)
-#include <intrin.h>
-#endif
-
 namespace base {
 namespace bits {
 
@@ -79,86 +75,8 @@
 // C does not have an operator to do this, but fortunately the various
 // compilers have built-ins that map to fast underlying processor instructions.
 //
-// Prefer the clang path on Windows, as _BitScanReverse() and friends are not
-// constexpr.
-//
 // TODO(pkasting): When C++20 is available, replace with std::countl_zero() and
 // similar.
-#if defined(COMPILER_MSVC) && !defined(__clang__)
-
-template <typename T, int bits = sizeof(T) * 8>
-ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
-                            int>::type
-    CountLeadingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-  return LIKELY(_BitScanReverse(&index, static_cast<uint32_t>(x)))
-             ? (31 - index - (32 - bits))
-             : bits;
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
-                            int>::type
-    CountLeadingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-// MSVC only supplies _BitScanReverse64 when building for a 64-bit target.
-#if defined(ARCH_CPU_64_BITS)
-  return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
-             ? (63 - index)
-             : 64;
-#else
-  uint32_t left = static_cast<uint32_t>(x >> 32);
-  if (LIKELY(_BitScanReverse(&index, left)))
-    return 31 - index;
-
-  uint32_t right = static_cast<uint32_t>(x);
-  if (LIKELY(_BitScanReverse(&index, right)))
-    return 63 - index;
-
-  return 64;
-#endif
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
-                            int>::type
-    CountTrailingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-  return LIKELY(_BitScanForward(&index, static_cast<uint32_t>(x))) ? index
-                                                                   : bits;
-}
-
-template <typename T, int bits = sizeof(T) * 8>
-ALWAYS_INLINE
-    typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
-                            int>::type
-    CountTrailingZeroBits(T x) {
-  static_assert(bits > 0, "invalid instantiation");
-  unsigned long index;
-// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
-#if defined(ARCH_CPU_64_BITS)
-  return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
-                                                                     : 64;
-#else
-  uint32_t right = static_cast<uint32_t>(x);
-  if (LIKELY(_BitScanForward(&index, right)))
-    return index;
-
-  uint32_t left = static_cast<uint32_t>(x >> 32);
-  if (LIKELY(_BitScanForward(&index, left)))
-    return 32 + index;
-
-  return 64;
-#endif
-}
-
-#elif defined(COMPILER_GCC) || defined(__clang__)
 
 // __builtin_clz has undefined behaviour for an input of 0, even though there's
 // clearly a return value that makes sense, and even though some processor clz
@@ -188,8 +106,6 @@
                        : bits;
 }
 
-#endif
-
 // Returns the integer i such as 2^i <= n < 2^(i+1).
 //
 // There is a common `BitLength` function, which returns the number of bits
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
index 5a49e06..7056ef3 100644
--- a/base/json/json_file_value_serializer.cc
+++ b/base/json/json_file_value_serializer.cc
@@ -64,7 +64,7 @@
   last_read_size_ = 0u;
   if (!base::ReadFileToString(json_file_path_, json_string)) {
 #if BUILDFLAG(IS_WIN)
-    int error = ::GetLastError();
+    DWORD error = ::GetLastError();
     if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
       return JSON_FILE_LOCKED;
     } else if (error == ERROR_ACCESS_DENIED) {
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index b632a47..ff3c5054 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -63,7 +63,7 @@
 }
 
 const int32_t kExtendedASCIIStart = 0x80;
-constexpr uint32_t kUnicodeReplacementPoint = 0xFFFD;
+constexpr base_icu::UChar32 kUnicodeReplacementPoint = 0xFFFD;
 
 // UnprefixedHexStringToInt acts like |HexStringToInt|, but enforces that the
 // input consists purely of hex digits. I.e. no "0x" nor "OX" prefix is
@@ -194,8 +194,8 @@
 JSONParser::StringBuilder& JSONParser::StringBuilder::operator=(
     StringBuilder&& other) = default;
 
-void JSONParser::StringBuilder::Append(uint32_t point) {
-  DCHECK(IsValidCodepoint(static_cast<base_icu::UChar32>(point)));
+void JSONParser::StringBuilder::Append(base_icu::UChar32 point) {
+  DCHECK(IsValidCodepoint(point));
 
   if (point < kExtendedASCIIStart && !string_) {
     DCHECK_EQ(static_cast<char>(point), pos_[length_]);
@@ -205,7 +205,7 @@
     if (UNLIKELY(point == kUnicodeReplacementPoint)) {
       string_->append(kUnicodeReplacementString);
     } else {
-      WriteUnicodeCharacter(static_cast<base_icu::UChar32>(point), &*string_);
+      WriteUnicodeCharacter(point, &*string_);
     }
   }
 }
@@ -621,7 +621,7 @@
         }
         case 'u': {  // UTF-16 sequence.
           // UTF units are of the form \uXXXX.
-          uint32_t code_point;
+          base_icu::UChar32 code_point;
           if (!DecodeUTF16(&code_point)) {
             ReportError(JSON_INVALID_ESCAPE, -1);
             return false;
@@ -675,7 +675,7 @@
 }
 
 // Entry is at the first X in \uXXXX.
-bool JSONParser::DecodeUTF16(uint32_t* out_code_point) {
+bool JSONParser::DecodeUTF16(base_icu::UChar32* out_code_point) {
   absl::optional<StringPiece> escape_sequence = ConsumeChars(4);
   if (!escape_sequence)
     return false;
@@ -720,7 +720,7 @@
       return true;
     }
 
-    uint32_t code_point =
+    base_icu::UChar32 code_point =
         CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low);
 
     *out_code_point = code_point;
@@ -852,7 +852,7 @@
 void JSONParser::ReportError(JsonParseError code, int column_adjust) {
   error_code_ = code;
   error_line_ = line_number_;
-  error_column_ = index_ - index_last_line_ + column_adjust;
+  error_column_ = static_cast<int>(index_ - index_last_line_) + column_adjust;
 
   // For a final blank line ('\n' and then EOF), a negative column_adjust may
   // put us below 1, which doesn't really make sense for 1-based columns.
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
index aad1b3a..680d967 100644
--- a/base/json/json_parser.h
+++ b/base/json/json_parser.h
@@ -16,6 +16,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/json/json_common.h"
 #include "base/strings/string_piece.h"
+#include "base/third_party/icu/icu_utf.h"
 #include "base/values.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -133,7 +134,7 @@
     // Appends the Unicode code point |point| to the string, either by
     // increasing the |length_| of the string if the string has not been
     // converted, or by appending the UTF8 bytes for the code point.
-    void Append(uint32_t point);
+    void Append(base_icu::UChar32 point);
 
     // Converts the builder from its default StringPiece to a full std::string,
     // performing a copy. Once a builder is converted, it cannot be made a
@@ -212,7 +213,7 @@
   // bytes (parser is wound to the first character of a HEX sequence, with the
   // potential for consuming another \uXXXX for a surrogate). Returns true on
   // success and places the code point |out_code_point|, and false on failure.
-  bool DecodeUTF16(uint32_t* out_code_point);
+  bool DecodeUTF16(base_icu::UChar32* out_code_point);
 
   // Assuming that the parser is wound to the start of a valid JSON number,
   // this parses and converts it to either an int or double value.
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index 69362f7..d1623cc 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -33,7 +33,7 @@
 // Try to escape the |code_point| if it is a known special character. If
 // successful, returns true and appends the escape sequence to |dest|. This
 // isn't required by the spec, but it's more readable by humans.
-bool EscapeSpecialCodePoint(uint32_t code_point, std::string* dest) {
+bool EscapeSpecialCodePoint(base_icu::UChar32 code_point, std::string* dest) {
   // WARNING: if you add a new case here, you need to update the reader as well.
   // Note: \v is in the reader, but not here since the JSON spec doesn't
   // allow it.
@@ -141,14 +141,16 @@
   if (put_in_quotes)
     dest.push_back('"');
 
-  for (unsigned char c : str) {
+  for (char c : str) {
     if (EscapeSpecialCodePoint(c, &dest))
       continue;
 
-    if (c < 32 || c > 126)
-      base::StringAppendF(&dest, kU16EscapeFormat, c);
-    else
+    if (c < 32 || c > 126) {
+      base::StringAppendF(&dest, kU16EscapeFormat,
+                          static_cast<unsigned char>(c));
+    } else {
       dest.push_back(c);
+    }
   }
 
   if (put_in_quotes)
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
index f35b983..0fa5c83 100644
--- a/base/test/test_file_util_win.cc
+++ b/base/test/test_file_util_win.cc
@@ -116,8 +116,12 @@
 }
 
 bool EvictFileFromSystemCache(const FilePath& file) {
+  FilePath::StringType file_value = file.value();
+  if (file_value.length() >= MAX_PATH && file.IsAbsolute()) {
+    file_value.insert(0, L"\\\\?\\");
+  }
   win::ScopedHandle file_handle(
-      CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr,
+      CreateFile(file_value.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr,
                  OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr));
   if (!file_handle.is_valid())
     return false;
diff --git a/base/test/test_file_util_win_unittest.cc b/base/test/test_file_util_win_unittest.cc
new file mode 100644
index 0000000..f940e9f
--- /dev/null
+++ b/base/test/test_file_util_win_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright 2022 Yandex LLC. All rights reserved.
+
+#include "base/test/test_file_util.h"
+
+#include <windows.h>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class ScopedFileForTest {
+ public:
+  ScopedFileForTest(const FilePath& filename)
+      : long_path_(L"\\\\?\\" + filename.value()) {
+    win::ScopedHandle handle(::CreateFile(long_path_.c_str(), GENERIC_WRITE, 0,
+                                          nullptr, CREATE_NEW,
+                                          FILE_ATTRIBUTE_NORMAL, nullptr));
+
+    valid_ = handle.is_valid();
+  }
+
+  ScopedFileForTest(ScopedFileForTest&&) = delete;
+  ScopedFileForTest& operator=(ScopedFileForTest&&) = delete;
+
+  bool IsValid() const { return valid_; }
+
+  ~ScopedFileForTest() {
+    if (valid_)
+      ::DeleteFile(long_path_.c_str());
+  }
+
+ private:
+  FilePath::StringType long_path_;
+  bool valid_;
+};
+
+}  // namespace
+
+TEST(TestFileUtil, EvictNonExistingFile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  FilePath path = temp_dir.GetPath().Append(FilePath(L"non_existing"));
+
+  ASSERT_FALSE(EvictFileFromSystemCache(path));
+}
+
+TEST(TestFileUtil, EvictFileWithShortName) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  FilePath temp_file = temp_dir.GetPath().Append(FilePath(L"file_for_evict"));
+  ASSERT_TRUE(temp_file.value().length() < MAX_PATH);
+  ScopedFileForTest file(temp_file);
+  ASSERT_TRUE(file.IsValid());
+
+  ASSERT_TRUE(EvictFileFromSystemCache(temp_file));
+}
+
+TEST(TestFileUtil, EvictFileWithLongName) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  // Create subdirectory with long name.
+  FilePath subdir =
+      temp_dir.GetPath().Append(FilePath(std::wstring(100, L'a')));
+  ASSERT_TRUE(subdir.value().length() < MAX_PATH);
+  ASSERT_TRUE(CreateDirectory(subdir));
+
+  // Create file with long name in subdirectory.
+  FilePath temp_file = subdir.Append(FilePath(std::wstring(200, L'b')));
+  ASSERT_TRUE(temp_file.value().length() > MAX_PATH);
+  ScopedFileForTest file(temp_file);
+  ASSERT_TRUE(file.IsValid());
+
+  ASSERT_TRUE(EvictFileFromSystemCache(temp_file));
+}
+
+}  // namespace base
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
index 6fa41010..0b50b710 100644
--- a/base/third_party/icu/icu_utf.h
+++ b/base/third_party/icu/icu_utf.h
@@ -118,7 +118,7 @@
  * @return TRUE or FALSE
  * @stable ICU 2.4
  */
-#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+#define CBU_IS_SURROGATE(c) (((uint32_t)(c)&0xfffff800) == 0xd800)
 
 /**
  * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 7eab6d0..d263a89 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-8.20220621.1.1
+8.20220621.2.1
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 3d3fc0fa..63a92b2 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -28,6 +28,7 @@
 #include "cc/trees/property_tree_builder.h"
 #include "cc/trees/scroll_node.h"
 #include "cc/trees/transform_node.h"
+#include "cc/trees/viewport_property_ids.h"
 #include "components/viz/common/display/de_jelly.h"
 #include "components/viz/common/shared_element_resource_id.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -1425,7 +1426,8 @@
   }
 }
 
-void ComputeTransforms(TransformTree* transform_tree) {
+void ComputeTransforms(TransformTree* transform_tree,
+                       const ViewportPropertyIds& viewport_property_ids) {
   if (!transform_tree->needs_update()) {
 #if DCHECK_IS_ON()
     // If the transform tree does not need an update, no TransformNode should
@@ -1439,7 +1441,7 @@
   }
   for (int i = kContentsRootPropertyNodeId;
        i < static_cast<int>(transform_tree->size()); ++i)
-    transform_tree->UpdateTransforms(i);
+    transform_tree->UpdateTransforms(i, &viewport_property_ids);
   transform_tree->set_needs_update(false);
 }
 
@@ -1460,14 +1462,16 @@
     property_trees->clip_tree_mutable().set_needs_update(true);
     property_trees->effect_tree_mutable().set_needs_update(true);
   }
-  ComputeTransforms(&property_trees->transform_tree_mutable());
+
+  ComputeTransforms(&property_trees->transform_tree_mutable(),
+                    layer_tree_host->viewport_property_ids());
   ComputeEffects(&property_trees->effect_tree_mutable());
   // Computation of clips uses ToScreen which is updated while computing
   // transforms. So, ComputeTransforms should be before ComputeClips.
   ComputeClips(property_trees);
 }
 
-void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
+void UpdatePropertyTreesAndRenderSurfaces(LayerTreeImpl* layer_tree_impl,
                                           PropertyTrees* property_trees) {
   if (property_trees->transform_tree().needs_update()) {
     property_trees->clip_tree_mutable().set_needs_update(true);
@@ -1475,7 +1479,8 @@
   }
   UpdateRenderTarget(&property_trees->effect_tree_mutable());
 
-  ComputeTransforms(&property_trees->transform_tree_mutable());
+  ComputeTransforms(&property_trees->transform_tree_mutable(),
+                    layer_tree_impl->viewport_property_ids());
   ComputeEffects(&property_trees->effect_tree_mutable());
   // Computation of clips uses ToScreen which is updated while computing
   // transforms. So, ComputeTransforms should be before ComputeClips.
@@ -1554,8 +1559,7 @@
       gfx::RectF(layer_tree_impl->GetDeviceViewport()));
   property_trees->transform_tree_mutable().SetRootScaleAndTransform(
       layer_tree_impl->device_scale_factor(), layer_tree_impl->DrawTransform());
-  UpdatePropertyTreesAndRenderSurfaces(layer_tree_impl->root_layer(),
-                                       property_trees);
+  UpdatePropertyTreesAndRenderSurfaces(layer_tree_impl, property_trees);
 
   {
     TRACE_EVENT0("cc", "draw_property_utils::FindLayersThatNeedUpdates");
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index b80b38e3..2c6d94c 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -24,6 +24,7 @@
 class PropertyTrees;
 struct EffectNode;
 struct TransformNode;
+struct ViewportPropertyIds;
 
 namespace draw_property_utils {
 
@@ -32,7 +33,9 @@
 
 // Computes combined (screen space) transforms for every node in the transform
 // tree. This must be done prior to calling |ComputeClips|.
-void CC_EXPORT ComputeTransforms(TransformTree* transform_tree);
+void CC_EXPORT
+ComputeTransforms(TransformTree* transform_tree,
+                  const ViewportPropertyIds& viewport_property_ids);
 
 // Computes screen space opacity for every node in the opacity tree.
 void CC_EXPORT ComputeEffects(EffectTree* effect_tree);
@@ -40,7 +43,7 @@
 void CC_EXPORT UpdatePropertyTrees(LayerTreeHost* layer_tree_host);
 
 void CC_EXPORT
-UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
+UpdatePropertyTreesAndRenderSurfaces(LayerTreeImpl* layer_tree_impl,
                                      PropertyTrees* property_trees);
 
 void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 6cb6a1e..49bba472 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -807,6 +807,10 @@
     return recording_scale_factor_;
   }
 
+  const ViewportPropertyIds& viewport_property_ids() const {
+    return pending_commit_state()->viewport_property_ids;
+  }
+
   void SetSourceURL(ukm::SourceId source_id, const GURL& url);
   base::ReadOnlySharedMemoryRegion CreateSharedMemoryForSmoothnessUkm();
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 691496d..caaead85 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2939,11 +2939,16 @@
   // it will push the updated viz::LocalSurfaceId. Begin Impl Frame production
   // if it has already become activated, or is on the |pending_tree| to be
   // activated during this frame's production.
-  const viz::LocalSurfaceId& upcoming_lsid =
-      pending_tree() ? pending_tree()->local_surface_id_from_parent()
-                     : active_tree()->local_surface_id_from_parent();
-  if (target_local_surface_id_.IsNewerThan(upcoming_lsid)) {
-    return false;
+  //
+  // However when using a synchronous compositor we skip this throttling
+  // completely.
+  if (!settings_.using_synchronous_renderer_compositor) {
+    const viz::LocalSurfaceId& upcoming_lsid =
+        pending_tree() ? pending_tree()->local_surface_id_from_parent()
+                       : active_tree()->local_surface_id_from_parent();
+    if (target_local_surface_id_.IsNewerThan(upcoming_lsid)) {
+      return false;
+    }
   }
 
   if (is_likely_to_require_a_draw_) {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index dadca4b..31e4fe9 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -4413,9 +4413,11 @@
 
   // Verify this scroll delta is consistent with the snapped position of the
   // scroll layer.
-  draw_property_utils::ComputeTransforms(&scroll_layer->layer_tree_impl()
-                                              ->property_trees()
-                                              ->transform_tree_mutable());
+  draw_property_utils::ComputeTransforms(
+      &scroll_layer->layer_tree_impl()
+           ->property_trees()
+           ->transform_tree_mutable(),
+      scroll_layer->layer_tree_impl()->viewport_property_ids());
   EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(0, -19),
                       scroll_layer->ScreenSpaceTransform().To2dTranslation());
 }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index a6389b6..c4602129 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -450,6 +450,10 @@
     return display_color_spaces_;
   }
 
+  const ViewportPropertyIds& viewport_property_ids() const {
+    return viewport_property_ids_;
+  }
+
   SyncedElasticOverscroll* elastic_overscroll() {
     return elastic_overscroll_.get();
   }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 4e8eaad0..7a3bb079 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -22,6 +22,7 @@
 #include "cc/trees/property_tree.h"
 #include "cc/trees/scroll_node.h"
 #include "cc/trees/transform_node.h"
+#include "cc/trees/viewport_property_ids.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "ui/gfx/geometry/outsets_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
@@ -57,7 +58,6 @@
 TransformTree::TransformTree(PropertyTrees* property_trees)
     : PropertyTree<TransformNode>(property_trees),
       page_scale_factor_(1.f),
-      overscroll_node_id_(kInvalidPropertyNodeId),
       fixed_elements_dont_overscroll_(false),
       device_scale_factor_(1.f),
       device_transform_scale_factor_(1.f) {
@@ -128,7 +128,6 @@
   PropertyTree<TransformNode>::clear();
 
   page_scale_factor_ = 1.f;
-  overscroll_node_id_ = kInvalidPropertyNodeId;
   fixed_elements_dont_overscroll_ = false;
   device_scale_factor_ = 1.f;
   device_transform_scale_factor_ = 1.f;
@@ -174,14 +173,16 @@
   }
 }
 
-void TransformTree::UpdateTransforms(int id) {
+void TransformTree::UpdateTransforms(
+    int id,
+    const ViewportPropertyIds* viewport_property_ids) {
   TransformNode* node = Node(id);
   TransformNode* parent_node = parent(node);
   DCHECK(parent_node);
   // TODO(flackr): Only dirty when scroll offset changes.
   if (node->sticky_position_constraint_id >= 0 ||
       node->needs_local_transform_update || ShouldUndoOverscroll(node)) {
-    UpdateLocalTransform(node);
+    UpdateLocalTransform(node, viewport_property_ids);
   } else {
     UndoSnapping(node);
   }
@@ -460,12 +461,19 @@
 
 void TransformTree::UpdateFixedNodeTransformAndClip(
     const TransformNode* node,
-    gfx::Vector2dF& fixed_position_adjustment) {
-  if (!ShouldUndoOverscroll(node) ||
-      overscroll_node_id_ == kInvalidPropertyNodeId)
+    gfx::Vector2dF& fixed_position_adjustment,
+    const ViewportPropertyIds* viewport_property_ids) {
+  const int transform_id =
+      viewport_property_ids
+          ? viewport_property_ids->overscroll_elasticity_transform
+          : kInvalidPropertyNodeId;
+  const int clip_id = viewport_property_ids ? viewport_property_ids->outer_clip
+                                            : kInvalidPropertyNodeId;
+  if (!ShouldUndoOverscroll(node) || transform_id == kInvalidPropertyNodeId ||
+      clip_id == kInvalidPropertyNodeId)
     return;
 
-  const TransformNode* overscroll_node = Node(overscroll_node_id_);
+  const TransformNode* overscroll_node = Node(transform_id);
   const gfx::Vector2dF overscroll_offset =
       overscroll_node->scroll_offset.OffsetFromOrigin();
   if (overscroll_offset.IsZero())
@@ -475,24 +483,24 @@
       gfx::ScaleVector2d(overscroll_offset, 1.f / page_scale_factor());
 
   ClipTree& clip_tree = property_trees()->clip_tree_mutable();
-  ClipNode* clip_node = clip_tree.Node(clip_tree.overscroll_node_id());
+  ClipNode* clip_node = clip_tree.Node(clip_id);
+  DCHECK(clip_node);
 
-  if (clip_node) {
-    // Inflate the clip rect based on the overscroll direction.
-    gfx::OutsetsF outsets;
-    fixed_position_adjustment.x() < 0
-        ? outsets.set_left(-fixed_position_adjustment.x())
-        : outsets.set_right(fixed_position_adjustment.x());
-    fixed_position_adjustment.y() < 0
-        ? outsets.set_top(-fixed_position_adjustment.y())
-        : outsets.set_bottom(fixed_position_adjustment.y());
-
-    clip_node->clip.Outset(outsets);
-    clip_tree.set_needs_update(true);
-  }
+  // Inflate the clip rect based on the overscroll direction.
+  gfx::OutsetsF outsets;
+  fixed_position_adjustment.x() < 0
+      ? outsets.set_left(-fixed_position_adjustment.x())
+      : outsets.set_right(fixed_position_adjustment.x());
+  fixed_position_adjustment.y() < 0
+      ? outsets.set_top(-fixed_position_adjustment.y())
+      : outsets.set_bottom(fixed_position_adjustment.y());
+  clip_node->clip.Outset(outsets);
+  clip_tree.set_needs_update(true);
 }
 
-void TransformTree::UpdateLocalTransform(TransformNode* node) {
+void TransformTree::UpdateLocalTransform(
+    TransformNode* node,
+    const ViewportPropertyIds* viewport_property_ids) {
   gfx::Transform transform;
   transform.Translate3d(node->post_translation.x() + node->origin.x(),
                         node->post_translation.y() + node->origin.y(),
@@ -504,7 +512,8 @@
         property_trees()->outer_viewport_container_bounds_delta().y());
   }
 
-  UpdateFixedNodeTransformAndClip(node, fixed_position_adjustment);
+  UpdateFixedNodeTransformAndClip(node, fixed_position_adjustment,
+                                  viewport_property_ids);
   transform.Translate(fixed_position_adjustment -
                       node->scroll_offset.OffsetFromOrigin());
   transform.Translate(StickyPositionOffset(node));
@@ -709,7 +718,6 @@
 bool TransformTree::operator==(const TransformTree& other) const {
   return PropertyTree::operator==(other) &&
          page_scale_factor_ == other.page_scale_factor() &&
-         overscroll_node_id_ == other.overscroll_node_id() &&
          fixed_elements_dont_overscroll_ ==
              other.fixed_elements_dont_overscroll() &&
          device_scale_factor_ == other.device_scale_factor() &&
@@ -1265,8 +1273,7 @@
 }
 
 ClipTree::ClipTree(PropertyTrees* property_trees)
-    : PropertyTree<ClipNode>(property_trees),
-      overscroll_node_id_(kInvalidPropertyNodeId) {}
+    : PropertyTree<ClipNode>(property_trees) {}
 
 void ClipTree::SetViewportClip(gfx::RectF viewport_rect) {
   if (size() < 2)
@@ -1286,8 +1293,7 @@
 
 #if DCHECK_IS_ON()
 bool ClipTree::operator==(const ClipTree& other) const {
-  return PropertyTree::operator==(other) &&
-         overscroll_node_id_ == other.overscroll_node_id();
+  return PropertyTree::operator==(other);
 }
 #endif
 
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 12ecb6e..78f52a3 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -53,6 +53,7 @@
 class RenderSurfaceImpl;
 struct RenderSurfacePropertyChangedFlags;
 struct CompositorCommitData;
+struct ViewportPropertyIds;
 
 using SyncedScrollOffset =
     SyncedProperty<AdditionGroup<gfx::PointF, gfx::Vector2dF>>;
@@ -182,7 +183,9 @@
                            const gfx::Transform& transform);
   void ResetChangeTracking();
   // Updates the parent, target, and screen space transforms and snapping.
-  void UpdateTransforms(int id);
+  void UpdateTransforms(
+      int id,
+      const ViewportPropertyIds* viewport_property_ids = nullptr);
   void UpdateTransformChanged(TransformNode* node, TransformNode* parent_node);
   void UpdateNodeAndAncestorsAreAnimatedOrInvertible(
       TransformNode* node,
@@ -199,8 +202,6 @@
   }
   float page_scale_factor() const { return page_scale_factor_; }
 
-  void set_overscroll_node_id(int id) { overscroll_node_id_ = id; }
-  int overscroll_node_id() const { return overscroll_node_id_; }
   void set_fixed_elements_dont_overscroll(bool value) {
     fixed_elements_dont_overscroll_ = value;
   }
@@ -249,7 +250,8 @@
   bool ShouldUndoOverscroll(const TransformNode* node) const;
   void UpdateFixedNodeTransformAndClip(
       const TransformNode* node,
-      gfx::Vector2dF& fixed_position_adjustment);
+      gfx::Vector2dF& fixed_position_adjustment,
+      const ViewportPropertyIds* viewport_property_ids);
 
   const StickyPositionNodeData* GetStickyPositionData(int node_id) const {
     return const_cast<TransformTree*>(this)->MutableStickyPositionData(node_id);
@@ -276,7 +278,8 @@
 
   StickyPositionNodeData* MutableStickyPositionData(int node_id);
   gfx::Vector2dF StickyPositionOffset(TransformNode* node);
-  void UpdateLocalTransform(TransformNode* node);
+  void UpdateLocalTransform(TransformNode* node,
+                            const ViewportPropertyIds* viewport_property_ids);
   void UpdateScreenSpaceTransform(TransformNode* node,
                                   TransformNode* parent_node);
   void UpdateAnimationProperties(TransformNode* node,
@@ -291,7 +294,6 @@
   // scale is calculated using page scale factor, device scale factor and the
   // scale factor of device transform. So we need to store them explicitly.
   float page_scale_factor_;
-  int overscroll_node_id_;
   bool fixed_elements_dont_overscroll_;
   float device_scale_factor_;
   float device_transform_scale_factor_;
@@ -333,14 +335,6 @@
 
   void SetViewportClip(gfx::RectF viewport_rect);
   gfx::RectF ViewportClip() const;
-
-  void set_overscroll_node_id(int id) { overscroll_node_id_ = id; }
-  int overscroll_node_id() const { return overscroll_node_id_; }
-
- private:
-  // Used to track the ClipNode that is corresponding to the overscroll
-  // TransformNode.
-  int overscroll_node_id_;
 };
 
 class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> {
diff --git a/cc/trees/property_tree_unittest.cc b/cc/trees/property_tree_unittest.cc
index b2ec896d..13dcfc9 100644
--- a/cc/trees/property_tree_unittest.cc
+++ b/cc/trees/property_tree_unittest.cc
@@ -16,6 +16,7 @@
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/scroll_node.h"
 #include "cc/trees/transform_node.h"
+#include "cc/trees/viewport_property_ids.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/test/geometry_util.h"
@@ -202,6 +203,7 @@
   FakeProtectedSequenceSynchronizer synchronizer;
   PropertyTrees property_trees(synchronizer);
 
+  ViewportPropertyIds viewport_property_ids;
   ClipTree& clip_tree = property_trees.clip_tree_mutable();
   const gfx::RectF clip_rect(0, 0, 100, 100);
   ClipNode clip_node;
@@ -209,20 +211,20 @@
   clip_node.parent_id = 0;
   clip_node.clip = clip_rect;
   clip_tree.Insert(clip_node, 0);
-  clip_tree.set_overscroll_node_id(clip_node.id);
+  viewport_property_ids.outer_clip = clip_node.id;
 
   TransformTree& transform_tree = property_trees.transform_tree_mutable();
   TransformNode contents_root;
   contents_root.local.Translate(2, 2);
   contents_root.id = transform_tree.Insert(contents_root, 0);
-  transform_tree.UpdateTransforms(1);
+  transform_tree.UpdateTransforms(1, &viewport_property_ids);
 
   const gfx::PointF overscroll_offset(0, 10);
   TransformNode overscroll_node;
   overscroll_node.scroll_offset = overscroll_offset;
   overscroll_node.id = transform_tree.Insert(overscroll_node, 1);
+  viewport_property_ids.overscroll_elasticity_transform = overscroll_node.id;
 
-  transform_tree.set_overscroll_node_id(overscroll_node.id);
   transform_tree.set_fixed_elements_dont_overscroll(true);
 
   TransformNode fixed_node;
@@ -231,8 +233,9 @@
 
   EXPECT_TRUE(transform_tree.ShouldUndoOverscroll(&fixed_node));
 
-  transform_tree.UpdateTransforms(2);  // overscroll_node
-  transform_tree.UpdateTransforms(3);  // fixed_node
+  transform_tree.UpdateTransforms(2,
+                                  &viewport_property_ids);  // overscroll_node
+  transform_tree.UpdateTransforms(3, &viewport_property_ids);  // fixed_node
 
   gfx::Transform expected;
   expected.Translate(overscroll_offset.OffsetFromOrigin());
@@ -240,7 +243,7 @@
 
   gfx::RectF expected_clip_rect(clip_rect);
   expected_clip_rect.set_height(clip_rect.height() + overscroll_offset.y());
-  EXPECT_EQ(clip_tree.Node(clip_tree.overscroll_node_id())->clip,
+  EXPECT_EQ(clip_tree.Node(viewport_property_ids.outer_clip)->clip,
             expected_clip_rect);
 }
 
@@ -279,7 +282,7 @@
   tree.Node(grand_child)->local = rotation_about_x;
 
   tree.set_needs_update(true);
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
   property_trees.ResetCachedData();
 
   gfx::Transform flattened_rotation_about_x = rotation_about_x;
@@ -306,7 +309,7 @@
   // Remove flattening at grand_child, and recompute transforms.
   tree.Node(grand_child)->flattens_inherited_transform = false;
   tree.set_needs_update(true);
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
 
   property_trees.GetToTarget(grand_child, effect_parent, &to_target);
   EXPECT_TRANSFORM_EQ(rotation_about_x * rotation_about_x, to_target);
@@ -417,7 +420,7 @@
   tree.Node(grand_parent_id)->needs_local_transform_update = true;
   tree.set_needs_update(true);
 
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
 
   transform.MakeIdentity();
   tree.CombineTransformsBetween(child_id, grand_parent_id, &transform);
@@ -428,7 +431,7 @@
   tree.Node(grand_parent_id)->needs_local_transform_update = true;
   tree.set_needs_update(true);
 
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
 
   transform.MakeIdentity();
   tree.CombineTransformsBetween(child_id, grand_parent_id, &transform);
@@ -456,7 +459,7 @@
   tree.Node(grand_child)->flattens_inherited_transform = true;
 
   tree.set_needs_update(true);
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
 
   gfx::Transform flattened_rotation_about_x = rotation_about_x;
   flattened_rotation_about_x.FlattenTo2d();
@@ -511,7 +514,7 @@
   child_node->local.Translate(1.3f, 1.3f);
   tree.set_needs_update(true);
 
-  draw_property_utils::ComputeTransforms(&tree);
+  draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
   property_trees.ResetCachedData();
 
   gfx::Transform from_target;
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 7cf7b919..f90a117 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1659,7 +1659,6 @@
     "//components/image_fetcher:java",
     "//components/infobars/android:java",
     "//components/infobars/core:infobar_enums_java",
-    "//components/installedapp/android:javatests",
     "//components/javascript_dialogs/android:java",
     "//components/language/android:java",
     "//components/language/android:javatests",
@@ -1764,7 +1763,6 @@
     "//ui/android:clipboard_java_test_support",
     "//ui/android:ui_java",
     "//ui/android:ui_java_test_support",
-    "//ui/android:ui_javatests",
     "//ui/base/mojom:mojom_java",
     "//url:gurl_java",
     "//url:gurl_junit_test_support",
@@ -3211,6 +3209,7 @@
     "//chrome/browser/ui/android/night_mode:unit_device_javatests",
     "//chrome/browser/ui/android/omnibox:unit_device_javatests",
     "//chrome/browser/ui/android/searchactivityutils:unit_device_javatests",
+    "//chrome/browser/ui/android/signin:unit_device_javatests",
     "//chrome/browser/ui/messages/android:unit_device_javatests",
     "//chrome/browser/user_education:unit_device_javatests",
     "//chrome/browser/video_tutorials/internal:unit_device_javatests",
@@ -3223,11 +3222,13 @@
     "//components/embedder_support/android:embedder_support_javatests",
     "//components/external_intents/android:unit_device_javatests",
     "//components/infobars/android:unit_device_javatests",
+    "//components/installedapp/android:unit_device_javatests",
     "//components/messages/android/internal:unit_device_javatests",
     "//components/payments/content/android:unit_device_javatests",
     "//components/signin/public/android:unit_device_javatests",
     "//components/strictmode/android:unit_device_javatests",
     "//components/url_formatter/android:unit_device_javatests",
+    "//ui/android:ui_unit_device_javatests",
   ]
 
   data_deps = [
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 748cd0f6..f26c5ac 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -213,7 +213,6 @@
   "javatests/src/org/chromium/chrome/browser/hardware_acceleration/ToastHWATest.java",
   "javatests/src/org/chromium/chrome/browser/hardware_acceleration/Utils.java",
   "javatests/src/org/chromium/chrome/browser/hardware_acceleration/WebappActivityHWATest.java",
-  "javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java",
   "javatests/src/org/chromium/chrome/browser/history/HistoryTest.java",
   "javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java",
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 3a6460a..336b34e 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -23,8 +23,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
@@ -87,7 +85,6 @@
 import org.chromium.chrome.browser.tasks.ReturnToChromeUtil;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
-import org.chromium.chrome.browser.ui.appmenu.AppMenuTestSupport;
 import org.chromium.chrome.features.tasks.SingleTabSwitcherMediator;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -98,12 +95,10 @@
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.content_public.browser.test.util.RenderProcessHostUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.test.util.UiRestriction;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
 
 /**
  * Integration tests of the {@link StartSurface} for cases with tabs. See {@link
@@ -984,58 +979,6 @@
     @Test
     @MediumTest
     @Feature({"StartSurface"})
-    @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS})
-    public void testStartSurfaceMenu() throws ExecutionException {
-        ChromeTabbedActivity cta = mActivityTestRule.getActivity();
-        if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta);
-        StartSurfaceTestUtils.waitForOverviewVisible(
-                mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta);
-        TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0);
-
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            AppMenuTestSupport.showAppMenu(mActivityTestRule.getAppMenuCoordinator(), null, false);
-        });
-
-        assertNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.icon_row_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.new_tab_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.new_incognito_tab_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.divider_line_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.open_history_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.downloads_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.all_bookmarks_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.recent_tabs_menu_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.divider_line_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.preferences_id));
-        assertNotNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.help_id));
-
-        assertNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.menu_group_tabs));
-        assertNull(AppMenuTestSupport.getMenuItemPropertyModel(
-                mActivityTestRule.getAppMenuCoordinator(), R.id.close_all_tabs_menu_id));
-
-        boolean hasUpdateMenuItem =
-                AppMenuTestSupport.getMenuItemPropertyModel(
-                        mActivityTestRule.getAppMenuCoordinator(), R.id.update_menu_id)
-                != null;
-        ModelList menuItemsModelList =
-                AppMenuTestSupport.getMenuModelList(mActivityTestRule.getAppMenuCoordinator());
-        assertEquals(hasUpdateMenuItem ? 11 : 10, menuItemsModelList.size());
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"StartSurface"})
     // clang-format off
     @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS})
     public void test_DoNotLoadLastSelectedTabOnStartup() {
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
index 566c3ad..f38575c 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java
@@ -64,6 +64,7 @@
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.KeyboardVisibilityDelegate;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -185,8 +186,7 @@
                     ContextUtils.getApplicationContext())) {
             mTabSelectionEditorController = null;
         }
-        mActivity = Robolectric.buildActivity(Activity.class).get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).get();
         mModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS);
         mMediator = new TabGridDialogMediator(mActivity, mDialogController, mModel,
                 mTabModelSelector, mTabCreatorManager, mTabSwitcherResetHandler,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
index 9412ffd..8abeb18e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -306,7 +306,8 @@
     /**
      * @return Whether the Start surface homepage is showing.
      */
-    private boolean isInStartSurfaceHomepage() {
+    @VisibleForTesting
+    boolean isInStartSurfaceHomepage() {
         return mStartSurfaceSupplier != null && mStartSurfaceSupplier.get() != null
                 && mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE;
     }
@@ -1259,6 +1260,11 @@
         sItemInReadingListForTesting = highlight;
     }
 
+    @VisibleForTesting
+    void setStartSurfaceStateForTesting(@StartSurfaceState int state) {
+        mStartSurfaceState = state;
+    }
+
     void setBookmarkBridgeSupplierForTesting(
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier) {
         mBookmarkBridgeSupplier = bookmarkBridgeSupplier;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
index efb87acb..a1bfd80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
@@ -12,6 +12,7 @@
 import androidx.browser.customtabs.PostMessageBackend;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.browserservices.verification.OriginVerifier;
 import org.chromium.chrome.browser.browserservices.verification.OriginVerifier.OriginVerificationListener;
@@ -51,6 +52,7 @@
             @Override
             public void onMessage(MessagePayload messagePayload, MessagePort[] sentPorts) {
                 mPostMessageBackend.onPostMessage(messagePayload.getAsString(), null);
+                RecordHistogram.recordBooleanHistogram("CustomTabs.PostMessage.OnMessage", true);
             }
         };
     }
@@ -152,6 +154,8 @@
                 mChannel[0].postMessage(new MessagePayload(message), null);
             }
         });
+        RecordHistogram.recordBooleanHistogram(
+                "CustomTabs.PostMessage.PostMessageFromClientApp", true);
         return CustomTabsService.RESULT_SUCCESS;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index a6fdb51..62990d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -700,6 +700,8 @@
         logCall("requestPostMessageChannel() with origin "
                         + (postMessageOrigin != null ? postMessageOrigin.toString() : ""),
                 success);
+        RecordHistogram.recordBooleanHistogram(
+                "CustomTabs.PostMessage.RequestPostMessageChannel", success);
         return success;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 0f3986f..e7a3eb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -59,7 +59,6 @@
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.components.version_info.VersionInfo;
 import org.chromium.content_public.browser.ChildProcessImportance;
-import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsAccessibility;
@@ -1696,57 +1695,36 @@
 
     private @UserAgentOverrideOption int calculateUserAgentOverrideOption() {
         WebContents webContents = getWebContents();
-        boolean currentRequestDesktopSite = webContents == null
-                ? false
-                : webContents.getNavigationController().getUseDesktopUserAgent();
-
+        boolean currentRequestDesktopSite = TabUtils.isUsingDesktopUserAgent(webContents);
         @TabUserAgent
-        int tabUserAgent = CriticalPersistedTabData.from(this).getUserAgent();
-        // TabUserAgent.UNSET means this is a pre-existing tab from an earlier build. In this case
-        // we set the TabUserAgent bit based on last committed entry's user agent. If webContents is
-        // null, this method is triggered too early, and we cannot read the last committed entry's
-        // user agent yet. We will skip for now and let the following call set the TabUserAgent bit.
-        if (webContents != null && tabUserAgent == TabUserAgent.UNSET) {
-            if (currentRequestDesktopSite) {
-                tabUserAgent = TabUserAgent.DESKTOP;
-            } else {
-                tabUserAgent = TabUserAgent.DEFAULT;
-            }
-            CriticalPersistedTabData.from(this).setUserAgent(tabUserAgent);
-        }
-        // We only calculate the user agent when users did not manually choose one.
-        if (tabUserAgent == TabUserAgent.DEFAULT) {
-            // We only do the following logic to choose the desktop/mobile user agent if:
-            // 1. User never manually made a choice in the app menu for requesting desktop site.
-            // 2. User-enabled request desktop site in site settings.
-            Profile profile =
-                    IncognitoUtils.getProfileFromWindowAndroid(mWindowAndroid, isIncognito());
-            boolean shouldRequestDesktopSite;
-            if (ContentFeatureList.isEnabled(ContentFeatureList.REQUEST_DESKTOP_SITE_EXCEPTIONS)) {
-                shouldRequestDesktopSite = getWebContents() != null
-                        && TabUtils.isDesktopSiteEnabled(profile, getWebContents().getVisibleUrl());
-            } else {
-                shouldRequestDesktopSite = TabUtils.isDesktopSiteGlobalEnabled(profile);
-            }
-
-            if (shouldRequestDesktopSite != currentRequestDesktopSite) {
-                // TODO(crbug.com/1243758): Confirm if a new histogram should be used.
-                RecordHistogram.recordBooleanHistogram(
-                        "Android.RequestDesktopSite.UseDesktopUserAgent", shouldRequestDesktopSite);
-
-                // The user is not forcing any mode and we determined that we need to
-                // change, therefore we are using TRUE or FALSE option. On Android TRUE mean
-                // override to Desktop user agent, while FALSE means go with Mobile version.
-                return shouldRequestDesktopSite ? UserAgentOverrideOption.TRUE
-                                                : UserAgentOverrideOption.FALSE;
-            }
+        int tabUserAgent = TabUtils.getTabUserAgent(this);
+        // INHERIT means use the same UA that was used last time.
+        @UserAgentOverrideOption
+        int userAgentOverrideOption = UserAgentOverrideOption.INHERIT;
+        // Do not override UA if there is a tab level setting.
+        if (tabUserAgent != TabUserAgent.DEFAULT) {
+            recordHistogramUseDesktopUserAgent(currentRequestDesktopSite);
+            return userAgentOverrideOption;
         }
 
+        Profile profile = IncognitoUtils.getProfileFromWindowAndroid(mWindowAndroid, isIncognito());
+        boolean shouldRequestDesktopSite =
+                TabUtils.readRequestDesktopSiteContentSettings(profile, webContents);
+        if (shouldRequestDesktopSite != currentRequestDesktopSite) {
+            // The user is not forcing any mode and we determined that we need to
+            // change, therefore we are using TRUE or FALSE option. On Android TRUE mean
+            // override to Desktop user agent, while FALSE means go with Mobile version.
+            userAgentOverrideOption = shouldRequestDesktopSite ? UserAgentOverrideOption.TRUE
+                                                               : UserAgentOverrideOption.FALSE;
+        }
+        recordHistogramUseDesktopUserAgent(shouldRequestDesktopSite);
+        return userAgentOverrideOption;
+    }
+
+    // TODO(crbug.com/1243758): Confirm if a new histogram should be used.
+    private void recordHistogramUseDesktopUserAgent(boolean value) {
         RecordHistogram.recordBooleanHistogram(
-                "Android.RequestDesktopSite.UseDesktopUserAgent", currentRequestDesktopSite);
-
-        // INHERIT means use the same that was used last time.
-        return UserAgentOverrideOption.INHERIT;
+                "Android.RequestDesktopSite.UseDesktopUserAgent", value);
     }
 
     private void switchUserAgentIfNeeded() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
index d294a3b..592cbf2a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
@@ -26,6 +26,7 @@
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
@@ -109,6 +110,57 @@
     }
 
     /**
+     * Get UseDesktopUserAgent setting from webContents.
+     * @param webContents The webContents used to retrieve UseDesktopUserAgent setting.
+     * @return Whether the webContents is set to use desktop user agent.
+     */
+    public static boolean isUsingDesktopUserAgent(WebContents webContents) {
+        return webContents != null
+                && webContents.getNavigationController().getUseDesktopUserAgent();
+    }
+
+    /**
+     * Get tabUserAgent from the tab, which represents the tab level RDS setting.
+     * @param tab The tab used to retrieve tabUserAgent.
+     * @return The tab level RDS setting.
+     */
+    public static @TabUserAgent int getTabUserAgent(Tab tab) {
+        @TabUserAgent
+        int tabUserAgent = CriticalPersistedTabData.from(tab).getUserAgent();
+        WebContents webContents = tab.getWebContents();
+        boolean currentRequestDesktopSite = isUsingDesktopUserAgent(webContents);
+        // TabUserAgent.UNSET means this is a pre-existing tab from an earlier build. In this case
+        // we set the TabUserAgent bit based on last committed entry's user agent. If webContents is
+        // null, this method is triggered too early, and we cannot read the last committed entry's
+        // user agent yet. We will skip for now and let the following call set the TabUserAgent bit.
+        if (webContents != null && tabUserAgent == TabUserAgent.UNSET) {
+            if (currentRequestDesktopSite) {
+                tabUserAgent = TabUserAgent.DESKTOP;
+            } else {
+                tabUserAgent = TabUserAgent.DEFAULT;
+            }
+            CriticalPersistedTabData.from(tab).setUserAgent(tabUserAgent);
+        }
+        return tabUserAgent;
+    }
+
+    /**
+     * Read Request Desktop Site ContentSettings.
+     * @param profile The profile used to retrieve ContentSettings.
+     * @param webContents The webContents used to retrieve Url for site level setting.
+     * @return Whether Request Desktop Site is enabled in ContentSettings.
+     */
+    public static boolean readRequestDesktopSiteContentSettings(
+            Profile profile, WebContents webContents) {
+        if (ContentFeatureList.isEnabled(ContentFeatureList.REQUEST_DESKTOP_SITE_EXCEPTIONS)) {
+            return webContents != null
+                    && TabUtils.isDesktopSiteEnabled(profile, webContents.getVisibleUrl());
+        } else {
+            return TabUtils.isDesktopSiteGlobalEnabled(profile);
+        }
+    }
+
+    /**
      * Check if the tab is large enough for displaying desktop sites. This method will only check
      * for tablets, if the device is a phone, will return false regardless of tab size.
      * @param tab The tab to be checked if the size is large enough for desktop site.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivityCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivityCoordinator.java
index fa3d9e8..401c3191 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivityCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivityCoordinator.java
@@ -6,11 +6,15 @@
 
 import androidx.annotation.NonNull;
 
+import org.chromium.base.BuildInfo;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.permissiondelegation.PermissionUpdater;
+import org.chromium.chrome.browser.browserservices.ui.controller.trustedwebactivity.TwaRegistrar;
 import org.chromium.chrome.browser.browserservices.ui.controller.webapps.WebappDisclosureController;
 import org.chromium.chrome.browser.browserservices.ui.view.DisclosureInfobar;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.flags.CachedFeatureFlags;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.DestroyObserver;
 import org.chromium.components.embedder_support.util.Origin;
@@ -27,6 +31,7 @@
 public class WebApkActivityCoordinator implements DestroyObserver {
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
     private final Lazy<WebApkUpdateManager> mWebApkUpdateManager;
+    private final TwaRegistrar mTwaRegistrar;
 
     @Inject
     public WebApkActivityCoordinator(
@@ -35,13 +40,14 @@
             WebApkActivityLifecycleUmaTracker webApkActivityLifecycleUmaTracker,
             ActivityLifecycleDispatcher lifecycleDispatcher,
             BrowserServicesIntentDataProvider intendDataProvider,
-            Lazy<WebApkUpdateManager> webApkUpdateManager) {
+            Lazy<WebApkUpdateManager> webApkUpdateManager, TwaRegistrar twaRegistrar) {
         // We don't need to do anything with |disclosureController|, |disclosureInfobar| and
         // |webApkActivityLifecycleUmaTracker|. We just need to resolve
         // them so that they start working.
 
         mIntentDataProvider = intendDataProvider;
         mWebApkUpdateManager = webApkUpdateManager;
+        mTwaRegistrar = twaRegistrar;
 
         deferredStartupWithStorageHandler.addTask((storage, didCreateStorage) -> {
             if (lifecycleDispatcher.isActivityFinishingOrDestroyed()) return;
@@ -62,8 +68,18 @@
         String scope = storage.getScope();
         assert !scope.isEmpty();
 
-        PermissionUpdater.get().onWebApkLaunch(
-                Origin.create(scope), storage.getWebApkPackageName());
+        Origin origin = Origin.create(scope);
+        String packageName = storage.getWebApkPackageName();
+
+        if (!BuildInfo.isAtLeastT()
+                || !CachedFeatureFlags.isEnabled(
+                        ChromeFeatureList
+                                .TRUSTED_WEB_ACTIVITY_NOTIFICATION_PERMISSION_DELEGATION)) {
+            return;
+        }
+
+        mTwaRegistrar.registerClient(packageName, origin);
+        PermissionUpdater.get().onWebApkLaunch(origin, packageName);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java
index b33e4d08..60e91b3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java
@@ -21,6 +21,7 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.components.autofill.AutofillDelegate;
 import org.chromium.components.autofill.AutofillPopup;
@@ -151,6 +152,7 @@
     @Test
     @SmallTest
     @Feature({"autofill"})
+    @DisabledTest(message = "https://crbug.com/1338184")
     public void testAutofillClickFirstSuggestion() {
         AutofillSuggestion[] suggestions = createTwoAutofillSuggestionArray();
         openAutofillPopupAndWaitUntilReady(suggestions);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java
deleted file mode 100644
index cb1fac8..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityScrollingTest.java
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.history;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.test.espresso.intent.Intents;
-import androidx.test.espresso.intent.rule.IntentsTestRule;
-import androidx.test.filters.SmallTest;
-
-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.test.params.ParameterAnnotations;
-import org.chromium.base.test.params.ParameterProvider;
-import org.chromium.base.test.params.ParameterSet;
-import org.chromium.base.test.params.ParameterizedRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.history.HistoryTestUtils.TestObserver;
-import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
-import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
-import org.chromium.components.browser_ui.widget.DateDividedAdapter.FooterItem;
-import org.chromium.components.browser_ui.widget.DateDividedAdapter.TimedItem;
-import org.chromium.components.browser_ui.widget.MoreProgressButton;
-import org.chromium.components.browser_ui.widget.MoreProgressButton.State;
-import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.test.util.UiRestriction;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Tests the scrolling behavior on {@link HistoryActivity}.
- * The main difference for this test file with {@link HistoryUiTest} is to test scrolling
- * behavior under different settings.
- */
-// clang-format off
-@RunWith(ParameterizedRunner.class)
-@Batch(Batch.PER_CLASS)
-@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-public class HistoryActivityScrollingTest {
-    // clang-format on
-    // TODO(crbug.com/1238144): Migrate to BaseActivityTestRule.
-    @Rule
-    public IntentsTestRule<HistoryActivity> mActivityTestRule =
-            new IntentsTestRule<>(HistoryActivity.class, false, false);
-
-    @ParameterAnnotations.ClassParameter
-    private static List<ParameterSet> sClassParams = new TestParamsProvider().getParameters();
-
-    private static class TestParams extends ParameterSet {
-        public final int mPaging;
-        public final int mTotalItems;
-        public final boolean mIsScrollToLoadDisabled;
-
-        public TestParams(int paging, int totalItems, boolean isScrollToLoadDisabled) {
-            super();
-            mPaging = paging;
-            mTotalItems = totalItems;
-            mIsScrollToLoadDisabled = isScrollToLoadDisabled;
-
-            value(paging, totalItems, isScrollToLoadDisabled);
-        }
-
-        @Override
-        public String toString() {
-            return "paging: " + mPaging + ", totalItems: " + mTotalItems
-                    + ", isScrollToLoadDisabled: " + mIsScrollToLoadDisabled;
-        }
-    }
-
-    private static class TestParamsProvider implements ParameterProvider {
-        private static List<ParameterSet> sScrollToLoad =
-                Arrays.asList(new TestParams(5, 30, false).name("Enabled"),
-                        new TestParams(5, 30, true).name("Disabled"),
-                        new TestParams(5, 12, true).name("Disabled_Less"));
-
-        @Override
-        public List<ParameterSet> getParameters() {
-            return sScrollToLoad;
-        }
-    }
-
-    @Rule
-    public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
-
-    private StubbedHistoryProvider mHistoryProvider;
-    private HistoryAdapter mAdapter;
-    private HistoryManager mHistoryManager;
-    private RecyclerView mRecyclerView;
-    private TestObserver mTestObserver;
-    // private PrefChangeRegistrar mPrefChangeRegistrar;
-
-    private List<HistoryItem> mItems;
-
-    private int mPaging;
-    private int mTotalItems;
-    private boolean mIsScrollToLoadDisabled;
-    private int mOrigItemsCount;
-
-    public HistoryActivityScrollingTest(
-            int paging, int totalItems, boolean isScrollToLoadDisabled) {
-        mPaging = paging;
-        mTotalItems = totalItems;
-        mIsScrollToLoadDisabled = isScrollToLoadDisabled;
-        mItems = new ArrayList<>(mTotalItems);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        // Account not signed in by default, the AccountManagerTestRule above is used to setup
-        // the signin environment.
-        // The clear browsing data header, one date view, and two history item views
-        // should be shown, but the info header should not. We enforce a defaultx
-        // state because the number of headers shown depends on the signed-in state.
-        mHistoryProvider = new StubbedHistoryProvider();
-        mHistoryProvider.setPaging(mPaging);
-
-        Date today = new Date();
-        long timestamp = today.getTime();
-
-        for (int i = 0; i < mTotalItems; i++) {
-            HistoryItem item = StubbedHistoryProvider.createHistoryItem(0, --timestamp);
-            mItems.add(item);
-            mHistoryProvider.addItem(item);
-        }
-
-        HistoryContentManager.setProviderForTests(mHistoryProvider);
-        HistoryContentManager.setScrollToLoadDisabledForTesting(mIsScrollToLoadDisabled);
-
-        launchHistoryActivity();
-        HistoryTestUtils.setupHistoryTestHeaders(mAdapter, mTestObserver);
-
-        mOrigItemsCount = mAdapter.getItemCount();
-        Assert.assertTrue("At least one item should be loaded to adapter", mOrigItemsCount > 0);
-    }
-
-    @After
-    public void tearDown() {
-        if (mActivityTestRule.getActivity() == null) {
-            // IntentsTestRule assumes the Activity was started when tearing down the rule, so we
-            // need to work around that.
-            Intents.init();
-        }
-    }
-
-    private void launchHistoryActivity() {
-        HistoryActivity activity = mActivityTestRule.launchActivity(null);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mHistoryManager = activity.getHistoryManagerForTests();
-            mAdapter = mHistoryManager.getContentManagerForTests().getAdapter();
-            mRecyclerView = mHistoryManager.getContentManagerForTests().getRecyclerView();
-            mTestObserver = new TestObserver();
-            mHistoryManager.getSelectionDelegateForTests().addObserver(mTestObserver);
-            mAdapter.registerAdapterDataObserver(mTestObserver);
-        });
-    }
-
-    @Test
-    @SmallTest
-    public void testScrollToLoadEnabled() {
-        assumeFalse(mIsScrollToLoadDisabled);
-
-        RecyclerViewTestUtils.scrollToBottom(mRecyclerView);
-
-        Assert.assertTrue("Should load more items into view after scroll",
-                mAdapter.getItemCount() > mOrigItemsCount);
-        Assert.assertTrue(String.valueOf(mPaging) + " more Items should be loaded",
-                mAdapter.getItemCount() == mOrigItemsCount + mPaging);
-    }
-
-    @Test
-    @SmallTest
-    public void testScrollToLoadDisabled() throws Exception {
-        assumeTrue(mIsScrollToLoadDisabled);
-
-        RecyclerViewTestUtils.scrollToBottom(mRecyclerView);
-
-        Assert.assertTrue("Should not load more items into view after scroll",
-                mAdapter.getItemCount() == mOrigItemsCount);
-        Assert.assertTrue(
-                "Footer should be added to the end of the view", mAdapter.hasListFooter());
-        Assert.assertEquals(
-                "Footer group should contain one item", 1, mAdapter.getLastGroupForTests().size());
-
-        // Verify the button is correctly displayed
-        TimedItem item = mAdapter.getLastGroupForTests().getItemAt(0);
-        MoreProgressButton button = (MoreProgressButton) ((FooterItem) item).getView();
-        Assert.assertSame("FooterItem view should be MoreProgressButton",
-                mAdapter.getMoreProgressButtonForTest(), button);
-        Assert.assertEquals(
-                "State for the MPB should be button", button.getStateForTest(), State.BUTTON);
-
-        // Test click, should load more items
-        int callCount = mTestObserver.onChangedCallback.getCallCount();
-
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> button.findViewById(R.id.action_button).performClick());
-        mTestObserver.onChangedCallback.waitForCallback(callCount);
-
-        Assert.assertTrue("Should load more items into view after click more button",
-                mAdapter.getItemCount() > mOrigItemsCount);
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/history/OWNERS
index 0fa757c..c08a4c1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/OWNERS
@@ -1 +1 @@
-twellington@chromium.org
+file://chrome/android/java/src/org/chromium/chrome/browser/history/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActivityUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActivityUnitTest.java
index e80635e..fa35835 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActivityUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActivityUnitTest.java
@@ -16,11 +16,11 @@
 import org.robolectric.Robolectric;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.ui.BottomContainer;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.ui.base.TestActivity;
 
 /**
  * Unit tests for ChromeActivity.
@@ -31,8 +31,7 @@
 
     @Before
     public void setup() {
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
index 54cd5a5..a37e185 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
@@ -75,6 +75,9 @@
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.chrome.browser.toolbar.menu_button.MenuUiState;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
+import org.chromium.chrome.features.start_surface.StartSurface;
+import org.chromium.chrome.features.start_surface.StartSurfaceCoordinator;
+import org.chromium.chrome.features.start_surface.StartSurfaceState;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.browser_ui.accessibility.PageZoomCoordinator;
@@ -133,6 +136,8 @@
     @Mock
     private LayoutStateProvider mLayoutStateProvider;
     @Mock
+    private StartSurfaceCoordinator mStartSurfaceCoordinator;
+    @Mock
     private UpdateMenuItemHelper mUpdateMenuItemHelper;
     @Mock
     private UserPrefs.Natives mUserPrefsJniMock;
@@ -165,6 +170,7 @@
             new OneshotSupplierImpl<>();
     private ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier =
             new ObservableSupplierImpl<>();
+    private OneshotSupplierImpl<StartSurface> mStartSurfaceSupplier = new OneshotSupplierImpl<>();
 
     private final TestValues mTestValues = new TestValues();
     private AppMenuPropertiesDelegateImpl mAppMenuPropertiesDelegate;
@@ -208,11 +214,11 @@
         mBookmarkBridgeSupplier.set(mBookmarkBridge);
         PowerBookmarkUtils.setPriceTrackingEligibleForTesting(false);
         PowerBookmarkUtils.setPowerBookmarkMetaForTesting(PowerBookmarkMeta.newBuilder().build());
-        mAppMenuPropertiesDelegate =
-                Mockito.spy(new AppMenuPropertiesDelegateImpl(ContextUtils.getApplicationContext(),
-                        mActivityTabProvider, mMultiWindowModeStateDispatcher, mTabModelSelector,
-                        mToolbarManager, mDecorView, mLayoutStateProviderSupplier, null,
-                        mBookmarkBridgeSupplier, mIncognitoReauthControllerSupplier));
+        mAppMenuPropertiesDelegate = Mockito.spy(new AppMenuPropertiesDelegateImpl(
+                ContextUtils.getApplicationContext(), mActivityTabProvider,
+                mMultiWindowModeStateDispatcher, mTabModelSelector, mToolbarManager, mDecorView,
+                mLayoutStateProviderSupplier, mStartSurfaceSupplier, mBookmarkBridgeSupplier,
+                mIncognitoReauthControllerSupplier));
     }
 
     private void setupFeatureDefaults() {
@@ -886,6 +892,28 @@
         assertTrue(item.isEnabled());
     }
 
+    @Test
+    public void testStartSurfaceMenu() {
+        mStartSurfaceSupplier.set(mStartSurfaceCoordinator);
+        setUpMocksForOverviewMenu();
+        doReturn(true).when(mAppMenuPropertiesDelegate).isAutoDarkWebContentsEnabled();
+
+        when(mIncognitoTabModel.getCount()).thenReturn(0);
+        mAppMenuPropertiesDelegate.setStartSurfaceStateForTesting(StartSurfaceState.SHOWN_HOMEPAGE);
+        Assert.assertTrue(mAppMenuPropertiesDelegate.shouldShowPageMenu());
+        Assert.assertTrue(mAppMenuPropertiesDelegate.isInStartSurfaceHomepage());
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.new_tab_menu_id, R.id.new_incognito_tab_menu_id,
+                R.id.divider_line_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.all_bookmarks_menu_id, R.id.recent_tabs_menu_id, R.id.divider_line_id,
+                R.id.preferences_id, R.id.help_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
     private void setUpMocksForPageMenu() {
         when(mActivityTabProvider.get()).thenReturn(mTab);
         when(mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER)).thenReturn(false);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
index 9040bc62..646be1d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinatorTest.java
@@ -52,6 +52,7 @@
 import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ContentFeatures;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.dragdrop.DragStateTracker;
@@ -142,8 +143,7 @@
 
     @Before
     public void setUpTest() {
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
         mCoordinator = new ContextMenuCoordinator(TOP_CONTENT_OFFSET_PX, mNativeDelegate);
         MockitoAnnotations.initMocks(this);
         mocker.mock(PerformanceHintsObserverJni.TEST_HOOKS, mNativeMock);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java
index 7cc0741..17f75f57 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderMediatorTest.java
@@ -33,7 +33,6 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.blink_public.common.ContextMenuDataMediaType;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver;
 import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver.PerformanceClass;
 import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserverJni;
@@ -42,6 +41,7 @@
 import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
 import org.chromium.components.favicon.LargeIconBridge;
 import org.chromium.components.favicon.LargeIconBridgeJni;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -73,8 +73,7 @@
 
     @Before
     public void setUpTest() {
-        mActivity = Robolectric.setupActivity(Activity.class);
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.setupActivity(TestActivity.class);
         MockitoAnnotations.initMocks(this);
         mocker.mock(PerformanceHintsObserverJni.TEST_HOOKS, mMockPerformanceHintsObserverJni);
         mocker.mock(LargeIconBridgeJni.TEST_HOOKS, mMockLargeIconBridgeJni);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/history/HistoryUITest.java b/chrome/android/junit/src/org/chromium/chrome/browser/history/HistoryUITest.java
index c2b0241..5c0cb0b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/history/HistoryUITest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/history/HistoryUITest.java
@@ -69,6 +69,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.browser_ui.widget.DateDividedAdapter;
+import org.chromium.components.browser_ui.widget.MoreProgressButton;
 import org.chromium.components.browser_ui.widget.selectable_list.SelectableItemView;
 import org.chromium.components.browser_ui.widget.selectable_list.SelectableItemViewHolder;
 import org.chromium.components.favicon.LargeIconBridge;
@@ -90,6 +91,9 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @DisableFeatures(ChromeFeatureList.HISTORY_JOURNEYS)
 public class HistoryUITest {
+    private static final int PAGE_INCREMENT = 2;
+    private static final String HISTORY_SEARCH_QUERY = "some page";
+
     @Rule
     public AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
     @Rule
@@ -109,8 +113,7 @@
 
     private HistoryItem mItem1;
     private HistoryItem mItem2;
-
-    private static final String HISTORY_SEARCH_QUERY = "some page";
+    private int mHeight;
 
     @Mock
     private SnackbarManager mSnackbarManager;
@@ -140,9 +143,7 @@
     @Before
     public void setUp() throws Exception {
         mHistoryProvider = new StubbedHistoryProvider();
-
-        Date today = new Date();
-        long timestamp = today.getTime();
+        long timestamp = new Date().getTime();
         mItem1 = StubbedHistoryProvider.createHistoryItem(0, timestamp);
         mItem2 = StubbedHistoryProvider.createHistoryItem(1, timestamp);
         mHistoryProvider.addItem(mItem1);
@@ -168,6 +169,13 @@
         mHistoryClustersCoordinator = mHistoryManager.getHistoryClustersCoordinatorForTests();
         mAdapter = mHistoryManager.getContentManagerForTests().getAdapter();
         mRecyclerView = mHistoryManager.getContentManagerForTests().getRecyclerView();
+
+        // Layout the recycler view with ample height so that we can measure how much height it
+        // needs to fully display its initial set of items.
+        mRecyclerView.measure(0, 0);
+        mRecyclerView.layout(0, 0, 600, 1000);
+        // Constrain the recycler view to only the height it needs and lay it out again.
+        mHeight = mRecyclerView.getMeasuredHeight();
         layoutRecyclerView();
 
         int expectedItemCount = 4;
@@ -589,6 +597,73 @@
                 mHistoryManager.getView().getChildAt(0), mHistoryManager.getSelectableListLayout());
     }
 
+    @Test
+    @SmallTest
+    public void testScrollToLoadEnabled() {
+        HistoryContentManager.setScrollToLoadDisabledForTesting(false);
+        // Reduce the height available to the recycler view to less than it needs so that scrolling
+        // has an effect.
+        mHeight--;
+        layoutRecyclerView();
+
+        mHistoryProvider.setPaging(PAGE_INCREMENT);
+        long timestamp = new Date().getTime();
+        mHistoryProvider.addItem(StubbedHistoryProvider.createHistoryItem(2, --timestamp));
+        mHistoryProvider.addItem(StubbedHistoryProvider.createHistoryItem(3, --timestamp));
+        mHistoryProvider.addItem(StubbedHistoryProvider.createHistoryItem(4, --timestamp));
+        mHistoryProvider.addItem(StubbedHistoryProvider.createHistoryItem(5, --timestamp));
+        int itemCount = mAdapter.getItemCount();
+        // Trigger a reload of items so that the adapter sees that there are now more to load.
+        mAdapter.startLoadingItems();
+
+        scrollRecyclerViewToBottom();
+
+        Assert.assertEquals(PAGE_INCREMENT + " more Items should be loaded",
+                mAdapter.getItemCount(), itemCount + PAGE_INCREMENT);
+        itemCount = mAdapter.getItemCount();
+
+        scrollRecyclerViewToBottom();
+        Assert.assertEquals(PAGE_INCREMENT + " more Items should be loaded",
+                mAdapter.getItemCount(), itemCount + PAGE_INCREMENT);
+    }
+
+    @Test
+    @SmallTest
+    public void testScrollToLoadDisabled() throws Exception {
+        mHistoryProvider.setPaging(PAGE_INCREMENT);
+        HistoryContentManager.setScrollToLoadDisabledForTesting(true);
+        mHistoryProvider.addItem(StubbedHistoryProvider.createHistoryItem(2, new Date().getTime()));
+        mHistoryProvider.addItem(
+                StubbedHistoryProvider.createHistoryItem(3, new Date().getTime() - 1));
+        mHistoryProvider.addItem(
+                StubbedHistoryProvider.createHistoryItem(4, new Date().getTime() - 2));
+        mAdapter.startLoadingItems();
+        int itemCount = mAdapter.getItemCount();
+        scrollRecyclerViewToBottom();
+
+        Assert.assertEquals("Should not load more items into view after scroll",
+                mAdapter.getItemCount(), itemCount);
+        Assert.assertTrue(
+                "Footer should be added to the end of the view", mAdapter.hasListFooter());
+        Assert.assertEquals(
+                "Footer group should contain one item", 1, mAdapter.getLastGroupForTests().size());
+
+        // Verify the button is correctly displayed
+        DateDividedAdapter.TimedItem item = mAdapter.getLastGroupForTests().getItemAt(0);
+        MoreProgressButton button =
+                (MoreProgressButton) ((DateDividedAdapter.FooterItem) item).getView();
+        Assert.assertSame("FooterItem view should be MoreProgressButton",
+                mAdapter.getMoreProgressButtonForTest(), button);
+        Assert.assertEquals("State for the MPB should be button", button.getStateForTest(),
+                MoreProgressButton.State.BUTTON);
+
+        // Test click, should load more items
+        button.findViewById(R.id.action_button).performClick();
+
+        Assert.assertEquals((PAGE_INCREMENT) + " more Items should be loaded",
+                mAdapter.getItemCount(), itemCount + PAGE_INCREMENT);
+    }
+
     private void toggleItemSelection(int position) {
         final SelectableItemView<HistoryItem> itemView = getItemView(position);
         itemView.performLongClick();
@@ -635,6 +710,10 @@
 
     private void layoutRecyclerView() {
         mRecyclerView.measure(0, 0);
-        mRecyclerView.layout(0, 0, 600, 1000);
+        mRecyclerView.layout(0, 0, 600, mHeight);
+    }
+
+    private void scrollRecyclerViewToBottom() {
+        mRecyclerView.scrollBy(0, mHeight);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/history/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/history/OWNERS
new file mode 100644
index 0000000..c08a4c1
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/history/OWNERS
@@ -0,0 +1 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/history/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/TileRendererTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/TileRendererTest.java
index 5d08e190..dbc9820 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/TileRendererTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/TileRendererTest.java
@@ -28,7 +28,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
-import org.robolectric.android.controller.ActivityController;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowDrawable;
 
@@ -47,6 +46,7 @@
 import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
 
@@ -102,7 +102,6 @@
     private ColorStateList mFakeColorStateList;
 
     private ShadowPostTaskImpl mPostTaskRunner;
-    private ActivityController<Activity> mActivityController;
     private Activity mActivity;
     private LinearLayout mSharedParent;
     private final ArgumentCaptor<Drawable> mIconCaptor = ArgumentCaptor.forClass(Drawable.class);
@@ -114,10 +113,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mActivityController = Robolectric.buildActivity(Activity.class);
-        mActivityController.setup();
-        mActivity = mActivityController.get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
 
         mPostTaskRunner = new ShadowPostTaskImpl();
         ShadowPostTask.setTestImpl(mPostTaskRunner);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabUtilsUnitTest.java
index 0fd6888..7d0d1a0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabUtilsUnitTest.java
@@ -14,6 +14,7 @@
 import static org.mockito.Mockito.when;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -25,13 +26,17 @@
 import org.robolectric.annotation.Implements;
 import org.robolectric.annotation.Resetter;
 
+import org.chromium.base.FeatureList;
+import org.chromium.base.FeatureList.TestValues;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
+import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.WebContents;
 
@@ -106,6 +111,9 @@
     private CriticalPersistedTabData mCriticalPersistedTabData;
 
     private boolean mRdsDefault;
+    private @ContentSettingValues int mRdsException;
+    private boolean mUseDesktopUserAgent;
+    private @TabUserAgent int mTabUserAgent;
 
     @Before
     public void setup() {
@@ -114,15 +122,29 @@
         ShadowProfile.setProfile(mProfile);
         mJniMocker.mock(WebsitePreferenceBridgeJni.TEST_HOOKS, mWebsitePreferenceBridgeJniMock);
 
-        doAnswer(invocation -> mRdsDefault)
-                .when(mWebsitePreferenceBridgeJniMock)
-                .isContentSettingEnabled(any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE));
-
         when(mTab.isNativePage()).thenReturn(false);
         when(mTabNative.isNativePage()).thenReturn(true);
         when(mTab.getWebContents()).thenReturn(mWebContents);
         when(mTabNative.getWebContents()).thenReturn(mWebContents);
         when(mWebContents.getNavigationController()).thenReturn(mNavigationController);
+
+        doAnswer(invocation -> mRdsDefault)
+                .when(mWebsitePreferenceBridgeJniMock)
+                .isContentSettingEnabled(any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE));
+        doAnswer(invocation -> mRdsException)
+                .when(mWebsitePreferenceBridgeJniMock)
+                .getContentSetting(
+                        any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE), any(), any());
+        doAnswer(invocation -> mUseDesktopUserAgent)
+                .when(mNavigationController)
+                .getUseDesktopUserAgent();
+        doAnswer(invocation -> mTabUserAgent).when(mCriticalPersistedTabData).getUserAgent();
+        doAnswer(invocation -> {
+            mTabUserAgent = invocation.getArgument(0);
+            return null;
+        })
+                .when(mCriticalPersistedTabData)
+                .setUserAgent(anyInt());
     }
 
     @After
@@ -198,4 +220,99 @@
         verify(mNavigationController).setUseDesktopUserAgent(true, false);
         verify(mCriticalPersistedTabData, times(2)).setUserAgent(TabUserAgent.DEFAULT);
     }
+
+    @Test
+    public void testIsUsingDesktopUserAgent() {
+        Assert.assertFalse("The result should be false when there is no webContents.",
+                TabUtils.isUsingDesktopUserAgent(null));
+        mUseDesktopUserAgent = false;
+        Assert.assertFalse(
+                "Should get RDS from WebContents.", TabUtils.isUsingDesktopUserAgent(mWebContents));
+        mUseDesktopUserAgent = true;
+        Assert.assertTrue(
+                "Should get RDS from WebContents.", TabUtils.isUsingDesktopUserAgent(mWebContents));
+    }
+
+    @Test
+    public void testGetTabUserAgent_UpgradePath() {
+        mTabUserAgent = TabUserAgent.UNSET;
+        mUseDesktopUserAgent = false;
+        Assert.assertEquals("TabUserAgent is not set up correctly for upgrade path.",
+                TabUserAgent.DEFAULT, TabUtils.getTabUserAgent(mTab));
+        verify(mCriticalPersistedTabData).setUserAgent(TabUserAgent.DEFAULT);
+
+        mTabUserAgent = TabUserAgent.UNSET;
+        mUseDesktopUserAgent = true;
+        Assert.assertEquals("TabUserAgent is not set up correctly for upgrade path.",
+                TabUserAgent.DESKTOP, TabUtils.getTabUserAgent(mTab));
+        verify(mCriticalPersistedTabData).setUserAgent(TabUserAgent.DESKTOP);
+    }
+
+    @Test
+    public void testGetTabUserAgent_Mobile() {
+        mTabUserAgent = TabUserAgent.MOBILE;
+        mUseDesktopUserAgent = false;
+        Assert.assertEquals("Read unexpected TabUserAgent value.", TabUserAgent.MOBILE,
+                TabUtils.getTabUserAgent(mTab));
+
+        mUseDesktopUserAgent = true;
+        Assert.assertEquals("Read unexpected TabUserAgent value.", TabUserAgent.MOBILE,
+                TabUtils.getTabUserAgent(mTab));
+
+        verify(mCriticalPersistedTabData, never()).setUserAgent(anyInt());
+    }
+
+    @Test
+    public void testGetTabUserAgent_Desktop() {
+        mTabUserAgent = TabUserAgent.DESKTOP;
+        mUseDesktopUserAgent = false;
+        Assert.assertEquals("Read unexpected TabUserAgent value.", TabUserAgent.DESKTOP,
+                TabUtils.getTabUserAgent(mTab));
+
+        mUseDesktopUserAgent = true;
+        Assert.assertEquals("Read unexpected TabUserAgent value.", TabUserAgent.DESKTOP,
+                TabUtils.getTabUserAgent(mTab));
+
+        verify(mCriticalPersistedTabData, never()).setUserAgent(anyInt());
+    }
+
+    @Test
+    public void testReadRequestDesktopSiteContentSettings_DesktopSiteExceptionDisabled() {
+        enableDesktopSiteException(false);
+
+        // Global setting is Mobile.
+        mRdsDefault = false;
+        Assert.assertFalse("The result should match RDS global setting.",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, mWebContents));
+
+        // Global setting is Desktop.
+        mRdsDefault = true;
+        Assert.assertTrue("The result should match RDS global setting.",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, mWebContents));
+    }
+
+    @Test
+    public void testReadRequestDesktopSiteContentSettings_DesktopSiteExceptionEnabled() {
+        enableDesktopSiteException(true);
+
+        // Site level setting is Mobile.
+        mRdsException = ContentSettingValues.BLOCK;
+        Assert.assertFalse("The result should be false when there is no webContents",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, null));
+        Assert.assertFalse("The result should match RDS site level setting.",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, mWebContents));
+
+        // Site level setting is Desktop.
+        mRdsException = ContentSettingValues.ALLOW;
+        Assert.assertFalse("The result should be false when there is no webContents",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, null));
+        Assert.assertTrue("The result should match RDS site level setting.",
+                TabUtils.readRequestDesktopSiteContentSettings(mProfile, mWebContents));
+    }
+
+    private void enableDesktopSiteException(boolean enable) {
+        TestValues features = new TestValues();
+        features.addFeatureFlagOverride(ContentFeatureList.REQUEST_DESKTOP_SITE_EXCEPTIONS, enable);
+        FeatureList.setTestValues(features);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
index eee86b6b..8b15c51 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
@@ -36,7 +36,6 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.tab.Tab;
@@ -46,6 +45,7 @@
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tab.TabViewManager;
 import org.chromium.chrome.browser.tab.TabViewProvider;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -119,8 +119,7 @@
         mDestroyedUserDataHost = new UserDataHost();
         mDestroyedUserDataHost.destroy();
 
-        Activity activity = Robolectric.buildActivity(Activity.class).get();
-        activity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        Activity activity = Robolectric.buildActivity(TestActivity.class).get();
 
         doReturn(false).when(mTab).isIncognito();
         doReturn(null).when(mTab).getUrl();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 8b1ac35..0ac71ba 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-104.0.5112.18_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-105.0.5120.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 463f414..2ee3e0c1 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1689,8 +1689,6 @@
     "ssl/https_only_mode_controller_client.h",
     "ssl/https_only_mode_navigation_throttle.cc",
     "ssl/https_only_mode_navigation_throttle.h",
-    "ssl/https_only_mode_policy_handler.cc",
-    "ssl/https_only_mode_policy_handler.h",
     "ssl/https_only_mode_tab_helper.cc",
     "ssl/https_only_mode_tab_helper.h",
     "ssl/https_only_mode_upgrade_interceptor.cc",
diff --git a/chrome/browser/ash/eol_notification.cc b/chrome/browser/ash/eol_notification.cc
index a05ac688..69f5f70 100644
--- a/chrome/browser/ash/eol_notification.cc
+++ b/chrome/browser/ash/eol_notification.cc
@@ -20,7 +20,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
@@ -65,14 +65,11 @@
 EolNotification::EolNotification(Profile* profile)
     : clock_(base::DefaultClock::GetInstance()), profile_(profile) {}
 
-EolNotification::~EolNotification() {}
+EolNotification::~EolNotification() = default;
 
 void EolNotification::CheckEolInfo() {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-
   // Request the Eol Info.
-  update_engine_client->GetEolInfo(base::BindOnce(
+  UpdateEngineClient::Get()->GetEolInfo(base::BindOnce(
       &EolNotification::OnEolInfo, weak_ptr_factory_.GetWeakPtr()));
 }
 
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
index 68c0161..710c430 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -84,6 +84,8 @@
 const test::UIPath kDemoPreferencesCountry = {kDemoPrefsId, "countrySelect"};
 const test::UIPath kDemoPreferencesCountrySelect = {kDemoPrefsId,
                                                     "countrySelect", "select"};
+const test::UIPath kDemoPreferencesRetailerStoreId = {kDemoPrefsId,
+                                                      "retailerIdInput"};
 const test::UIPath kDemoPreferencesNext = {kDemoPrefsId, "nextButton"};
 
 const test::UIPath kNetworkScreen = {kNetworkId};
@@ -557,6 +559,39 @@
   SelectFranceAndFinishSetup();
 }
 
+IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest,
+                       OnlineSetupFlowSuccessWithRetailerAndStoreId) {
+  // Simulate successful online setup.
+  enrollment_helper_.ExpectEnrollmentMode(
+      policy::EnrollmentConfig::MODE_ATTESTATION);
+  enrollment_helper_.ExpectAttestationEnrollmentSuccess();
+  SimulateNetworkConnected();
+
+  TriggerDemoModeOnWelcomeScreen();
+
+  const std::string expectedRetailerStoreId = "ABC-1234";
+
+  test::OobeJS().TypeIntoPath(expectedRetailerStoreId,
+                              kDemoPreferencesRetailerStoreId);
+  test::OobeJS().ExpectEnabledPath(kDemoPreferencesNext);
+  test::OobeJS().ClickOnPath(kDemoPreferencesNext);
+
+  EXPECT_EQ(expectedRetailerStoreId, WizardController::default_controller()
+                                         ->demo_setup_controller()
+                                         ->get_retailer_store_id_input());
+
+  UseOnlineModeOnNetworkScreen();
+
+  AcceptTermsAndExpectDemoSetupProgress();
+
+  EXPECT_EQ("admin-us@cros-demo-mode.com",
+            DemoSetupController::GetSubOrganizationEmail());
+  OobeScreenWaiter(GetFirstSigninScreen()).Wait();
+
+  EXPECT_TRUE(StartupUtils::IsOobeCompleted());
+  EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
+}
+
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest, OnlineSetupFlowErrorDefault) {
   // Simulate online setup failure.
   enrollment_helper_.ExpectEnrollmentMode(
diff --git a/chrome/browser/ash/login/screens/reset_screen.cc b/chrome/browser/ash/login/screens/reset_screen.cc
index e31067c..69e576d 100644
--- a/chrome/browser/ash/login/screens/reset_screen.cc
+++ b/chrome/browser/ash/login/screens/reset_screen.cc
@@ -29,8 +29,8 @@
 #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -183,7 +183,7 @@
 ResetScreen::~ResetScreen() {
   if (view_)
     view_->Unbind();
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 // static
@@ -227,10 +227,8 @@
       view_->SetIsRollbackAvailable(false);
     dialog_type = reset::DialogViewType::kShortcutOfferingRollbackUnavailable;
   } else {
-    chromeos::DBusThreadManager::Get()
-        ->GetUpdateEngineClient()
-        ->CanRollbackCheck(base::BindOnce(&ResetScreen::OnRollbackCheck,
-                                          weak_ptr_factory_.GetWeakPtr()));
+    UpdateEngineClient::Get()->CanRollbackCheck(base::BindOnce(
+        &ResetScreen::OnRollbackCheck, weak_ptr_factory_.GetWeakPtr()));
   }
 
   if (dialog_type < reset::DialogViewType::kCount) {
@@ -326,7 +324,7 @@
       view_->GetIsRollbackRequested()) {
     OnToggleRollback();
   }
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   exit_callback_.Run();
 }
 
@@ -348,9 +346,9 @@
   if (view_ && view_->GetIsRollbackAvailable() &&
       view_->GetIsRollbackRequested()) {
     view_->SetScreenState(ResetView::State::kRevertPromise);
-    DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+    UpdateEngineClient::Get()->AddObserver(this);
     VLOG(1) << "Starting Rollback";
-    DBusThreadManager::Get()->GetUpdateEngineClient()->Rollback();
+    UpdateEngineClient::Get()->Rollback();
   } else if (view_ && view_->GetIsTpmFirmwareUpdateChecked()) {
     VLOG(1) << "Starting TPM firmware update";
     // Re-check availability with a couple seconds timeout. This addresses the
diff --git a/chrome/browser/ash/login/version_updater/version_updater.cc b/chrome/browser/ash/login/version_updater/version_updater.cc
index 39215f3b..c6b3916 100644
--- a/chrome/browser/ash/login/version_updater/version_updater.cc
+++ b/chrome/browser/ash/login/version_updater/version_updater.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/ash/login/version_updater/update_time_estimator.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_state.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -58,7 +58,7 @@
 }
 
 VersionUpdater::~VersionUpdater() {
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   network_portal_detector::GetInstance()->RemoveObserver(this);
 }
 
@@ -89,13 +89,10 @@
 }
 
 void VersionUpdater::SetUpdateOverCellularOneTimePermission() {
-  DBusThreadManager::Get()
-      ->GetUpdateEngineClient()
-      ->SetUpdateOverCellularOneTimePermission(
-          update_info_.update_version, update_info_.update_size,
-          base::BindOnce(
-              &VersionUpdater::OnSetUpdateOverCellularOneTimePermission,
-              weak_ptr_factory_.GetWeakPtr()));
+  UpdateEngineClient::Get()->SetUpdateOverCellularOneTimePermission(
+      update_info_.update_version, update_info_.update_size,
+      base::BindOnce(&VersionUpdater::OnSetUpdateOverCellularOneTimePermission,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void VersionUpdater::RejectUpdateOverCellular() {
@@ -108,7 +105,7 @@
 
 void VersionUpdater::RebootAfterUpdate() {
   VLOG(1) << "Initiate reboot after update";
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate();
+  UpdateEngineClient::Get()->RebootAfterUpdate();
   if (wait_for_reboot_time_.is_zero())  // Primarily for testing.
     OnWaitForRebootTimeElapsed();
   else
@@ -117,7 +114,7 @@
 }
 
 void VersionUpdater::StartExitUpdate(Result result) {
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   network_portal_detector::GetInstance()->RemoveObserver(this);
   delegate_->FinishExitUpdate(result);
   // Reset internal state, because in case of error user may make another
@@ -130,12 +127,10 @@
 }
 
 void VersionUpdater::GetEolInfo(EolInfoCallback callback) {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
   // Request the End of Life (Auto Update Expiration) status. Bind to a weak_ptr
   // bound method rather than passing `callback` directly so that `callback`
   // does not outlive `this`.
-  update_engine_client->GetEolInfo(
+  UpdateEngineClient::Get()->GetEolInfo(
       base::BindOnce(&VersionUpdater::OnGetEolInfo,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -158,11 +153,10 @@
   delegate_->UpdateInfoChanged(update_info_);
 
   network_portal_detector::GetInstance()->RemoveObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
   VLOG(1) << "Initiate update check";
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck(
-      base::BindOnce(&VersionUpdater::OnUpdateCheckStarted,
-                     weak_ptr_factory_.GetWeakPtr()));
+  UpdateEngineClient::Get()->RequestUpdateCheck(base::BindOnce(
+      &VersionUpdater::OnUpdateCheckStarted, weak_ptr_factory_.GetWeakPtr()));
 }
 
 void VersionUpdater::UpdateStatusChanged(
@@ -231,7 +225,7 @@
       update_info_.requires_permission_for_cellular = true;
       update_info_.progress_unavailable = false;
 
-      DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+      UpdateEngineClient::Get()->RemoveObserver(this);
       break;
     case update_engine::Operation::ATTEMPTING_ROLLBACK:
       VLOG(1) << "Attempting rollback";
@@ -322,7 +316,7 @@
 
       // StartUpdateCheck, which gets called when the error clears up, will add
       // the update engine observer back.
-      DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+      UpdateEngineClient::Get()->RemoveObserver(this);
 
       update_info_.state = State::STATE_ERROR;
       delegate_->UpdateInfoChanged(update_info_);
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index c4996107..b3bc017 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -189,7 +189,7 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/network/portal_detector/network_portal_detector.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_handler_callbacks.h"
 #include "chromeos/network/network_state.h"
@@ -1938,11 +1938,9 @@
   // If this is a Cellular First device, instruct UpdateEngine to allow
   // updates over cellular data connections.
   if (switches::IsCellularFirstDevice()) {
-    DBusThreadManager::Get()
-        ->GetUpdateEngineClient()
-        ->SetUpdateOverCellularPermission(
-            true, base::BindOnce(&WizardController::StartOOBEUpdate,
-                                 weak_factory_.GetWeakPtr()));
+    UpdateEngineClient::Get()->SetUpdateOverCellularPermission(
+        true, base::BindOnce(&WizardController::StartOOBEUpdate,
+                             weak_factory_.GetWeakPtr()));
   } else {
     StartOOBEUpdate();
   }
diff --git a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc
index 17441a9b..023b182 100644
--- a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc
+++ b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc
@@ -30,7 +30,7 @@
 #include "chrome/browser/upgrade_detector/build_state.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_handler.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -40,6 +40,7 @@
 
 namespace {
 
+using chromeos::UpdateEngineClient;
 using MinimumVersionRequirement =
     MinimumVersionPolicyHandler::MinimumVersionRequirement;
 
@@ -83,10 +84,6 @@
   return base::ClampRound(time / base::Days(1));
 }
 
-chromeos::UpdateEngineClient* GetUpdateEngineClient() {
-  return chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
-}
-
 // Overrides the relaunch notification style to required and configures the
 // relaunch deadline according to the deadline.
 void OverrideRelaunchNotification(base::Time deadline) {
@@ -169,7 +166,7 @@
 MinimumVersionPolicyHandler::~MinimumVersionPolicyHandler() {
   GetBuildState()->RemoveObserver(this);
   StopObservingNetwork();
-  GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void MinimumVersionPolicyHandler::AddObserver(Observer* observer) {
@@ -330,7 +327,7 @@
 
   update_required_time_ = clock_->Now();
   // Request the End of Life (Auto Update Expiration) status.
-  GetUpdateEngineClient()->GetEolInfo(
+  UpdateEngineClient::Get()->GetEolInfo(
       base::BindOnce(&MinimumVersionPolicyHandler::OnFetchEolInfo,
                      weak_factory_.GetWeakPtr()));
 }
@@ -560,7 +557,7 @@
   // will reboot it for applying the updates.
   VLOG(1) << "Update installed successfully at " << clock_->Now()
           << " with deadline " << update_required_deadline_;
-  GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   if (build_state->update_type() == BuildState::UpdateType::kNormalUpdate) {
     ResetOnUpdateCompleted();
     OverrideRelaunchNotification(update_required_deadline_);
@@ -592,7 +589,7 @@
 void MinimumVersionPolicyHandler::UpdateOverMeteredPermssionGranted() {
   VLOG(1) << "Permission for update over metered network granted.";
   chromeos::UpdateEngineClient* const update_engine_client =
-      GetUpdateEngineClient();
+      UpdateEngineClient::Get();
   if (!update_engine_client->HasObserver(this))
     update_engine_client->AddObserver(this);
   update_engine_client->RequestUpdateCheck(
@@ -604,14 +601,14 @@
     chromeos::UpdateEngineClient::UpdateCheckResult result) {
   VLOG(1) << "Update check started.";
   if (result != chromeos::UpdateEngineClient::UPDATE_RESULT_SUCCESS)
-    GetUpdateEngineClient()->RemoveObserver(this);
+    UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void MinimumVersionPolicyHandler::UpdateStatusChanged(
     const update_engine::StatusResult& status) {
   if (status.current_operation() ==
       update_engine::Operation::NEED_PERMISSION_TO_UPDATE) {
-    GetUpdateEngineClient()->SetUpdateOverCellularOneTimePermission(
+    UpdateEngineClient::Get()->SetUpdateOverCellularOneTimePermission(
         status.new_version(), status.new_size(),
         base::BindOnce(&MinimumVersionPolicyHandler::
                            OnSetUpdateOverCellularOneTimePermission,
@@ -624,7 +621,7 @@
   if (success)
     UpdateOverMeteredPermssionGranted();
   else
-    GetUpdateEngineClient()->RemoveObserver(this);
+    UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void MinimumVersionPolicyHandler::OnDeadlineReached() {
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
index b097a38..daa05bb 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
+++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "chrome/browser/browser_process.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_handler.h"
 #include "components/device_event_log/device_event_log.h"
@@ -22,8 +21,7 @@
           update_checker_internal::
               kMaxOsAndPoliciesUpdateCheckerRetryIterations,
           update_checker_internal::kOsAndPoliciesUpdateCheckerRetryTime),
-      update_engine_client_(
-          chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()) {}
+      update_engine_client_(chromeos::UpdateEngineClient::Get()) {}
 
 OsAndPoliciesUpdateChecker::~OsAndPoliciesUpdateChecker() {
   // Called to remove any observers.
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector.cc b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
index f18bc31..7f799b0f 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector.cc
@@ -69,7 +69,6 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/hermes/hermes_euicc_client.h"
 #include "chromeos/dbus/hermes/hermes_manager_client.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
@@ -2513,9 +2512,7 @@
   em::OsUpdateStatus* os_update_status = status->mutable_os_update_status();
 
   const update_engine::StatusResult update_engine_status =
-      chromeos::DBusThreadManager::Get()
-          ->GetUpdateEngineClient()
-          ->GetLastStatus();
+      chromeos::UpdateEngineClient::Get()->GetLastStatus();
 
   absl::optional<base::Version> required_platform_version;
 
diff --git a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
index 2ccbdcb..b070d2f 100644
--- a/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
+++ b/chrome/browser/ash/policy/status_collector/legacy_device_status_collector.cc
@@ -68,7 +68,6 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/attestation/attestation_client.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
 #include "chromeos/dbus/tpm_manager/tpm_manager.pb.h"
 #include "chromeos/dbus/tpm_manager/tpm_manager_client.h"
@@ -2433,9 +2432,7 @@
   em::OsUpdateStatus* os_update_status = status->mutable_os_update_status();
 
   const update_engine::StatusResult update_engine_status =
-      chromeos::DBusThreadManager::Get()
-          ->GetUpdateEngineClient()
-          ->GetLastStatus();
+      chromeos::UpdateEngineClient::Get()->GetLastStatus();
 
   absl::optional<base::Version> required_platform_version;
 
diff --git a/chrome/browser/ash/preferences.cc b/chrome/browser/ash/preferences.cc
index 6d52dfb6..d23d6978 100644
--- a/chrome/browser/ash/preferences.cc
+++ b/chrome/browser/ash/preferences.cc
@@ -51,7 +51,6 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/ash/components/dbus/pciguard/pciguard_client.h"
 #include "chromeos/components/disks/disks_prefs.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine/update_engine.pb.h"
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/system/devicemode.h"
@@ -124,7 +123,7 @@
 Preferences::~Preferences() {
   prefs_->RemoveObserver(this);
   user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 // static
@@ -605,8 +604,7 @@
     pref_change_registrar_.Add(copy_pref, callback);
 
   // Re-enable OTA update when feature flag is disabled by owner.
-  auto* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
+  auto* update_engine_client = UpdateEngineClient::Get();
   if (user_manager::UserManager::Get()->IsCurrentUserOwner() &&
       !features::IsConsumerAutoUpdateToggleAllowed()) {
     // Write into the platform will signal back so pref gets synced.
@@ -629,7 +627,7 @@
   // This causes OnIsSyncingChanged to be called when the value of
   // PrefService::IsSyncing() changes.
   prefs->AddObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
 
   user_ = user;
   user_is_primary_ =
@@ -696,9 +694,7 @@
 
   InitUserPrefs(prefs);
 
-  auto* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-  update_engine_client->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
 
   input_method_syncer_ =
       std::make_unique<input_method::InputMethodSyncer>(prefs, ime_state_);
diff --git a/chrome/browser/ash/system/automatic_reboot_manager.cc b/chrome/browser/ash/system/automatic_reboot_manager.cc
index dfb7b44..024d46d 100644
--- a/chrome/browser/ash/system/automatic_reboot_manager.cc
+++ b/chrome/browser/ash/system/automatic_reboot_manager.cc
@@ -36,7 +36,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
@@ -162,7 +162,7 @@
           &AutomaticRebootManager::OnAppTerminating, base::Unretained(this)));
 
   PowerManagerClient::Get()->AddObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
 
   // If no user is logged in, a reboot may be performed whenever the user is
   // idle. Start listening for user activity to determine whether the user is
@@ -189,7 +189,7 @@
     observer.WillDestroyAutomaticRebootManager();
 
   PowerManagerClient::Get()->RemoveObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   if (ui::UserActivityDetector::Get())
     ui::UserActivityDetector::Get()->RemoveObserver(this);
 }
@@ -290,8 +290,7 @@
     update_reboot_needed_time_ =
         *system_event_times.update_reboot_needed_time + offset;
   } else {
-    UpdateStatusChanged(
-        DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
+    UpdateStatusChanged(UpdateEngineClient::Get()->GetLastStatus());
   }
 
   Reschedule();
diff --git a/chrome/browser/ash/system_web_apps/BUILD.gn b/chrome/browser/ash/system_web_apps/BUILD.gn
index c6051ec..d44cd4b 100644
--- a/chrome/browser/ash/system_web_apps/BUILD.gn
+++ b/chrome/browser/ash/system_web_apps/BUILD.gn
@@ -94,8 +94,8 @@
     ":system_web_apps",
     "//base",
     "//chrome/app:command_ids",
+    "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
     "//chrome/browser/ash/system_web_apps/types",
-    "//chrome/browser/web_applications:browser_tests_base",
     "//chrome/browser/web_applications:web_applications_test_support",
     "//chrome/test:test_support",
     "//components/services/app_service/public/cpp:app_update",
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
index c6dfec7..1a8fcd2c 100644
--- a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/apps/app_service/launch_utils.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_type.h"
 #include "chrome/browser/file_system_access/file_system_access_permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -33,7 +34,6 @@
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/web_applications/proto/web_app.pb.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -104,9 +104,7 @@
 }  // namespace
 
 using SystemWebAppManagerBrowserTestBasicInstall =
-    web_app::SystemWebAppManagerBrowserTest;
-
-using SystemWebAppManagerBrowserTest = web_app::SystemWebAppManagerBrowserTest;
+    SystemWebAppManagerBrowserTest;
 
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
 // Test that System Apps install correctly with a manifest.
@@ -251,14 +249,14 @@
 // EvalJs because of some quirks surrounding origin trials and content security
 // policies.
 class SystemWebAppManagerFileHandlingBrowserTestBase
-    : public TestProfileTypeMixin<web_app::SystemWebAppBrowserTestBase> {
+    : public TestProfileTypeMixin<SystemWebAppBrowserTestBase> {
  public:
   using IncludeLaunchDirectory =
       web_app::TestSystemWebAppInstallation::IncludeLaunchDirectory;
 
   explicit SystemWebAppManagerFileHandlingBrowserTestBase(
       IncludeLaunchDirectory include_launch_directory)
-      : TestProfileTypeMixin<web_app::SystemWebAppBrowserTestBase>(
+      : TestProfileTypeMixin<SystemWebAppBrowserTestBase>(
             /*install_mock=*/false) {
     scoped_feature_blink_api_.InitWithFeatures(
         {blink::features::kFileHandlingAPI}, {});
@@ -275,7 +273,7 @@
     params.override_url = maybe_installation_->GetAppUrl();
     params.launch_files = std::move(launch_files);
 
-    return web_app::SystemWebAppBrowserTestBase::LaunchApp(std::move(params));
+    return SystemWebAppBrowserTestBase::LaunchApp(std::move(params));
   }
 
   content::WebContents* LaunchAppWithoutWaiting(
@@ -285,7 +283,7 @@
     params.override_url = maybe_installation_->GetAppUrl();
     params.launch_files = std::move(launch_files);
 
-    return web_app::SystemWebAppBrowserTestBase::LaunchAppWithoutWaiting(
+    return SystemWebAppBrowserTestBase::LaunchAppWithoutWaiting(
         std::move(params));
   }
 
@@ -852,7 +850,7 @@
     params.launch_files = {temp_file_path};
     params.override_url = GetStartUrl();
 
-    return web_app::SystemWebAppBrowserTestBase::LaunchApp(std::move(params));
+    return SystemWebAppBrowserTestBase::LaunchApp(std::move(params));
   }
 
   bool WaitForLaunchParam(content::WebContents* web_contents) {
diff --git a/chrome/browser/ash/system_web_apps/test_support/BUILD.gn b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
new file mode 100644
index 0000000..971de445
--- /dev/null
+++ b/chrome/browser/ash/system_web_apps/test_support/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chrome/browser/buildflags.gni")
+
+# TODO(crbug.com/1321984): Make SystemWebAppManager an ash-only object and
+# move all the GN dependencies under `if (is_chromeos_ash)` section.
+# assert(is_chromeos_ash)
+
+# Browsertest base classes that depend on //chrome/test:test_support_ui. Must
+# be separate from :test_support because that is depended upon by
+# //chrome/test:test_support_ui.
+source_set("test_support_ui") {
+  testonly = true
+
+  sources = [
+    "system_web_app_browsertest_base.cc",
+    "system_web_app_browsertest_base.h",
+  ]
+
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  deps = [
+    "//chrome/browser",
+    "//chrome/browser/ash/system_web_apps",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/ui",
+    "//chrome/browser/web_applications",
+    "//chrome/browser/web_applications:web_applications_test_support",
+    "//chrome/test:test_support_ui",
+    "//components/services/app_service/public/cpp:types",
+    "//content/test:test_support",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc b/chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.cc
similarity index 84%
rename from chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc
rename to chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.cc
index fda6bb6..87563c7 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc
+++ b/chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
@@ -21,23 +21,23 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-namespace web_app {
+namespace ash {
 
 SystemWebAppBrowserTestBase::SystemWebAppBrowserTestBase(bool install_mock) {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  EnableSystemWebAppsInLacrosForTesting();
+  web_app::EnableSystemWebAppsInLacrosForTesting();
 #endif
 }
 
 SystemWebAppBrowserTestBase::~SystemWebAppBrowserTestBase() = default;
 
-ash::SystemWebAppManager& SystemWebAppBrowserTestBase::GetManager() {
-  auto* swa_manager = ash::SystemWebAppManager::Get(browser()->profile());
+SystemWebAppManager& SystemWebAppBrowserTestBase::GetManager() {
+  auto* swa_manager = SystemWebAppManager::Get(browser()->profile());
   DCHECK(swa_manager);
   return *swa_manager;
 }
 
-ash::SystemWebAppType SystemWebAppBrowserTestBase::GetMockAppType() {
+SystemWebAppType SystemWebAppBrowserTestBase::GetMockAppType() {
   CHECK(maybe_installation_);
   return maybe_installation_->GetType();
 }
@@ -60,8 +60,8 @@
 }
 
 apps::AppLaunchParams SystemWebAppBrowserTestBase::LaunchParamsForApp(
-    ash::SystemWebAppType system_app_type) {
-  absl::optional<AppId> app_id =
+    SystemWebAppType system_app_type) {
+  absl::optional<web_app::AppId> app_id =
       GetManager().GetAppIdForSystemApp(system_app_type);
 
   CHECK(app_id.has_value());
@@ -83,14 +83,14 @@
   DCHECK(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(
       browser()->profile()));
 
-  DCHECK(AreSystemWebAppsSupported());
+  DCHECK(web_app::AreSystemWebAppsSupported());
 
   if (!params.launch_files.empty()) {
     // SWA browser tests bypass the code in `WebAppPublisherHelper` that fills
     // in `override_url`, so fill it in here, assuming the file handler action
     // URL matches the start URL.
     params.override_url =
-        WebAppProvider::GetForLocalAppsUnchecked(browser()->profile())
+        web_app::WebAppProvider::GetForLocalAppsUnchecked(browser()->profile())
             ->registrar()
             .GetAppStartUrl(params.app_id);
   }
@@ -121,7 +121,7 @@
 }
 
 content::WebContents* SystemWebAppBrowserTestBase::LaunchApp(
-    ash::SystemWebAppType type,
+    SystemWebAppType type,
     Browser** browser) {
   return LaunchApp(LaunchParamsForApp(type), browser);
 }
@@ -133,22 +133,23 @@
 }
 
 content::WebContents* SystemWebAppBrowserTestBase::LaunchAppWithoutWaiting(
-    ash::SystemWebAppType type,
+    SystemWebAppType type,
     Browser** browser) {
   return LaunchAppWithoutWaiting(LaunchParamsForApp(type), browser);
 }
 
 GURL SystemWebAppBrowserTestBase::GetStartUrl(
     const apps::AppLaunchParams& params) {
-  DCHECK(AreSystemWebAppsSupported());
+  DCHECK(web_app::AreSystemWebAppsSupported());
   return params.override_url.is_valid()
              ? params.override_url
-             : WebAppProvider::GetForLocalAppsUnchecked(browser()->profile())
+             : web_app::WebAppProvider::GetForLocalAppsUnchecked(
+                   browser()->profile())
                    ->registrar()
                    .GetAppStartUrl(params.app_id);
 }
 
-GURL SystemWebAppBrowserTestBase::GetStartUrl(ash::SystemWebAppType type) {
+GURL SystemWebAppBrowserTestBase::GetStartUrl(SystemWebAppType type) {
   return GetStartUrl(LaunchParamsForApp(type));
 }
 
@@ -157,7 +158,7 @@
 }
 
 size_t SystemWebAppBrowserTestBase::GetSystemWebAppBrowserCount(
-    ash::SystemWebAppType type) {
+    SystemWebAppType type) {
   auto* browser_list = BrowserList::GetInstance();
   return std::count_if(
       browser_list->begin(), browser_list->end(), [&](Browser* browser) {
@@ -170,8 +171,8 @@
     : TestProfileTypeMixin<SystemWebAppBrowserTestBase>(install_mock) {
   if (install_mock) {
     maybe_installation_ =
-        TestSystemWebAppInstallation::SetUpStandaloneSingleWindowApp();
+        web_app::TestSystemWebAppInstallation::SetUpStandaloneSingleWindowApp();
   }
 }
 
-}  // namespace web_app
+}  // namespace ash
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h b/chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h
similarity index 81%
rename from chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h
rename to chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h
index 92d416e..9efa734 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h
+++ b/chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_SYSTEM_WEB_APPS_TEST_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_SYSTEM_WEB_APPS_TEST_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
+#ifndef CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_TEST_SUPPORT_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
+#define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_TEST_SUPPORT_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
 
 #include <memory>
 
@@ -26,11 +26,9 @@
 }
 
 namespace ash {
+
 enum class SystemWebAppType;
 class SystemWebAppManager;
-}
-
-namespace web_app {
 
 class SystemWebAppBrowserTestBase : public InProcessBrowserTest {
  public:
@@ -48,11 +46,11 @@
   // Returns the SystemWebAppManager for browser()->profile(). For incognito
   // profiles, this will be the SystemWebAppManager of the original profile.
   // Returns TestSystemWebAppManager if initialized with |install_mock| true.
-  ash::SystemWebAppManager& GetManager();
+  SystemWebAppManager& GetManager();
 
-  // Returns ash::SystemWebAppType of mocked app, only valid if |install_mock|
+  // Returns SystemWebAppType of mocked app, only valid if |install_mock|
   // is true.
-  ash::SystemWebAppType GetMockAppType();
+  SystemWebAppType GetMockAppType();
 
   // Returns the start URL based on the given |params|.
   GURL GetStartUrl(const apps::AppLaunchParams& params);
@@ -61,14 +59,13 @@
   GURL GetStartUrl();
 
   // Returns the URL for a installed system web app type.
-  GURL GetStartUrl(ash::SystemWebAppType type);
+  GURL GetStartUrl(SystemWebAppType type);
 
   void WaitForTestSystemAppInstall();
 
   // Creates a default AppLaunchParams for |system_app_type|. Launches a window.
   // Uses kSourceTest as the AppLaunchSource.
-  apps::AppLaunchParams LaunchParamsForApp(
-      ash::SystemWebAppType system_app_type);
+  apps::AppLaunchParams LaunchParamsForApp(SystemWebAppType system_app_type);
 
   // Launch the given System App from |params|, and wait for the application to
   // finish loading. If |browser| is not nullptr, it will store the Browser*
@@ -79,7 +76,7 @@
   // Launch the given System App |type| with default AppLaunchParams, and wait
   // for the application to finish loading. If |browser| is not nullptr, it will
   // store the Browser* that hosts the launched application.
-  content::WebContents* LaunchApp(ash::SystemWebAppType type,
+  content::WebContents* LaunchApp(SystemWebAppType type,
                                   Browser** browser = nullptr);
 
   // Launch the given System App from |params|, without waiting for the
@@ -91,14 +88,14 @@
   // Launch the given System App |type| with default AppLaunchParams, without
   // waiting for the application to finish loading. If |browser| is not nullptr,
   // it will store the Browser* that hosts the launched application.
-  content::WebContents* LaunchAppWithoutWaiting(ash::SystemWebAppType type,
+  content::WebContents* LaunchAppWithoutWaiting(SystemWebAppType type,
                                                 Browser** browser = nullptr);
 
   // Returns number of system web app browser windows matching |type|.
-  size_t GetSystemWebAppBrowserCount(ash::SystemWebAppType type);
+  size_t GetSystemWebAppBrowserCount(SystemWebAppType type);
 
  protected:
-  std::unique_ptr<TestSystemWebAppInstallation> maybe_installation_;
+  std::unique_ptr<web_app::TestSystemWebAppInstallation> maybe_installation_;
 
  private:
   std::unique_ptr<KeyedService> CreateWebAppProvider(Profile* profile);
@@ -111,7 +108,7 @@
                                   bool wait_for_load,
                                   Browser** out_browser);
 
-  OsIntegrationManager::ScopedSuppressForTesting os_hooks_suppress_;
+  web_app::OsIntegrationManager::ScopedSuppressForTesting os_hooks_suppress_;
 };
 
 class SystemWebAppManagerBrowserTest
@@ -125,6 +122,6 @@
   ~SystemWebAppManagerBrowserTest() override = default;
 };
 
-}  // namespace web_app
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_SYSTEM_WEB_APPS_TEST_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
+#endif  // CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_TEST_SUPPORT_SYSTEM_WEB_APP_BROWSERTEST_BASE_H_
diff --git a/chrome/browser/ash/web_applications/camera_app/camera_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/camera_app/camera_app_integration_browsertest.cc
index fffa12d..061b91d 100644
--- a/chrome/browser/ash/web_applications/camera_app/camera_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/camera_app/camera_app_integration_browsertest.cc
@@ -4,11 +4,11 @@
 
 #include "ash/constants/ash_features.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
index d5ffc718..c8f9cfe 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_integration_browsertest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ash/release_notes/release_notes_notification.h"
 #include "chrome/browser/ash/release_notes/release_notes_storage.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/ash/web_applications/help_app/help_app_discover_tab_notification.h"
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
@@ -39,7 +40,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ash/web_applications/os_feedback_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/os_feedback_app_integration_browsertest.cc
index 133d3e8..ae2e9f7 100644
--- a/chrome/browser/ash/web_applications/os_feedback_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/os_feedback_app_integration_browsertest.cc
@@ -9,13 +9,13 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_integration_browsertest.cc
index 0d94398..3e5a8fe 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_integration_browsertest.cc
@@ -219,10 +219,7 @@
 
 class PersonalizationAppIntegrationTest : public SystemWebAppIntegrationTest {
  public:
-  PersonalizationAppIntegrationTest() {
-    scoped_feature_list_.InitWithFeatures({ash::features::kWallpaperWebUI},
-                                          {ash::features::kPersonalizationHub});
-  }
+  PersonalizationAppIntegrationTest() = default;
 
   // SystemWebAppIntegrationTest:
   void SetUp() override {
@@ -270,16 +267,13 @@
 
     EXPECT_TRUE(widget->IsFullscreen());
   }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Test that the Personalization App installs correctly.
 IN_PROC_BROWSER_TEST_P(PersonalizationAppIntegrationTest,
                        PersonalizationAppInstalls) {
   const GURL url(kChromeUIPersonalizationAppURL);
-  std::string appTitle = "Wallpaper";
+  std::string appTitle = "Wallpaper & style";
   EXPECT_NO_FATAL_FAILURE(ExpectSystemWebAppValid(
       ash::SystemWebAppType::PERSONALIZATION, url, appTitle));
 }
@@ -383,13 +377,12 @@
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
     PersonalizationAppIntegrationTest);
 
-class PersonalizationAppWithHubIntegrationTest
+class PersonalizationAppWithoutHubIntegrationTest
     : public PersonalizationAppIntegrationTest {
  public:
-  PersonalizationAppWithHubIntegrationTest() {
-    scoped_feature_list_.InitWithFeatures(
-        {ash::features::kWallpaperWebUI, ash::features::kPersonalizationHub},
-        {});
+  PersonalizationAppWithoutHubIntegrationTest() {
+    scoped_feature_list_.InitAndDisableFeature(
+        ash::features::kPersonalizationHub);
   }
 
  private:
@@ -398,16 +391,16 @@
 
 // Test that the Personalization App installs correctly with PersonalizationHub
 // feature on.
-IN_PROC_BROWSER_TEST_P(PersonalizationAppWithHubIntegrationTest,
+IN_PROC_BROWSER_TEST_P(PersonalizationAppWithoutHubIntegrationTest,
                        PersonalizationAppInstalls) {
   const GURL url(kChromeUIPersonalizationAppURL);
-  std::string appTitle = "Wallpaper & style";
+  std::string appTitle = "Wallpaper";
   EXPECT_NO_FATAL_FAILURE(ExpectSystemWebAppValid(
       ash::SystemWebAppType::PERSONALIZATION, url, appTitle));
 }
 
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
-    PersonalizationAppWithHubIntegrationTest);
+    PersonalizationAppWithoutHubIntegrationTest);
 
 }  // namespace personalization_app
 }  // namespace ash
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
index d8b22d5..0f1e370 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
@@ -224,8 +224,7 @@
       : scoped_user_manager_(std::make_unique<ash::FakeChromeUserManager>()),
         profile_manager_(TestingBrowserProcess::GetGlobal()) {
     std::vector<base::Feature> disabled_features;
-    std::vector<base::Feature> enabled_features = {
-        ash::features::kWallpaperWebUI};
+    std::vector<base::Feature> enabled_features;
 
     // Conditionally enable/disable Google Photos integration based on test
     // parameterization.
diff --git a/chrome/browser/ash/web_applications/system_web_app_integration_test.h b/chrome/browser/ash/web_applications/system_web_app_integration_test.h
index f13da96..f861783 100644
--- a/chrome/browser/ash/web_applications/system_web_app_integration_test.h
+++ b/chrome/browser/ash/web_applications/system_web_app_integration_test.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "url/gurl.h"
 
 namespace ash {
@@ -18,8 +18,7 @@
 
 // Test harness for how ChromeOS System Web Apps integrate with the System Web
 // App platform.
-class SystemWebAppIntegrationTest
-    : public web_app::SystemWebAppManagerBrowserTest {
+class SystemWebAppIntegrationTest : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppIntegrationTest();
   SystemWebAppIntegrationTest(const SystemWebAppIntegrationTest&) = delete;
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc
index 4f730331..10e06f5 100644
--- a/chrome/browser/download/download_shelf_context_menu.cc
+++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -51,7 +51,7 @@
     return;
   }
 
-  for (int command_int = 1; command_int < DownloadCommands::Command::REVIEW;
+  for (int command_int = 1; command_int < DownloadCommands::Command::MAX;
        command_int++) {
     if (model->GetIndexOfCommandId(command_int) != -1 &&
         IsCommandIdEnabled(command_int)) {
@@ -205,9 +205,8 @@
     case DownloadCommands::BYPASS_DEEP_SCANNING:
       id = IDS_OPEN_DOWNLOAD_NOW;
       break;
+    // This command is not supported on the context menu.
     case DownloadCommands::REVIEW:
-      id = IDS_REVIEW_DOWNLOAD;
-      break;
     case DownloadCommands::MAX:
       NOTREACHED();
       break;
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index 8b658b2..c276e87 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -165,8 +165,11 @@
       return clicked
                  ? DownloadShelfContextMenuAction::kBypassDeepScanningClicked
                  : DownloadShelfContextMenuAction::kBypassDeepScanningEnabled;
+
+    // The following is not actually visible in the context menu so should
+    // never be logged.
     case DownloadCommands::Command::REVIEW:
-      return clicked ? DownloadShelfContextMenuAction::kReviewClicked
-                     : DownloadShelfContextMenuAction::kReviewEnabled;
+      NOTREACHED();
+      return DownloadShelfContextMenuAction::kNotReached;
   }
 }
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index 272a7dd..6d6520a1 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -221,9 +221,10 @@
   kDeepScanClicked = 31,
   kBypassDeepScanningEnabled = 32,
   kBypassDeepScanningClicked = 33,
-  kReviewEnabled = 34,
-  kReviewClicked = 35,
-  kMaxValue = kReviewClicked
+  // kReviewEnabled = 34,
+  // kReviewClicked = 35,
+  kNotReached = 36,  // Should not be possible to hit
+  kMaxValue = kNotReached
 };
 
 DownloadShelfContextMenuAction DownloadCommandToShelfAction(
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc
index 0398fb2..28711d1 100644
--- a/chrome/browser/download/notification/download_item_notification.cc
+++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -148,14 +148,6 @@
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_OpenWhenComplete"));
       break;
-    case DownloadCommands::ALWAYS_OPEN_TYPE:
-      base::RecordAction(
-          UserMetricsAction("DownloadNotification.Button_AlwaysOpenType"));
-      break;
-    case DownloadCommands::PLATFORM_OPEN:
-      base::RecordAction(
-          UserMetricsAction("DownloadNotification.Button_PlatformOpen"));
-      break;
     case DownloadCommands::CANCEL:
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_Cancel"));
@@ -171,10 +163,6 @@
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_LearnScanning"));
       break;
-    case DownloadCommands::LEARN_MORE_INTERRUPTED:
-      base::RecordAction(
-          UserMetricsAction("DownloadNotification.Button_LearnInterrupted"));
-      break;
     case DownloadCommands::LEARN_MORE_MIXED_CONTENT:
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_LearnMixedContent"));
@@ -195,14 +183,12 @@
       base::RecordAction(
           UserMetricsAction("DownloadNotification.Button_DeepScan"));
       break;
+    // Not actually displayed in notification, so should never be reached.
+    case DownloadCommands::ALWAYS_OPEN_TYPE:
+    case DownloadCommands::PLATFORM_OPEN:
+    case DownloadCommands::LEARN_MORE_INTERRUPTED:
     case DownloadCommands::BYPASS_DEEP_SCANNING:
-      base::RecordAction(
-          UserMetricsAction("DownloadNotification.Button_BypassDeepScanning"));
-      break;
     case DownloadCommands::REVIEW:
-      base::RecordAction(
-          UserMetricsAction("DownloadNotification.Button_Review"));
-      break;
     case DownloadCommands::MAX:
       NOTREACHED();
       break;
diff --git a/chrome/browser/extensions/api/system_private/system_private_api.cc b/chrome/browser/extensions/api/system_private/system_private_api.cc
index 6c5df053..8b5709b 100644
--- a/chrome/browser/extensions/api/system_private/system_private_api.cc
+++ b/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -19,7 +19,6 @@
 #include "google_apis/google_api_keys.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/dbus/dbus_thread_manager.h"  // nogncheck
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #else
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
@@ -71,9 +70,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // With UpdateEngineClient, we can provide more detailed information about
   // system updates on ChromeOS.
-  const update_engine::StatusResult status = chromeos::DBusThreadManager::Get()
-                                                 ->GetUpdateEngineClient()
-                                                 ->GetLastStatus();
+  const update_engine::StatusResult status =
+      chromeos::UpdateEngineClient::Get()->GetLastStatus();
   // |download_progress| is set to 1 after download finishes
   // (i.e. verify, finalize and need-reboot phase) to indicate the progress
   // even though |status.download_progress| is 0 in these phases.
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 6ba2115..d1130b0 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -93,6 +93,7 @@
 #include "content/public/test/url_loader_monitor.h"
 #include "content/public/test/web_transport_simple_test_server.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
+#include "extensions/browser/background_script_executor.h"
 #include "extensions/browser/blocked_action_type.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -245,23 +246,50 @@
   EXPECT_TRUE(success);
 }
 
+base::Value ExecuteScriptAndReturnValue(const ExtensionId& extension_id,
+                                        content::BrowserContext* context,
+                                        const std::string& script) {
+  return BackgroundScriptExecutor::ExecuteScript(
+      context, extension_id, script,
+      BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+}
+
+absl::optional<bool> ExecuteScriptAndReturnBool(
+    const ExtensionId& extension_id,
+    content::BrowserContext* context,
+    const std::string& script) {
+  absl::optional<bool> result;
+  base::Value script_result =
+      ExecuteScriptAndReturnValue(extension_id, context, script);
+  if (script_result.is_bool())
+    result = script_result.GetBool();
+  return result;
+}
+
+absl::optional<std::string> ExecuteScriptAndReturnString(
+    const ExtensionId& extension_id,
+    content::BrowserContext* context,
+    const std::string& script) {
+  absl::optional<std::string> result;
+  base::Value script_result =
+      ExecuteScriptAndReturnValue(extension_id, context, script);
+  if (script_result.is_string())
+    result = script_result.GetString();
+  return result;
+}
+
 // Returns the current count of a variable stored in the |extension| background
 // page. Returns -1 if something goes awry.
 int GetCountFromBackgroundPage(const Extension* extension,
                                content::BrowserContext* context,
                                const std::string& variable_name) {
-  ExtensionHost* host =
-      ProcessManager::Get(context)->GetBackgroundHostForExtension(
-          extension->id());
-  if (!host || !host->host_contents())
+  const std::string script = base::StringPrintf(
+      "chrome.test.sendScriptResult(%s)", variable_name.c_str());
+  base::Value value =
+      ExecuteScriptAndReturnValue(extension->id(), context, script);
+  if (!value.is_int())
     return -1;
-
-  int count = -1;
-  if (!ExecuteScriptAndExtractInt(
-          host->host_contents(),
-          "window.domAutomationController.send(" + variable_name + ")", &count))
-    return -1;
-  return count;
+  return value.GetInt();
 }
 
 // Returns the current count of webRequests received by the |extension| in
@@ -269,8 +297,7 @@
 // object). Returns -1 if something goes awry.
 int GetWebRequestCountFromBackgroundPage(const Extension* extension,
                                          content::BrowserContext* context) {
-  return GetCountFromBackgroundPage(extension, context,
-                                    "window.webRequestCount");
+  return GetCountFromBackgroundPage(extension, context, "self.webRequestCount");
 }
 
 // Returns true if the |extension|'s background page saw an event for a request
@@ -278,22 +305,14 @@
 bool HasSeenWebRequestInBackgroundPage(const Extension* extension,
                                        content::BrowserContext* context,
                                        const std::string& hostname) {
-  // TODO(devlin): Here and in Get*CountFromBackgroundPage(), we should leverage
-  // ExecuteScriptInBackgroundPage().
-  ExtensionHost* host =
-      ProcessManager::Get(context)->GetBackgroundHostForExtension(
-          extension->id());
-  if (!host || !host->host_contents())
-    return false;
-
-  bool seen = false;
-  std::string script = base::StringPrintf(
-      R"(domAutomationController.send(
-                 window.requestedHostnames.includes('%s'));)",
+  const std::string script = base::StringPrintf(
+      R"(chrome.test.sendScriptResult(
+                 self.requestedHostnames.includes('%s'));)",
       hostname.c_str());
-  EXPECT_TRUE(
-      ExecuteScriptAndExtractBool(host->host_contents(), script, &seen));
-  return seen;
+  base::Value value =
+      ExecuteScriptAndReturnValue(extension->id(), context, script);
+  DCHECK(value.is_bool());
+  return value.GetBool();
 }
 
 void WaitForExtraHeadersListener(base::WaitableEvent* event,
@@ -1239,16 +1258,16 @@
            "name": "Web Request Withheld Hosts",
            "manifest_version": 2,
            "version": "0.1",
-           "background": { "scripts": ["background.js"] },
+           "background": { "scripts": ["background.js"], "persistent": true },
            "permissions": ["*://b.com:*/*", "webRequest"]
          })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
-                     R"(window.webRequestCount = 0;
-         window.requestedHostnames = [];
+                     R"(self.webRequestCount = 0;
+         self.requestedHostnames = [];
 
          chrome.webRequest.onBeforeRequest.addListener(function(details) {
-           ++window.webRequestCount;
-           window.requestedHostnames.push((new URL(details.url)).hostname);
+           ++self.webRequestCount;
+           self.requestedHostnames.push((new URL(details.url)).hostname);
          }, {urls:['<all_urls>']});
          chrome.test.sendMessage('ready');)");
 
@@ -1305,11 +1324,11 @@
 
   auto get_clients_google_request_count = [this, extension]() {
     return GetCountFromBackgroundPage(extension, profile(),
-                                      "window.clientsGoogleWebRequestCount");
+                                      "self.clientsGoogleWebRequestCount");
   };
   auto get_yahoo_request_count = [this, extension]() {
     return GetCountFromBackgroundPage(extension, profile(),
-                                      "window.yahooWebRequestCount");
+                                      "self.yahooWebRequestCount");
   };
 
   EXPECT_EQ(0, get_clients_google_request_count());
@@ -1413,11 +1432,11 @@
 
   // The extension should not have seen the PAC request.
   EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.pacRequestCount"));
+                                          "self.pacRequestCount"));
 
   // The extension should have seen the request for the main frame.
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.title2RequestCount"));
+                                          "self.title2RequestCount"));
 
   // The PAC request should have succeeded, as should the subsequent URL
   // request.
@@ -1510,9 +1529,9 @@
 
   // Check that the Dice header cannot be read by the extension.
   EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.diceResponseHeaderCount"));
+                                          "self.diceResponseHeaderCount"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.controlResponseHeaderCount"));
+                                          "self.controlResponseHeaderCount"));
 
   // Navigate to a non-Gaia URL intercepted by the extension.
   test_webcontents_observer.Clear();
@@ -1530,9 +1549,9 @@
 
   // Check that the Dice header can be read by the extension.
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.diceResponseHeaderCount"));
+                                          "self.diceResponseHeaderCount"));
   EXPECT_EQ(2, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.controlResponseHeaderCount"));
+                                          "self.controlResponseHeaderCount"));
 }
 
 // Test that the webRequest events are dispatched for the WebSocket handshake
@@ -1641,7 +1660,7 @@
            "version": "0.1",
            "permissions": ["webRequest", "webRequestBlocking", "*://*/*"],
            "manifest_version": 2,
-           "background": { "scripts": ["background.js"] }
+           "background": { "scripts": ["background.js"], "persistent": true }
          })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
                      R"(chrome.webRequest.onBeforeRequest.addListener(
@@ -1843,11 +1862,9 @@
 
     // Run a script in the extensions background page to ensure that we have
     // received the initiator message from the extension.
-    ASSERT_EQ(
-        std::to_string(expected_requests_intercepted_count),
-        ExecuteScriptInBackgroundPage(extension->id(),
-                                      "window.domAutomationController.send("
-                                      "requestsIntercepted.toString());"));
+    ASSERT_EQ(expected_requests_intercepted_count,
+              GetCountFromBackgroundPage(extension, profile(),
+                                         "self.requestsIntercepted"));
 
     if (testcase.expected_initiator.empty()) {
       EXPECT_FALSE(initiator_listener.was_satisfied());
@@ -2011,12 +2028,11 @@
   // Returns true if the given extension was able to intercept the request to
   // "fake_ntp_script.js".
   auto was_script_request_intercepted =
-      [this](const std::string& extension_id) {
-        const std::string result = ExecuteScriptInBackgroundPage(
-            extension_id, "getAndResetRequestIntercepted();");
-        EXPECT_TRUE(result == "true" || result == "false")
-            << "Unexpected result " << result;
-        return result == "true";
+      [this](const ExtensionId& extension_id) {
+        const absl::optional<bool> result = ExecuteScriptAndReturnBool(
+            extension_id, profile(), "getAndResetRequestIntercepted();");
+        DCHECK(result);
+        return *result;
       };
 
   // Returns true if the given |web_contents| has window.scriptExecuted set to
@@ -2152,12 +2168,11 @@
   // Returns true if the given extension was able to intercept the request to
   // |one_google_bar_url()|.
   auto was_script_request_intercepted =
-      [this](const std::string& extension_id) {
-        const std::string result = ExecuteScriptInBackgroundPage(
-            extension_id, "getAndResetRequestIntercepted();");
-        EXPECT_TRUE(result == "true" || result == "false")
-            << "Unexpected result " << result;
-        return result == "true";
+      [this](const ExtensionId& extension_id) {
+        absl::optional<bool> result = ExecuteScriptAndReturnBool(
+            extension_id, profile(), "getAndResetRequestIntercepted();");
+        DCHECK(result);
+        return *result;
       };
 
   ASSERT_FALSE(GetAndResetOneGoogleBarRequestSeen());
@@ -2220,7 +2235,7 @@
 
   // The number of requests initiated by a protected origin is tracked in
   // the extension's background page under this variable name.
-  const std::string request_counter_name = "window.protectedOriginCount";
+  const std::string request_counter_name = "self.protectedOriginCount";
 
   EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
                                           request_counter_name));
@@ -2499,19 +2514,19 @@
         "name": "Web Request Stale Headers Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
-        window.locationCount = 0;
-        window.requestCount = 0;
+        self.locationCount = 0;
+        self.requestCount = 0;
         chrome.test.sendMessage('ready', function(reply) {
           chrome.webRequest.onResponseStarted.addListener(function(details) {
-              window.requestCount++;
+              self.requestCount++;
               var headers = details.responseHeaders;
               for (var i = 0; i < headers.length; i++) {
                 if (headers[i].name === 'Location') {
-                  window.locationCount++;
+                  self.locationCount++;
                 }
               }
             },
@@ -2566,10 +2581,9 @@
                     embedded_test_server()->host_port_pair().host(),
                     embedded_test_server()->port(), "redirect-and-wait");
   EXPECT_EQ(
-      GetCountFromBackgroundPage(extension, profile(), "window.requestCount"),
-      1);
+      GetCountFromBackgroundPage(extension, profile(), "self.requestCount"), 1);
   EXPECT_EQ(
-      GetCountFromBackgroundPage(extension, profile(), "window.locationCount"),
+      GetCountFromBackgroundPage(extension, profile(), "self.locationCount"),
       0);
 }
 
@@ -2586,7 +2600,7 @@
         "name": "Web Request UMA Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -2682,7 +2696,7 @@
         "name": "Web Request UMA Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -2764,7 +2778,7 @@
         "name": "Web Request Header Modifying Extension",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
 
@@ -3171,7 +3185,9 @@
       LoadExtension(test_data_dir_.AppendASCII("webrequest")
                         .AppendASCII("initiator_spanning"));
   ASSERT_TRUE(extension);
-  const std::string extension_id = extension->id();
+  // Save the ID because enabling the extension for incognito mode will
+  // invalidate |extension|.
+  const ExtensionId extension_id = extension->id();
   EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
 
   Browser* incognito_browser = CreateIncognitoBrowser(profile());
@@ -3182,21 +3198,26 @@
   GURL url = embedded_test_server()->GetURL("google.com", "/iframe.html");
   const std::string url_origin = url::Origin::Create(url).Serialize();
 
-  const char* kScript = R"(
-    domAutomationController.send(JSON.stringify(window.initiators));
-    window.initiators = [];
+  static constexpr char kScript[] = R"(
+    chrome.test.sendScriptResult(JSON.stringify(self.initiators));
+    self.initiators = [];
   )";
 
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
-  EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()),
-            ExecuteScriptInBackgroundPage(extension_id, kScript));
+  absl::optional<std::string> result =
+      ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()), *result);
 
   // The extension isn't enabled in incognito. Se we shouldn't intercept the
   // request to |url|.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url));
-  EXPECT_EQ("[]", ExecuteScriptInBackgroundPage(extension_id, kScript));
+  result = ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+  ASSERT_TRUE(result);
+  EXPECT_EQ("[]", *result);
 
   // Now enable the extension in incognito.
+  extension = nullptr;
   ready_listener.Reset();
   extensions::util::SetIsIncognitoEnabled(extension_id, profile(),
                                           true /* enabled */);
@@ -3204,8 +3225,9 @@
 
   // Now we should be able to intercept the incognito request.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url));
-  EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()),
-            ExecuteScriptInBackgroundPage(extension_id, kScript));
+  result = ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()), *result);
 }
 
 // Ensure we don't strip off initiator incorrectly in web request events when
@@ -3237,20 +3259,22 @@
   const std::string origin_incognito =
       url::Origin::Create(url_incognito).Serialize();
 
-  const char* kScript = R"(
-    domAutomationController.send(JSON.stringify(window.initiators));
-    window.initiators = [];
+  static constexpr char kScript[] = R"(
+    chrome.test.sendScriptResult(JSON.stringify(self.initiators));
+    self.initiators = [];
   )";
 
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_normal));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url_incognito));
-  EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_normal.c_str()),
-            browsertest_util::ExecuteScriptInBackgroundPage(
-                profile(), extension->id(), kScript));
-  EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_incognito.c_str()),
-            browsertest_util::ExecuteScriptInBackgroundPage(
-                profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true),
-                extension->id(), kScript));
+  absl::optional<std::string> result =
+      ExecuteScriptAndReturnString(extension->id(), profile(), kScript);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_normal.c_str()), *result);
+  result = ExecuteScriptAndReturnString(
+      extension->id(),
+      profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), kScript);
+  ASSERT_TRUE(result);
+  EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_incognito.c_str()), *result);
 }
 
 // A request handler that sets the Access-Control-Allow-Origin header.
@@ -3277,12 +3301,12 @@
         "name": "Web Request HSTS Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
         chrome.webRequest.onBeforeRedirect.addListener(function(details) {
-          window.headerCount = details.responseHeaders.length;
+          self.headerCount = details.responseHeaders.length;
         }, {urls: ['<all_urls>']},
         ['responseHeaders', 'extraHeaders']);
 
@@ -3312,8 +3336,7 @@
                     https_test_server.host_port_pair().host(),
                     https_test_server.port(), "echo");
   EXPECT_GT(
-      GetCountFromBackgroundPage(extension, profile(), "window.headerCount"),
-      0);
+      GetCountFromBackgroundPage(extension, profile(), "self.headerCount"), 0);
 }
 
 // Ensure that when an extension blocks a main-frame request, the resultant
@@ -3351,7 +3374,7 @@
         "name": "Web Request HSTS Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -3526,7 +3549,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest"]
       })");
 
@@ -3535,19 +3558,19 @@
     opt_extra_info_spec += "'extraHeaders'";
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
                      base::StringPrintf(R"(
-        window.numMainResourceRequests = 0;
-        window.numWebBundleRequests = 0;
-        window.numScriptRequests = 0;
-        window.numUUIDInPackageScriptRequests = 0;
+        self.numMainResourceRequests = 0;
+        self.numWebBundleRequests = 0;
+        self.numScriptRequests = 0;
+        self.numUUIDInPackageScriptRequests = 0;
         chrome.webRequest.onBeforeRequest.addListener(function(details) {
           if (details.url.includes('test.html'))
-            window.numMainResourceRequests++;
+            self.numMainResourceRequests++;
           else if (details.url.includes('web_bundle.wbn'))
-            window.numWebBundleRequests++;
+            self.numWebBundleRequests++;
           else if (details.url.includes('test.js'))
-            window.numScriptRequests++;
+            self.numScriptRequests++;
           else if (details.url === '%s')
-            window.numUUIDInPackageScriptRequests++;
+            self.numUUIDInPackageScriptRequests++;
         }, {urls: ['<all_urls>']}, [%s]);
 
         chrome.test.sendMessage('ready');
@@ -3625,14 +3648,14 @@
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
 
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.numMainResourceRequests"));
+                                          "self.numMainResourceRequests"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.numWebBundleRequests"));
+                                          "self.numWebBundleRequests"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.numScriptRequests"));
-  EXPECT_EQ(
-      1, GetCountFromBackgroundPage(extension, profile(),
-                                    "window.numUUIDInPackageScriptRequests"));
+                                          "self.numScriptRequests"));
+  EXPECT_EQ(1,
+            GetCountFromBackgroundPage(extension, profile(),
+                                       "self.numUUIDInPackageScriptRequests"));
 }
 
 // Ensure web request API can block the requests for the subresources inside the
@@ -3645,7 +3668,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   std::string pass_uuid_in_package_js_url =
@@ -3657,22 +3680,22 @@
     opt_extra_info_spec += ", 'extraHeaders'";
   test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
                      base::StringPrintf(R"(
-        window.numPassScriptRequests = 0;
-        window.numCancelScriptRequests = 0;
-        window.numUUIDInPackagePassScriptRequests = 0;
-        window.numUUIDInPackageCancelScriptRequests = 0;
+        self.numPassScriptRequests = 0;
+        self.numCancelScriptRequests = 0;
+        self.numUUIDInPackagePassScriptRequests = 0;
+        self.numUUIDInPackageCancelScriptRequests = 0;
         chrome.webRequest.onBeforeRequest.addListener(function(details) {
           if (details.url.includes('pass.js')) {
-            window.numPassScriptRequests++;
+            self.numPassScriptRequests++;
             return {cancel: false};
           } else if (details.url.includes('cancel.js')) {
-            window.numCancelScriptRequests++;
+            self.numCancelScriptRequests++;
             return {cancel: true};
           } else if (details.url === '%s') {
-            window.numUUIDInPackagePassScriptRequests++;
+            self.numUUIDInPackagePassScriptRequests++;
             return {cancel: false};
           } else if (details.url === '%s') {
-            window.numUUIDInPackageCancelScriptRequests++;
+            self.numUUIDInPackageCancelScriptRequests++;
             return {cancel: true};
           }
         }, {urls: ['<all_urls>']}, [%s]);
@@ -3770,15 +3793,15 @@
   EXPECT_FALSE(TryLoadScript(cancel_uuid_in_package_js_url));
 
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.numPassScriptRequests"));
+                                          "self.numPassScriptRequests"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "window.numCancelScriptRequests"));
+                                          "self.numCancelScriptRequests"));
+  EXPECT_EQ(
+      1, GetCountFromBackgroundPage(extension, profile(),
+                                    "self.numUUIDInPackagePassScriptRequests"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(
                    extension, profile(),
-                   "window.numUUIDInPackagePassScriptRequests"));
-  EXPECT_EQ(1, GetCountFromBackgroundPage(
-                   extension, profile(),
-                   "window.numUUIDInPackageCancelScriptRequests"));
+                   "self.numUUIDInPackageCancelScriptRequests"));
 }
 
 // Ensure web request API can change the headers of the subresources inside the
@@ -3791,7 +3814,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   std::string opt_extra_info_spec = "'blocking', 'responseHeaders'";
@@ -3893,7 +3916,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   std::string opt_extra_info_spec = "'blocking', 'responseHeaders'";
@@ -3988,7 +4011,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   std::string opt_extra_info_spec = "'blocking'";
@@ -4129,7 +4152,7 @@
         "name": "Web Request Subresource Web Bundles Test",
         "manifest_version": 2,
         "version": "0.1",
-        "background": { "scripts": ["background.js"] },
+        "background": { "scripts": ["background.js"], "persistent": true },
         "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
       })");
   std::string opt_extra_info_spec = "'blocking'";
@@ -4207,7 +4230,7 @@
           "name": "Simple Redirect",
           "manifest_version": 2,
           "version": "0.1",
-          "background": { "scripts": ["background.js"] },
+          "background": { "scripts": ["background.js"], "persistent": true },
           "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
         })");
     test_dir.WriteFile(
@@ -4606,7 +4629,7 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
   ExtensionTestMessageListener preflight_listener("cors-preflight-succeeded");
-  const char kCORSPreflightedRequest[] = R"(
+  static constexpr char kCORSPreflightedRequest[] = R"(
       var xhr = new XMLHttpRequest();
       xhr.open('GET', '%s');
       xhr.setRequestHeader('%s', 'testvalue');
@@ -4621,15 +4644,16 @@
       &success));
   EXPECT_TRUE(success);
   EXPECT_TRUE(preflight_listener.WaitUntilSatisfied());
-  EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "preflightHeadersReceivedCount"));
-  EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "preflightProxyAuthRequiredCount"));
-  EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
-                                          "preflightResponseStartedCount"));
+  EXPECT_EQ(1, GetCountFromBackgroundPage(
+                   extension, profile(), "self.preflightHeadersReceivedCount"));
+  EXPECT_EQ(1,
+            GetCountFromBackgroundPage(extension, profile(),
+                                       "self.preflightProxyAuthRequiredCount"));
+  EXPECT_EQ(1, GetCountFromBackgroundPage(
+                   extension, profile(), "self.preflightResponseStartedCount"));
   EXPECT_EQ(1, GetCountFromBackgroundPage(
                    extension, profile(),
-                   "preflightResponseStartedSuccessfullyCount"));
+                   "self.preflightResponseStartedSuccessfullyCount"));
 }
 
 class ExtensionWebRequestApiFencedFrameTest
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc
index edbe013..1d2406f 100644
--- a/chrome/browser/extensions/browsertest_util.cc
+++ b/chrome/browser/extensions/browsertest_util.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
@@ -52,6 +53,10 @@
 }
 
 Browser* LaunchAppBrowser(Profile* profile, const Extension* extension_app) {
+  ui_test_utils::BrowserChangeObserver browser_change_observer(
+      /*browser=*/nullptr,
+      ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+
   EXPECT_TRUE(apps::AppServiceProxyFactory::GetForProfile(profile)
                   ->BrowserAppLauncher()
                   ->LaunchAppWithParamsForTesting(apps::AppLaunchParams(
@@ -60,13 +65,12 @@
                       WindowOpenDisposition::CURRENT_TAB,
                       apps::mojom::LaunchSource::kFromTest)));
 
-  Browser* browser = chrome::FindLastActive();
-  bool is_correct_app_browser =
-      browser && web_app::GetAppIdFromApplicationName(browser->app_name()) ==
-                     extension_app->id();
-  EXPECT_TRUE(is_correct_app_browser);
-
-  return is_correct_app_browser ? browser : nullptr;
+  Browser* const browser = browser_change_observer.Wait();
+  DCHECK(browser);
+  ui_test_utils::BrowserActivationWaiter(browser).WaitForActivation();
+  EXPECT_EQ(web_app::GetAppIdFromApplicationName(browser->app_name()),
+            extension_app->id());
+  return browser;
 }
 
 content::WebContents* AddTab(Browser* browser, const GURL& url) {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java
index 9728b24..74b694f 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java
@@ -39,7 +39,6 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
-import org.chromium.chrome.browser.feed.test.R;
 import org.chromium.chrome.browser.feed.webfeed.WebFeedSnackbarController.FeedLauncher;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -55,6 +54,7 @@
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.components.user_prefs.UserPrefsJni;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -119,9 +119,8 @@
         Profile.setLastUsedProfileForTesting(mProfile);
         Mockito.when(mUserPrefsJniMock.get(mProfile)).thenReturn(mPrefService);
 
-        mActivity = Robolectric.setupActivity(Activity.class);
         // Required for resolving an attribute used in AppMenuItemText.
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
         mClock = new FakeClock();
         when(mTracker.shouldTriggerHelpUI(FeatureConstants.IPH_WEB_FEED_FOLLOW_FEATURE))
                 .thenReturn(true);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItemTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItemTest.java
index 9308f8e..e518291 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItemTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItemTest.java
@@ -49,6 +49,7 @@
 import org.chromium.components.embedder_support.util.ShadowUrlUtilities;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.components.url_formatter.UrlFormatterJni;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.widget.LoadingView;
 import org.chromium.url.GURL;
@@ -108,9 +109,8 @@
         doReturn(GURL.emptyGURL()).when(mTab).getOriginalUrl();
         doReturn(false).when(mTab).isShowingErrorPage();
 
-        mActivity = Robolectric.setupActivity(Activity.class);
         // Required for resolving an attribute used in AppMenuItemText.
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.setupActivity(TestActivity.class);
 
         // Add requests for web feed information to mWaitingMetadataCallbacks.
         doAnswer(invocation -> {
diff --git a/chrome/browser/flags/BUILD.gn b/chrome/browser/flags/BUILD.gn
index b25ea07..ab2b46e0 100644
--- a/chrome/browser/flags/BUILD.gn
+++ b/chrome/browser/flags/BUILD.gn
@@ -10,11 +10,13 @@
     "android/java/src/org/chromium/chrome/browser/flags/BooleanCachedFieldTrialParameter.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameter.java",
+    "android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFlagsSafeMode.java",
     "android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java",
     "android/java/src/org/chromium/chrome/browser/flags/ChromeSessionState.java",
     "android/java/src/org/chromium/chrome/browser/flags/DoubleCachedFieldTrialParameter.java",
     "android/java/src/org/chromium/chrome/browser/flags/FeatureParamUtils.java",
+    "android/java/src/org/chromium/chrome/browser/flags/Flag.java",
     "android/java/src/org/chromium/chrome/browser/flags/IntCachedFieldTrialParameter.java",
     "android/java/src/org/chromium/chrome/browser/flags/StringCachedFieldTrialParameter.java",
     "android/java/src/org/chromium/chrome/browser/flags/ValuesOverridden.java",
@@ -72,10 +74,12 @@
 
 robolectric_library("flags_junit_tests") {
   sources = [
+    "android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsAnnotationUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsSafeModeUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameterUnitTest.java",
+    "android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListWithProcessorUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListWithoutProcessorUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/flags/FeatureParamUtilsUnitTest.java",
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java
new file mode 100644
index 0000000..a9d9dd5
--- /dev/null
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/BaseFlagTestRule.java
@@ -0,0 +1,74 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.flags;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import org.chromium.base.FeatureList;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test rule for testing subclasses of {@link Flag}.
+ */
+public class BaseFlagTestRule implements TestRule {
+    @Override
+    public Statement apply(final Statement base, final Description desc) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    base.evaluate();
+                } finally {
+                    tearDown();
+                }
+            }
+        };
+    }
+
+    private void tearDown() {
+        FeatureList.setTestFeatures(null);
+        Flag.resetFlagsForTesting();
+        CachedFeatureFlags.resetFlagsForTesting();
+    }
+
+    static final String FEATURE_A = "FeatureA";
+    static final String FEATURE_B = "FeatureB";
+
+    static final Map<String, Boolean> A_OFF_B_ON = new HashMap<String, Boolean>() {
+        {
+            put(FEATURE_A, false);
+            put(FEATURE_B, true);
+        }
+    };
+    static final Map<String, Boolean> A_OFF_B_OFF = new HashMap<String, Boolean>() {
+        {
+            put(FEATURE_A, false);
+            put(FEATURE_B, false);
+        }
+    };
+    static final Map<String, Boolean> A_ON_B_OFF = new HashMap<String, Boolean>() {
+        {
+            put(FEATURE_A, true);
+            put(FEATURE_B, false);
+        }
+    };
+    static final Map<String, Boolean> A_ON_B_ON = new HashMap<String, Boolean>() {
+        {
+            put(FEATURE_A, true);
+            put(FEATURE_B, true);
+        }
+    };
+
+    static void assertIsEnabledMatches(Map<String, Boolean> state, Flag feature1, Flag feature2) {
+        assertEquals(state.get(FEATURE_A), feature1.isEnabled());
+        assertEquals(state.get(FEATURE_B), feature2.isEnabled());
+    }
+}
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index 25f9e39..3fbd637 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -139,6 +139,20 @@
      *
      * Requires that the feature be registered in {@link #sDefaults}.
      *
+     * @param featureName the feature name from ChromeFeatureList.
+     * @return whether the cached feature should be considered enabled.
+     */
+    @CalledByNative
+    public static boolean isEnabled(String featureName) {
+        // All cached feature flags should have a default value.
+        if (!sDefaults.containsKey(featureName)) {
+            throw new IllegalArgumentException(
+                    "Feature " + featureName + " has no default in CachedFeatureFlags.");
+        }
+        return isEnabled(featureName, sDefaults.get(featureName));
+    }
+
+    /**
      * Rules from highest to lowest priority:
      * 1. If the flag has been forced by {@link #setForTesting}, the forced value is returned.
      * 2. If a value was previously returned in the same run, the same value is returned for
@@ -146,20 +160,10 @@
      * 3. If native is loaded, the value from {@link ChromeFeatureList} is returned.
      * 4. If in a previous run, the value from {@link ChromeFeatureList} was cached to SharedPrefs,
      *    it is returned.
-     * 5. The default value defined in {@link #sDefaults} is returned.
-     *
-     * @param featureName the feature name from ChromeFeatureList.
-     * @return whether the cached feature should be considered enabled.
+     * 5. The default value passed as a parameter is returned.
      */
-    @CalledByNative
     @AnyThread
-    public static boolean isEnabled(String featureName) {
-        // All cached feature flags should have a default value.
-        if (!sDefaults.containsKey(featureName)) {
-            throw new IllegalArgumentException(
-                    "Feature " + featureName + " has no default in CachedFeatureFlags.");
-        }
-
+    static boolean isEnabled(String featureName, boolean defaultValue) {
         sSafeMode.onFlagChecked();
 
         String preferenceName = getPrefForFeatureFlag(featureName);
@@ -177,7 +181,7 @@
                 if (prefs.contains(preferenceName)) {
                     flag = prefs.readBoolean(preferenceName, false);
                 } else {
-                    flag = sDefaults.get(featureName);
+                    flag = defaultValue;
                 }
             }
 
@@ -191,7 +195,7 @@
      *
      * @param featureName the feature name from ChromeFeatureList.
      */
-    private static void cacheFeature(String featureName) {
+    static void cacheFeature(String featureName) {
         String preferenceName = getPrefForFeatureFlag(featureName);
         boolean isEnabledInNative = ChromeFeatureList.isEnabled(featureName);
         SharedPreferencesManager.getInstance().writeBoolean(preferenceName, isEnabledInNative);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsUnitTest.java
index 5f2d2e94..9b9657c 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsUnitTest.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlagsUnitTest.java
@@ -5,186 +5,21 @@
 package org.chromium.chrome.browser.flags;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import org.junit.After;
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.FeatureList;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Unit Tests for {@link CachedFeatureFlags}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
 public class CachedFeatureFlagsUnitTest {
-    @Before
-    public void setUp() {
-        CachedFeatureFlags.resetFlagsForTesting();
-    }
-
-    @After
-    public void tearDown() {
-        CachedFeatureFlags.resetFlagsForTesting();
-        FeatureList.setTestFeatures(null);
-    }
-
-    public static final String FEATURE_A = "FeatureA";
-    public static final String FEATURE_B = "FeatureB";
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testNativeInitializedNoDefault_throwsException() {
-        // Setup FeatureA in ChromeFeatureList but not in the defaults.
-        Map<String, Boolean> testFeatures = Collections.singletonMap(FEATURE_A, false);
-        FeatureList.setTestFeatures(testFeatures);
-
-        // Assert {@link CachedFeatureFlags} throws an exception.
-        CachedFeatureFlags.cacheNativeFlags(Collections.singletonList(FEATURE_A));
-        assertFalse(CachedFeatureFlags.isEnabled(FEATURE_A));
-    }
-
-    private static final Map<String, Boolean> A_OFF_B_ON = new HashMap<String, Boolean>() {
-        {
-            put(FEATURE_A, false);
-            put(FEATURE_B, true);
-        }
-    };
-    private static final Map<String, Boolean> A_OFF_B_OFF = new HashMap<String, Boolean>() {
-        {
-            put(FEATURE_A, false);
-            put(FEATURE_B, false);
-        }
-    };
-    private static final Map<String, Boolean> A_ON_B_OFF = new HashMap<String, Boolean>() {
-        {
-            put(FEATURE_A, true);
-            put(FEATURE_B, false);
-        }
-    };
-    private static final Map<String, Boolean> A_ON_B_ON = new HashMap<String, Boolean>() {
-        {
-            put(FEATURE_A, true);
-            put(FEATURE_B, true);
-        }
-    };
-    private static final List<String> FEATURES_A_AND_B = Arrays.asList(FEATURE_A, FEATURE_B);
-
-    private static void assertIsEnabledMatches(Map<String, Boolean> state) {
-        assertEquals(state.get(FEATURE_A), CachedFeatureFlags.isEnabled(FEATURE_A));
-        assertEquals(state.get(FEATURE_B), CachedFeatureFlags.isEnabled(FEATURE_B));
-    }
-
-    @Test
-    public void testNativeInitialized_getsFromChromeFeatureList() {
-        Map<String, Boolean> previousDefaults =
-                CachedFeatureFlags.swapDefaultsForTesting(A_OFF_B_OFF);
-
-        try {
-            // Cache native flags, meaning values from ChromeFeatureList should be used from now on.
-            FeatureList.setTestFeatures(A_OFF_B_ON);
-            CachedFeatureFlags.cacheNativeFlags(FEATURES_A_AND_B);
-
-            // Assert {@link CachedFeatureFlags} uses the values from {@link ChromeFeatureList}.
-            assertIsEnabledMatches(A_OFF_B_ON);
-        } finally {
-            CachedFeatureFlags.swapDefaultsForTesting(previousDefaults);
-        }
-    }
-
-    @Test
-    public void testNativeNotInitializedNotCached_useDefault() {
-        Map<String, Boolean> previousDefaults =
-                CachedFeatureFlags.swapDefaultsForTesting(A_OFF_B_OFF);
-
-        try {
-            // Do not cache values from native. There are no values stored in prefs either.
-            FeatureList.setTestFeatures(A_OFF_B_ON);
-
-            // Query the flags to make sure the default values are returned.
-            assertIsEnabledMatches(A_OFF_B_OFF);
-
-            // Now do cache the values from ChromeFeatureList.
-            CachedFeatureFlags.cacheNativeFlags(FEATURES_A_AND_B);
-
-            // Verify that {@link CachedFeatureFlags} returns consistent values in the same run.
-            assertIsEnabledMatches(A_OFF_B_OFF);
-        } finally {
-            CachedFeatureFlags.swapDefaultsForTesting(previousDefaults);
-        }
-    }
-
-    @Test
-    public void testNativeNotInitializedPrefsCached_getsFromPrefs() {
-        Map<String, Boolean> previousDefaults =
-                CachedFeatureFlags.swapDefaultsForTesting(A_OFF_B_OFF);
-
-        try {
-            // Cache native flags, meaning values from ChromeFeatureList should be used from now on.
-            FeatureList.setTestFeatures(A_OFF_B_ON);
-            CachedFeatureFlags.cacheNativeFlags(FEATURES_A_AND_B);
-            assertIsEnabledMatches(A_OFF_B_ON);
-
-            // Pretend the app was restarted. The SharedPrefs should remain.
-            CachedFeatureFlags.resetFlagsForTesting();
-
-            // Simulate ChromeFeatureList retrieving new, different values for the flags.
-            FeatureList.setTestFeatures(A_ON_B_ON);
-
-            // Do not cache new values, but query the flags to make sure the values stored to prefs
-            // are returned. Neither the defaults (false/false) or the ChromeFeatureList values
-            // (true/true) should be returned.
-            assertIsEnabledMatches(A_OFF_B_ON);
-
-            // Now do cache the values from ChromeFeatureList.
-            CachedFeatureFlags.cacheNativeFlags(FEATURES_A_AND_B);
-
-            // Verify that {@link CachedFeatureFlags} returns consistent values in the same run.
-            assertIsEnabledMatches(A_OFF_B_ON);
-
-            // Pretend the app was restarted again.
-            CachedFeatureFlags.resetFlagsForTesting();
-
-            // The SharedPrefs should retain the latest values.
-            assertIsEnabledMatches(A_ON_B_ON);
-        } finally {
-            CachedFeatureFlags.swapDefaultsForTesting(previousDefaults);
-        }
-    }
-
-    @Test
-    public void testSetForTesting_returnsForcedValue() {
-        Map<String, Boolean> previousDefaults =
-                CachedFeatureFlags.swapDefaultsForTesting(A_OFF_B_OFF);
-
-        try {
-            // Do not cache values from native. There are no values stored in prefs either.
-            // Query the flags to make sure the default values are returned.
-            assertIsEnabledMatches(A_OFF_B_OFF);
-
-            // Force a feature flag.
-            CachedFeatureFlags.setForTesting(FEATURE_A, true);
-
-            // Verify that the forced value is returned.
-            assertIsEnabledMatches(A_ON_B_OFF);
-
-            // Remove the forcing.
-            CachedFeatureFlags.setForTesting(FEATURE_A, null);
-
-            // Verify that the forced value is not returned anymore.
-            assertIsEnabledMatches(A_OFF_B_OFF);
-        } finally {
-            CachedFeatureFlags.swapDefaultsForTesting(previousDefaults);
-        }
-    }
+    @Rule
+    public final BaseFlagTestRule baseFlagTestRule = new BaseFlagTestRule();
 
     @Test
     public void testGetLastCachedMinimalBrowserFlagsTimeMillis() {
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java
new file mode 100644
index 0000000..53f1dc5
--- /dev/null
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlag.java
@@ -0,0 +1,36 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.flags;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Flags of this type may be used before native is loaded and return the value read
+ * from native and cached to SharedPreferences in a previous run.
+ * @see {@link CachedFeatureFlags#isEnabled(String, boolean)}
+ */
+public class CachedFlag extends Flag {
+    private final boolean mDefaultValue;
+
+    public CachedFlag(String name, boolean defaultValue) {
+        super(name);
+        mDefaultValue = defaultValue;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return CachedFeatureFlags.isEnabled(mFeatureName, mDefaultValue);
+    }
+
+    @VisibleForTesting
+    public void setForTesting(String name, @Nullable Boolean value) {
+        CachedFeatureFlags.setForTesting(name, value);
+    }
+
+    public void cacheFeature() {
+        CachedFeatureFlags.cacheFeature(mFeatureName);
+    }
+}
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java
new file mode 100644
index 0000000..44e6fe7
--- /dev/null
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFlagUnitTest.java
@@ -0,0 +1,126 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.flags;
+
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.A_OFF_B_OFF;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.A_OFF_B_ON;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.A_ON_B_OFF;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.A_ON_B_ON;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.FEATURE_A;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.FEATURE_B;
+import static org.chromium.chrome.browser.flags.BaseFlagTestRule.assertIsEnabledMatches;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.FeatureList;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+/**
+ * Unit Tests for {@link CachedFlag}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+public class CachedFlagUnitTest {
+    @Rule
+    public final BaseFlagTestRule baseFlagTestRule = new BaseFlagTestRule();
+
+    @Test(expected = AssertionError.class)
+    public void testDuplicateFeature_throwsException() {
+        new CachedFlag(FEATURE_A, true);
+        new CachedFlag(FEATURE_A, true);
+    }
+
+    @Test
+    public void testNativeInitialized_getsFromChromeFeatureList() {
+        CachedFlag featureA = new CachedFlag(FEATURE_A, false);
+        CachedFlag featureB = new CachedFlag(FEATURE_B, false);
+
+        // Cache native flags, meaning values from ChromeFeatureList should be used from now on.
+        FeatureList.setTestFeatures(A_OFF_B_ON);
+        featureA.cacheFeature();
+        featureB.cacheFeature();
+
+        // Assert {@link CachedFeatureFlags} uses the values from {@link ChromeFeatureList}.
+        assertIsEnabledMatches(A_OFF_B_ON, featureA, featureB);
+    }
+
+    @Test
+    public void testNativeNotInitializedNotCached_useDefault() {
+        CachedFlag featureA = new CachedFlag(FEATURE_A, true);
+        CachedFlag featureB = new CachedFlag(FEATURE_B, false);
+
+        // Do not cache values from native. There are no values stored in prefs either.
+        FeatureList.setTestFeatures(A_OFF_B_ON);
+
+        // Query the flags to make sure the default values are returned.
+        assertIsEnabledMatches(A_ON_B_OFF, featureA, featureB);
+
+        // Now do cache the values from ChromeFeatureList.
+        featureA.cacheFeature();
+        featureB.cacheFeature();
+
+        // Verify that {@link CachedFlag} returns consistent values in the same run.
+        assertIsEnabledMatches(A_ON_B_OFF, featureA, featureB);
+    }
+
+    @Test
+    public void testNativeNotInitializedPrefsCached_getsFromPrefs() {
+        CachedFlag featureA = new CachedFlag(FEATURE_A, false);
+        CachedFlag featureB = new CachedFlag(FEATURE_B, false);
+
+        // Cache native flags, meaning values from ChromeFeatureList should be used from now on.
+        FeatureList.setTestFeatures(A_OFF_B_ON);
+        featureA.cacheFeature();
+        featureB.cacheFeature();
+        assertIsEnabledMatches(A_OFF_B_ON, featureA, featureB);
+
+        // Pretend the app was restarted. The SharedPrefs should remain.
+        CachedFeatureFlags.resetFlagsForTesting();
+
+        // Simulate ChromeFeatureList retrieving new, different values for the flags.
+        FeatureList.setTestFeatures(A_ON_B_ON);
+
+        // Do not cache new values, but query the flags to make sure the values stored to prefs
+        // are returned. Neither the defaults (false/false) or the ChromeFeatureList values
+        // (true/true) should be returned.
+        assertIsEnabledMatches(A_OFF_B_ON, featureA, featureB);
+
+        // Now do cache the values from ChromeFeatureList.
+        featureA.cacheFeature();
+        featureB.cacheFeature();
+
+        // Verify that {@link CachedFlag} returns consistent values in the same run.
+        assertIsEnabledMatches(A_OFF_B_ON, featureA, featureB);
+
+        // Pretend the app was restarted again.
+        CachedFeatureFlags.resetFlagsForTesting();
+
+        // The SharedPrefs should retain the latest values.
+        assertIsEnabledMatches(A_ON_B_ON, featureA, featureB);
+    }
+
+    @Test
+    public void testSetForTesting_returnsForcedValue() {
+        CachedFlag featureA = new CachedFlag(FEATURE_A, false);
+        CachedFlag featureB = new CachedFlag(FEATURE_B, false);
+
+        // Do not cache values from native. There are no values stored in prefs either.
+        // Query the flags to make sure the default values are returned.
+        assertIsEnabledMatches(A_OFF_B_OFF, featureA, featureB);
+
+        // Force a feature flag.
+        featureA.setForTesting(FEATURE_A, true);
+
+        // Verify that the forced value is returned.
+        assertIsEnabledMatches(A_ON_B_OFF, featureA, featureB);
+
+        // Remove the forcing.
+        featureA.setForTesting(FEATURE_A, null);
+
+        // Verify that the forced value is not returned anymore.
+        assertIsEnabledMatches(A_OFF_B_OFF, featureA, featureB);
+    }
+}
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 8531f10b..e603b96 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -59,7 +59,7 @@
         return FeatureList.isInitialized();
     }
 
-    /*
+    /**
      * Returns whether the specified feature is enabled or not in native.
      *
      * @param featureName The name of the feature to query.
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/Flag.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/Flag.java
new file mode 100644
index 0000000..01f48958e
--- /dev/null
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/Flag.java
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.flags;
+
+import java.util.HashSet;
+
+/**
+ * Defines a feature flag for use in Java.
+ *
+ * Duplicate flag definitions are not permitted, so only a single
+ * instance can be created with a given feature name
+ */
+public abstract class Flag {
+    private static HashSet<String> sFlagsCreated = new HashSet<>();
+    protected final String mFeatureName;
+
+    Flag(String name) {
+        assert !sFlagsCreated.contains(name);
+        mFeatureName = name;
+        sFlagsCreated.add(mFeatureName);
+    }
+
+    /**
+     * Checks if a feature flag is enabled.
+     * @return whether the feature should be considered enabled.
+     */
+    public abstract boolean isEnabled();
+
+    static void resetFlagsForTesting() {
+        sFlagsCreated.clear();
+    }
+}
diff --git a/chrome/browser/lifetime/application_lifetime_chromeos.cc b/chrome/browser/lifetime/application_lifetime_chromeos.cc
index de43d8e..8f420c5 100644
--- a/chrome/browser/lifetime/application_lifetime_chromeos.cc
+++ b/chrome/browser/lifetime/application_lifetime_chromeos.cc
@@ -13,9 +13,8 @@
 namespace {
 
 chromeos::UpdateEngineClient* GetUpdateEngineClient() {
-  DCHECK(ash::DBusThreadManager::IsInitialized());
   chromeos::UpdateEngineClient* update_engine_client =
-      chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
+      chromeos::UpdateEngineClient::Get();
   DCHECK(update_engine_client);
   return update_engine_client;
 }
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index 26552b66..4944eb8 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -82,7 +82,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"  // nogncheck
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"  // nogncheck
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 using content::BrowserThread;
@@ -1068,11 +1068,9 @@
 // LaCROS due to errors on Wayland initialization and to keep test to ChromeOS
 // devices.
 // TODO(crbug.com/1285441): Disabled due to test flakes.
-class ErrorPageOfflineAppLaunchTest
-    : public web_app::SystemWebAppBrowserTestBase {
+class ErrorPageOfflineAppLaunchTest : public ash::SystemWebAppBrowserTestBase {
  public:
-  ErrorPageOfflineAppLaunchTest()
-      : web_app::SystemWebAppBrowserTestBase(true) {}
+  ErrorPageOfflineAppLaunchTest() : ash::SystemWebAppBrowserTestBase(true) {}
 };
 
 IN_PROC_BROWSER_TEST_F(ErrorPageOfflineAppLaunchTest,
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 0d488b2..35817700 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/sessions/restore_on_startup_policy_handler.h"
 #include "chrome/browser/spellchecker/spellcheck_language_blocklist_policy_handler.h"
 #include "chrome/browser/spellchecker/spellcheck_language_policy_handler.h"
-#include "chrome/browser/ssl/https_only_mode_policy_handler.h"
 #include "chrome/browser/ssl/secure_origin_policy_handler.h"
 #include "chrome/browser/themes/theme_color_policy_handler.h"
 #include "chrome/browser/ui/toolbar/chrome_labs_prefs.h"
@@ -96,6 +95,7 @@
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/search_engines/default_search_policy_handler.h"
 #include "components/search_engines/search_engines_pref_names.h"
+#include "components/security_interstitials/core/https_only_mode_policy_handler.h"
 #include "components/security_interstitials/core/pref_names.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
@@ -1948,7 +1948,8 @@
 
   handlers->AddHandler(
       std::make_unique<ExplicitlyAllowedNetworkPortsPolicyHandler>());
-  handlers->AddHandler(std::make_unique<HttpsOnlyModePolicyHandler>());
+  handlers->AddHandler(std::make_unique<HttpsOnlyModePolicyHandler>(
+      prefs::kHttpsOnlyModeEnabled));
 
   handlers->AddHandler(std::make_unique<BrowsingDataLifetimePolicyHandler>(
       key::kBrowsingDataLifetime, browsing_data::prefs::kBrowsingDataLifetime,
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
index 6543e497..647e96c 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -44,6 +44,10 @@
     ChromeCommandLinePrefStore::string_switch_map_[] = {
         {switches::kLang, language::prefs::kApplicationLocale},
         {switches::kAcceptLang, language::prefs::kSelectedLanguages},
+        // `switches::kAuthServerAllowlistDeprecated` must be before
+        // `switches::kAuthServerAllowlist` so that the deprecated value is
+        // overridden in `ChromeCommandLinePrefStore::ApplyStringSwitches`.
+        {switches::kAuthServerAllowlistDeprecated, prefs::kAuthServerAllowlist},
         {switches::kAuthServerAllowlist, prefs::kAuthServerAllowlist},
         {switches::kSSLVersionMin, prefs::kSSLVersionMin},
         {switches::kSSLVersionMax, prefs::kSSLVersionMax},
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 442fad5..a1be55d 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -52,6 +52,7 @@
 #include "chrome/common/chrome_render_frame.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/search_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/guest_view/browser/guest_view_manager_delegate.h"
@@ -66,6 +67,7 @@
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_plugin_guest_manager.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/context_menu_params.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
@@ -1066,39 +1068,38 @@
   ASSERT_EQ(kEmptyReferrer, page_referrer);
 }
 
-// Verify that "Open link in [App Name]" opens a new App window.
-// TODO(crbug.com/1180790): Test is flaky on Linux and Windows.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
-#define MAYBE_OpenLinkInWebApp DISABLED_OpenLinkInWebApp
-#else
-#define MAYBE_OpenLinkInWebApp OpenLinkInWebApp
-#endif
-IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, MAYBE_OpenLinkInWebApp) {
-  InstallTestWebApp(GURL(kAppUrl1));
+IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenLinkInWebApp) {
+  const GURL start_url(kAppUrl1);
+  InstallTestWebApp(start_url);
 
   ASSERT_TRUE(embedded_test_server()->Start());
 
   size_t num_browsers = chrome::GetBrowserCount(browser()->profile());
-  int num_tabs = browser()->tab_strip_model()->count();
+  const int num_tabs = browser()->tab_strip_model()->count();
   content::WebContents* initial_tab =
       browser()->tab_strip_model()->GetActiveWebContents();
   const GURL initial_url = initial_tab->GetLastCommittedURL();
+  ui_test_utils::BrowserChangeObserver browser_change_observer(
+      /*browser=*/nullptr,
+      ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
 
-  const GURL start_url(kAppUrl1);
-  ui_test_utils::UrlLoadObserver url_observer(
-      start_url, content::NotificationService::AllSources());
-  content::ContextMenuParams params;
-  params.page_url = GURL("https://www.example.com/");
-  params.link_url = start_url;
-  TestRenderViewContextMenu menu(*initial_tab->GetPrimaryMainFrame(), params);
-  menu.Init();
-  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP,
-                      0 /* event_flags */);
-  url_observer.Wait();
+  {
+    ui_test_utils::UrlLoadObserver url_observer(
+        start_url, content::NotificationService::AllSources());
+    content::ContextMenuParams params;
+    params.page_url = GURL("https://www.example.com/");
+    params.link_url = start_url;
+    TestRenderViewContextMenu menu(*initial_tab->GetPrimaryMainFrame(), params);
+    menu.Init();
+    menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP,
+                        0 /* event_flags */);
+    url_observer.Wait();
+  }
 
+  Browser* const app_browser = browser_change_observer.Wait();
+  ui_test_utils::BrowserActivationWaiter(app_browser).WaitForActivation();
   EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count());
   EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(browser()->profile()));
-  Browser* app_browser = chrome::FindLastActive();
   EXPECT_NE(browser(), app_browser);
   EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL());
   EXPECT_EQ(start_url, app_browser->tab_strip_model()
diff --git a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
index f09791d..c736ecf 100644
--- a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
+++ b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
@@ -13,6 +13,7 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
@@ -21,7 +22,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -436,7 +436,7 @@
 }
 
 class SystemWebAppSessionRestoreTestChromeOS
-    : public web_app::SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppSessionRestoreTestChromeOS()
       : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f48bb6be..588cea7 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -436,9 +436,6 @@
     "//chrome/browser/ui/webui/omnibox:mojo_bindings",
     "//chrome/browser/ui/webui/realbox:mojo_bindings",
     "//chrome/browser/ui/webui/segmentation_internals:mojo_bindings",
-    "//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings",
-    "//chrome/browser/ui/webui/side_panel/read_anything:mojo_bindings",
-    "//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings",
     "//chrome/browser/ui/webui/tab_search:mojo_bindings",
     "//chrome/browser/ui/webui/usb_internals:mojo_bindings",
     "//chrome/browser/video_tutorials",
@@ -1783,6 +1780,9 @@
       "//chrome/browser/ui/webui/internals/user_education:mojo_bindings",
       "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
       "//chrome/browser/ui/webui/new_tab_page_third_party:mojo_bindings",
+      "//chrome/browser/ui/webui/side_panel/bookmarks:mojo_bindings",
+      "//chrome/browser/ui/webui/side_panel/read_anything:mojo_bindings",
+      "//chrome/browser/ui/webui/side_panel/reading_list:mojo_bindings",
       "//chrome/browser/ui/webui/tab_strip:mojo_bindings",
       "//chrome/browser/web_applications",
       "//chrome/common:buildflags",
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn
index 281d7bf..a0f524e 100644
--- a/chrome/browser/ui/android/omnibox/BUILD.gn
+++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -477,6 +477,7 @@
     "//third_party/junit",
     "//third_party/metrics_proto:metrics_proto_java",
     "//third_party/mockito:mockito_java",
+    "//ui/android:ui_java_test_support",
     "//ui/android:ui_no_recycler_view_java",
     "//ui/android:ui_recycler_view_java",
     "//url:gurl_java",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxResourceProviderTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxResourceProviderTest.java
index 0001363..6ae4d09 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxResourceProviderTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/styles/OmniboxResourceProviderTest.java
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
+import org.chromium.ui.base.TestActivity;
 
 /** Tests for {@link OmniboxResourceProvider}. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -40,9 +41,7 @@
 
     @Before
     public void setUp() {
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
-
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
         mDefaultColor = ChromeColors.getDefaultThemeColor(mActivity, false);
     }
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/FaviconFetcherUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/FaviconFetcherUnitTest.java
index e7a86091..03925cb 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/FaviconFetcherUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/FaviconFetcherUnitTest.java
@@ -35,12 +35,12 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omnibox.suggestions.FaviconFetcher.FaviconFetchCompleteListener;
 import org.chromium.chrome.browser.omnibox.suggestions.FaviconFetcher.FaviconType;
 import org.chromium.components.browser_ui.widget.RoundedIconGenerator;
 import org.chromium.components.favicon.LargeIconBridge;
 import org.chromium.components.favicon.LargeIconBridge.LargeIconCallback;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
 
@@ -75,8 +75,7 @@
         // Enable logs to be printed along with possible test failures.
         ShadowLog.stream = System.out;
 
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
 
         mFetcher = new FaviconFetcher(mActivity, () -> mLargeIconBridge);
         mFetcher.setRoundedIconGeneratorForTesting(mIconGenerator);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinderUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinderUnitTest.java
index b892982..01a9191 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinderUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionViewBinderUnitTest.java
@@ -33,6 +33,7 @@
 import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties;
 import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProperties.Action;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
@@ -65,9 +66,8 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
         // First set the app theme, then apply the feed theme overlay.
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
         mResources = mActivity.getResources();
 
         when(mContentView.getContext()).thenReturn(mActivity);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/header/HeaderViewBinderUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/header/HeaderViewBinderUnitTest.java
index 69c75c7..3fb7aab 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/header/HeaderViewBinderUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/header/HeaderViewBinderUnitTest.java
@@ -30,6 +30,7 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
@@ -50,7 +51,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
         mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
 
         mHeaderView = mock(HeaderView.class,
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesProcessorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesProcessorUnitTest.java
index 1cb8ef5..bb4c6b2 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesProcessorUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/mostvisited/MostVisitedTilesProcessorUnitTest.java
@@ -46,6 +46,7 @@
 import org.chromium.components.omnibox.AutocompleteMatch;
 import org.chromium.components.omnibox.AutocompleteMatch.SuggestTile;
 import org.chromium.components.omnibox.AutocompleteMatchBuilder;
+import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
@@ -83,8 +84,7 @@
     public void setUp() {
         // Enable logs to be printed along with possible test failures.
         ShadowLog.stream = System.out;
-        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
+        mActivity = Robolectric.buildActivity(TestActivity.class).setup().get();
 
         doNothing()
                 .when(mFaviconFetcher)
diff --git a/chrome/browser/ui/android/signin/BUILD.gn b/chrome/browser/ui/android/signin/BUILD.gn
index da1b3c0..b219e6a8 100644
--- a/chrome/browser/ui/android/signin/BUILD.gn
+++ b/chrome/browser/ui/android/signin/BUILD.gn
@@ -171,17 +171,9 @@
 android_library("javatests") {
   testonly = true
   sources = [
-    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmImportSyncDataDialogTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmManagedSyncDataDialogTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmSyncDataIntegrationTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmSyncDataStateMachineDelegateTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/SignOutDialogRenderTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/SignOutDialogTest.java",
     "java/src/org/chromium/chrome/browser/ui/signin/SigninPromoControllerRenderTest.java",
     "java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetRenderTest.java",
     "java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java",
-    "java/src/org/chromium/chrome/browser/ui/signin/fre/FreUMADialogTest.java",
   ]
   deps = [
     ":java",
@@ -190,11 +182,47 @@
     "//chrome/android:chrome_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
-    "//chrome/browser/profiles/android:java",
     "//chrome/browser/signin/services/android:java",
     "//chrome/browser/ui/android/night_mode:night_mode_java_test_support",
     "//chrome/test/android:chrome_java_integration_test_support",
     "//components/browser_ui/bottomsheet/android:java",
+    "//components/signin/core/browser:signin_enums_java",
+    "//components/signin/public/android:java",
+    "//components/signin/public/android:signin_java_test_support",
+    "//content/public/test/android:content_java_test_support",
+    "//third_party/android_deps:espresso_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_test_runner_java",
+    "//third_party/hamcrest:hamcrest_java",
+    "//third_party/junit",
+    "//third_party/mockito:mockito_java",
+    "//ui/android:ui_java_test_support",
+  ]
+}
+
+android_library("unit_device_javatests") {
+  testonly = true
+  sources = [
+    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmImportSyncDataDialogTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmManagedSyncDataDialogTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmSyncDataIntegrationTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/ConfirmSyncDataStateMachineDelegateTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/SignOutDialogRenderTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/SignOutDialogTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerDialogTest.java",
+    "java/src/org/chromium/chrome/browser/ui/signin/fre/FreUMADialogTest.java",
+  ]
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//chrome/browser/flags:java",
+    "//chrome/browser/preferences:java",
+    "//chrome/browser/profiles/android:java",
+    "//chrome/browser/signin/services/android:java",
+    "//chrome/browser/ui/android/night_mode:night_mode_java_test_support",
+    "//chrome/test/android:chrome_java_integration_test_support",
     "//components/browser_ui/modaldialog/android:java",
     "//components/externalauth/android:java",
     "//components/prefs/android:java",
diff --git a/chrome/browser/ui/ash/holding_space/BUILD.gn b/chrome/browser/ui/ash/holding_space/BUILD.gn
index 25a7eb8..0bd7bb2 100644
--- a/chrome/browser/ui/ash/holding_space/BUILD.gn
+++ b/chrome/browser/ui/ash/holding_space/BUILD.gn
@@ -60,10 +60,10 @@
     "//base/test:test_support",
     "//chrome/browser",
     "//chrome/browser/ash",
+    "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
     "//chrome/browser/chromeos:test_support",
     "//chrome/browser/extensions",
     "//chrome/browser/ui",
-    "//chrome/browser/web_applications:browser_tests_base",
     "//chrome/test:test_support_ui",
     "//chromeos/ash/components/dbus/session_manager",
     "//components/session_manager/core",
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc
index 89fca258..9cff470 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.cc
@@ -86,7 +86,7 @@
 // HoldingSpaceBrowserTestBase -------------------------------------------------
 
 HoldingSpaceBrowserTestBase::HoldingSpaceBrowserTestBase()
-    : web_app::SystemWebAppBrowserTestBase(false) {}
+    : SystemWebAppBrowserTestBase(false) {}
 
 HoldingSpaceBrowserTestBase::~HoldingSpaceBrowserTestBase() = default;
 
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h
index 708f9127..c7bf4c7 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_browsertest_base.h
@@ -11,7 +11,7 @@
 #include "ash/public/cpp/holding_space/holding_space_item.h"
 #include "ash/public/cpp/holding_space/holding_space_progress.h"
 #include "base/test/scoped_feature_list.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 
 class Profile;
 
@@ -26,8 +26,7 @@
 // Base class for holding space browser tests. Subclasses
 // SystemWebAppBrowserTestBase for the ability to test with the Media App, which
 // is the default handler for files opened from the holding space.
-class HoldingSpaceBrowserTestBase
-    : public web_app::SystemWebAppBrowserTestBase {
+class HoldingSpaceBrowserTestBase : public SystemWebAppBrowserTestBase {
  public:
   HoldingSpaceBrowserTestBase();
   ~HoldingSpaceBrowserTestBase() override;
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc
index 10ff4052..fb944be 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -61,7 +61,6 @@
 #include "chrome/common/url_constants.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
 #include "chromeos/ash/components/network/onc/network_onc_utils.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
@@ -74,8 +73,6 @@
 #include "ui/events/event_constants.h"
 #include "url/gurl.h"
 
-using chromeos::DBusThreadManager;
-using chromeos::UpdateEngineClient;
 using session_manager::SessionManager;
 using session_manager::SessionState;
 
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 8f7bd9b6..aef444c 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -54,6 +54,7 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
@@ -220,6 +221,7 @@
 
       // Launch app in a window.
       app_browser_ = web_app::LaunchWebAppBrowser(profile(), app_id_);
+      ui_test_utils::BrowserActivationWaiter(app_browser_).WaitForActivation();
     }
 
     ASSERT_FALSE(app_id_.empty());
@@ -373,13 +375,7 @@
 }
 
 // Tests that Ctrl + Clicking a link opens a foreground tab.
-// TODO(crbug.com/1190448): Flaky on Linux.
-#if BUILDFLAG(IS_LINUX)
-#define MAYBE_CtrlClickLink DISABLED_CtrlClickLink
-#else
-#define MAYBE_CtrlClickLink CtrlClickLink
-#endif
-IN_PROC_BROWSER_TEST_P(HostedOrWebAppTest, MAYBE_CtrlClickLink) {
+IN_PROC_BROWSER_TEST_P(HostedOrWebAppTest, CtrlClickLink) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Set up an app which covers app.com URLs.
diff --git a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc
index 0b81699..1266853c 100644
--- a/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc
+++ b/chrome/browser/ui/signin/dice_web_signin_interceptor_delegate.cc
@@ -61,7 +61,7 @@
         bubble_parameters.profile_highlight_color,
         base::BindOnce(&ForcedEnterpriseSigninInterceptionHandle::
                            OnEnterpriseInterceptionDialogClosed,
-                       base::Unretained(this)));
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   ~ForcedEnterpriseSigninInterceptionHandle() override {
@@ -96,6 +96,8 @@
   const bool profile_creation_required_by_policy_;
   const bool show_link_data_option_;
   base::OnceCallback<void(SigninInterceptionResult)> callback_;
+  base::WeakPtrFactory<ForcedEnterpriseSigninInterceptionHandle>
+      weak_ptr_factory_{this};
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/tabs/tab_group_theme.cc b/chrome/browser/ui/tabs/tab_group_theme.cc
index 5ad43a7..a8090e9 100644
--- a/chrome/browser/ui/tabs/tab_group_theme.cc
+++ b/chrome/browser/ui/tabs/tab_group_theme.cc
@@ -21,7 +21,7 @@
            {kColorTabGroupTabStripFrameInactiveGrey,
             kColorTabGroupTabStripFrameActiveGrey}},
           {TabGroupColorId::kBlue,
-           {kColorTabGroupTabStripFrameInactiveGrey,
+           {kColorTabGroupTabStripFrameInactiveBlue,
             kColorTabGroupTabStripFrameActiveBlue}},
           {TabGroupColorId::kRed,
            {kColorTabGroupTabStripFrameInactiveRed,
@@ -36,7 +36,7 @@
            {kColorTabGroupTabStripFrameInactivePink,
             kColorTabGroupTabStripFrameActivePink}},
           {TabGroupColorId::kPurple,
-           {kColorTabGroupTabStripFrameInactivePink,
+           {kColorTabGroupTabStripFrameInactivePurple,
             kColorTabGroupTabStripFrameActivePurple}},
           {TabGroupColorId::kCyan,
            {kColorTabGroupTabStripFrameInactiveCyan,
diff --git a/chrome/browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc
index e92b790d..90578dc 100644
--- a/chrome/browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc
@@ -5,10 +5,10 @@
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test.h"
@@ -18,7 +18,7 @@
 #endif
 
 using SystemWebAppNonClientFrameViewBrowserTest =
-    web_app::SystemWebAppManagerBrowserTest;
+    ash::SystemWebAppManagerBrowserTest;
 
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
 // System Web Apps don't get the web app menu button.
diff --git a/chrome/browser/ui/views/user_education/browser_feature_promo_controller_unittest.cc b/chrome/browser/ui/views/user_education/browser_feature_promo_controller_unittest.cc
index e40c58a8..9f085d4 100644
--- a/chrome/browser/ui/views/user_education/browser_feature_promo_controller_unittest.cc
+++ b/chrome/browser/ui/views/user_education/browser_feature_promo_controller_unittest.cc
@@ -40,6 +40,7 @@
 #include "components/user_education/views/help_bubble_view.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/interaction/element_identifier.h"
 #include "ui/base/interaction/element_tracker.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/base_event_utils.h"
@@ -59,9 +60,12 @@
 namespace {
 base::Feature kTestIPHFeature{"TestIPHFeature",
                               base::FEATURE_ENABLED_BY_DEFAULT};
+base::Feature kOneOffIPHFeature("AnyContextIPHFeature",
+                                base::FEATURE_ENABLED_BY_DEFAULT);
 base::Feature kTutorialIPHFeature{"SecondIPHFeature",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 constexpr char kTestTutorialIdentifier[] = "Test Tutorial";
+DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOneOffIPHElementId);
 }  // namespace
 
 using user_education::FeaturePromoController;
@@ -115,10 +119,9 @@
     user_education_service->tutorial_registry().AddTutorial(
         kTestTutorialIdentifier, std::move(desc));
 
-    user_education_service->feature_promo_registry().RegisterFeature(
-        DefaultBubbleParams());
+    registry()->RegisterFeature(DefaultBubbleParams());
 
-    user_education_service->feature_promo_registry().RegisterFeature(
+    registry()->RegisterFeature(
         FeaturePromoSpecification::CreateForTutorialPromo(
             kTutorialIPHFeature, kAppMenuButtonElementId, IDS_REOPEN_TAB_PROMO,
             kTestTutorialIdentifier));
@@ -236,6 +239,130 @@
   EXPECT_TRUE(GetPromoBubble());
 }
 
+TEST_F(BrowserFeaturePromoControllerTest, ShowsBubbleAnyContext) {
+  registry()->RegisterFeature(std::move(
+      FeaturePromoSpecification::CreateForLegacyPromo(
+          &kOneOffIPHFeature, kOneOffIPHElementId, IDS_REOPEN_TAB_PROMO)
+          .SetInAnyContext(true)));
+
+  EXPECT_CALL(*mock_tracker_, ShouldTriggerHelpUI(Ref(kOneOffIPHFeature)))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  // Create a second widget with an element with the target identifier.
+  auto widget = std::make_unique<views::Widget>();
+  views::Widget::InitParams params(
+      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+  params.bounds = gfx::Rect(0, 0, 200, 200);
+  params.context = browser_view()->GetWidget()->GetNativeWindow();
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget->Init(std::move(params));
+  widget->SetContentsView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+  widget->Show();
+
+  const ui::ElementContext widget_context =
+      views::ElementTrackerViews::GetContextForWidget(widget.get());
+  EXPECT_NE(browser_view()->GetElementContext(), widget_context);
+
+  EXPECT_TRUE(controller_->MaybeShowPromo(kOneOffIPHFeature));
+  EXPECT_TRUE(controller_->IsPromoActive(kOneOffIPHFeature));
+  auto* const bubble = GetPromoBubble();
+  ASSERT_TRUE(bubble);
+  EXPECT_EQ(widget_context,
+            controller_->promo_bubble_for_testing()->GetContext());
+
+  bubble->Close();
+}
+
+TEST_F(BrowserFeaturePromoControllerTest, ShowsBubbleWithFilter) {
+  registry()->RegisterFeature(std::move(
+      FeaturePromoSpecification::CreateForLegacyPromo(
+          &kOneOffIPHFeature, kOneOffIPHElementId, IDS_REOPEN_TAB_PROMO)
+          .SetAnchorElementFilter(base::BindLambdaForTesting(
+              [](const ui::ElementTracker::ElementList& elements) {
+                EXPECT_EQ(2U, elements.size());
+                return elements[0];
+              }))));
+
+  EXPECT_CALL(*mock_tracker_, ShouldTriggerHelpUI(Ref(kOneOffIPHFeature)))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  // Add two random views to the browser with the same element ID.
+  browser_view()
+      ->toolbar()
+      ->AddChildView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+  browser_view()
+      ->toolbar()
+      ->AddChildView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+
+  EXPECT_TRUE(controller_->MaybeShowPromo(kOneOffIPHFeature));
+  EXPECT_TRUE(controller_->IsPromoActive(kOneOffIPHFeature));
+  auto* const bubble = GetPromoBubble();
+  ASSERT_TRUE(bubble);
+  bubble->Close();
+}
+
+TEST_F(BrowserFeaturePromoControllerTest, ShowsBubbleWithFilterAnyContext) {
+  ui::ElementContext widget_context;
+  registry()->RegisterFeature(std::move(
+      FeaturePromoSpecification::CreateForLegacyPromo(
+          &kOneOffIPHFeature, kOneOffIPHElementId, IDS_REOPEN_TAB_PROMO)
+          .SetInAnyContext(true)
+          .SetAnchorElementFilter(base::BindLambdaForTesting(
+              [&](const ui::ElementTracker::ElementList& elements) {
+                EXPECT_EQ(3U, elements.size());
+                for (auto* element : elements) {
+                  if (element->context() == widget_context)
+                    return element;
+                }
+                ADD_FAILURE() << "Did not find expected element.";
+                return (ui::TrackedElement*)(nullptr);
+              }))));
+
+  EXPECT_CALL(*mock_tracker_, ShouldTriggerHelpUI(Ref(kOneOffIPHFeature)))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  // Add two random views to the browser with the same element ID.
+  browser_view()
+      ->toolbar()
+      ->AddChildView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+  browser_view()
+      ->toolbar()
+      ->AddChildView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+
+  // Create a second widget with an element with the target identifier.
+  auto widget = std::make_unique<views::Widget>();
+  views::Widget::InitParams params(
+      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+  params.bounds = gfx::Rect(0, 0, 200, 200);
+  params.context = browser_view()->GetWidget()->GetNativeWindow();
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget->Init(std::move(params));
+  widget->SetContentsView(std::make_unique<views::View>())
+      ->SetProperty(views::kElementIdentifierKey, kOneOffIPHElementId);
+  widget->Show();
+  widget_context =
+      views::ElementTrackerViews::GetContextForWidget(widget.get());
+
+  EXPECT_NE(browser_view()->GetElementContext(), widget_context);
+
+  EXPECT_TRUE(controller_->MaybeShowPromo(kOneOffIPHFeature));
+  EXPECT_TRUE(controller_->IsPromoActive(kOneOffIPHFeature));
+  auto* const bubble = GetPromoBubble();
+  ASSERT_TRUE(bubble);
+  EXPECT_EQ(widget_context,
+            controller_->promo_bubble_for_testing()->GetContext());
+
+  bubble->Close();
+}
+
 TEST_F(BrowserFeaturePromoControllerTest,
        DismissNonCriticalBubbleInRegion_RegionDoesNotOverlap) {
   EXPECT_CALL(*mock_tracker_, ShouldTriggerHelpUI(Ref(kTestIPHFeature)))
diff --git a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
index abb7223..f714ee14 100644
--- a/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
+++ b/chrome/browser/ui/web_applications/test/system_web_app_interactive_uitest.cc
@@ -17,6 +17,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
 #include "chrome/browser/ui/app_list/app_service/app_service_app_item.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
-#include "chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h"
 #include "chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h"
 #include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
@@ -74,7 +74,7 @@
 namespace web_app {
 
 class SystemWebAppLinkCaptureBrowserTest
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppLinkCaptureBrowserTest()
       : SystemWebAppManagerBrowserTest(/*install_mock*/ false) {
@@ -481,7 +481,7 @@
 #endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
 
 class SystemWebAppManagerWindowSizeControlsTest
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppManagerWindowSizeControlsTest()
       : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
@@ -700,7 +700,8 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-using SystemWebAppLaunchProfileBrowserTest = SystemWebAppManagerBrowserTest;
+using SystemWebAppLaunchProfileBrowserTest =
+    ash::SystemWebAppManagerBrowserTest;
 
 IN_PROC_BROWSER_TEST_P(SystemWebAppLaunchProfileBrowserTest,
                        LaunchFromNormalSessionIncognitoProfile) {
@@ -792,7 +793,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 using SystemWebAppLaunchOmniboxNavigateBrowsertest =
-    SystemWebAppManagerBrowserTest;
+    ash::SystemWebAppManagerBrowserTest;
 
 IN_PROC_BROWSER_TEST_P(SystemWebAppLaunchOmniboxNavigateBrowsertest,
                        OpenInTab) {
@@ -853,10 +854,10 @@
 
 // Tests which are exercising OpenUrl called by Lacros in Ash.
 class SystemWebAppOpenInAshFromLacrosTests
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppOpenInAshFromLacrosTests()
-      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+      : ash::SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
     OsUrlHandlerSystemWebAppDelegate::EnableDelegateForTesting(true);
     url_handler_ = std::make_unique<crosapi::UrlHandlerAsh>();
   }
@@ -956,7 +957,7 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class SystemWebAppManagerCloseFromScriptsTest
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppManagerCloseFromScriptsTest()
       : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
@@ -988,10 +989,10 @@
 }
 
 class SystemWebAppManagerShouldNotCloseFromScriptsTest
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppManagerShouldNotCloseFromScriptsTest()
-      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+      : ash::SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
     maybe_installation_ =
         TestSystemWebAppInstallation::SetupAppWithAllowScriptsToCloseWindows(
             false);
@@ -1027,10 +1028,10 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 class SystemWebAppNewWindowMenuItemTest
-    : public SystemWebAppManagerBrowserTest {
+    : public ash::SystemWebAppManagerBrowserTest {
  public:
   SystemWebAppNewWindowMenuItemTest()
-      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+      : ash::SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
     maybe_installation_ =
         TestSystemWebAppInstallation::SetUpAppWithNewWindowMenuItem();
   }
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index ccedbab..65a0642 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -20,8 +20,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
@@ -34,7 +34,6 @@
 
 namespace {
 
-using ::chromeos::DBusThreadManager;
 using ::chromeos::OwnerSettingsServiceAsh;
 using ::chromeos::OwnerSettingsServiceAshFactory;
 using ::chromeos::UpdateEngineClient;
@@ -145,13 +144,11 @@
   if (!EnsureCanUpdate(false /* interactive */, callback_))
     return;
 
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
+  UpdateEngineClient* update_engine_client = UpdateEngineClient::Get();
   if (!update_engine_client->HasObserver(this))
     update_engine_client->AddObserver(this);
 
-  this->UpdateStatusChanged(
-      DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus());
+  this->UpdateStatusChanged(update_engine_client->GetLastStatus());
 }
 
 void VersionUpdaterCros::CheckForUpdate(StatusCallback callback,
@@ -162,8 +159,7 @@
   if (!EnsureCanUpdate(true /* interactive */, callback_))
     return;
 
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
+  UpdateEngineClient* update_engine_client = UpdateEngineClient::Get();
   if (!update_engine_client->HasObserver(this))
     update_engine_client->AddObserver(this);
 
@@ -192,8 +188,7 @@
   // For local owner set the field in the policy blob.
   if (service)
     service->SetString(ash::kReleaseChannel, channel);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->
-      SetChannel(channel, is_powerwash_allowed);
+  UpdateEngineClient::Get()->SetChannel(channel, is_powerwash_allowed);
 }
 
 void VersionUpdaterCros::SetUpdateOverCellularOneTimePermission(
@@ -201,13 +196,11 @@
     const std::string& update_version,
     int64_t update_size) {
   callback_ = std::move(callback);
-  DBusThreadManager::Get()
-      ->GetUpdateEngineClient()
-      ->SetUpdateOverCellularOneTimePermission(
-          update_version, update_size,
-          base::BindOnce(
-              &VersionUpdaterCros::OnSetUpdateOverCellularOneTimePermission,
-              weak_ptr_factory_.GetWeakPtr()));
+  UpdateEngineClient::Get()->SetUpdateOverCellularOneTimePermission(
+      update_version, update_size,
+      base::BindOnce(
+          &VersionUpdaterCros::OnSetUpdateOverCellularOneTimePermission,
+          weak_ptr_factory_.GetWeakPtr()));
 }
 
 void VersionUpdaterCros::OnSetUpdateOverCellularOneTimePermission(
@@ -226,12 +219,9 @@
 
 void VersionUpdaterCros::GetChannel(bool get_current_channel,
                                     ChannelCallback cb) {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-
   // Request the channel information. Bind to a weak_ptr bound method rather
   // than passing |cb| directly so that |cb| does not outlive |this|.
-  update_engine_client->GetChannel(
+  UpdateEngineClient::Get()->GetChannel(
       get_current_channel,
       base::BindOnce(&VersionUpdaterCros::OnGetChannel,
                      weak_ptr_factory_.GetWeakPtr(), std::move(cb)));
@@ -243,12 +233,9 @@
 }
 
 void VersionUpdaterCros::GetEolInfo(EolInfoCallback cb) {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-
   // Request the EolInfo. Bind to a weak_ptr bound method rather than passing
   // |cb| directly so that |cb| does not outlive |this|.
-  update_engine_client->GetEolInfo(
+  UpdateEngineClient::Get()->GetEolInfo(
       base::BindOnce(&VersionUpdaterCros::OnGetEolInfo,
                      weak_ptr_factory_.GetWeakPtr(), std::move(cb)));
 }
@@ -261,18 +248,12 @@
 
 void VersionUpdaterCros::ToggleFeature(const std::string& feature,
                                        bool enable) {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-
-  update_engine_client->ToggleFeature(feature, enable);
+  UpdateEngineClient::Get()->ToggleFeature(feature, enable);
 }
 
 void VersionUpdaterCros::IsFeatureEnabled(const std::string& feature,
                                           IsFeatureEnabledCallback callback) {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-
-  update_engine_client->IsFeatureEnabled(
+  UpdateEngineClient::Get()->IsFeatureEnabled(
       feature,
       base::BindOnce(&VersionUpdaterCros::OnIsFeatureEnabled,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -293,9 +274,7 @@
       check_for_update_when_idle_(false) {}
 
 VersionUpdaterCros::~VersionUpdaterCros() {
-  UpdateEngineClient* update_engine_client =
-      DBusThreadManager::Get()->GetUpdateEngineClient();
-  update_engine_client->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void VersionUpdaterCros::UpdateStatusChanged(
diff --git a/chrome/browser/upgrade_detector/installed_version_updater_chromeos.cc b/chrome/browser/upgrade_detector/installed_version_updater_chromeos.cc
index 912d15b..5571643 100644
--- a/chrome/browser/upgrade_detector/installed_version_updater_chromeos.cc
+++ b/chrome/browser/upgrade_detector/installed_version_updater_chromeos.cc
@@ -8,7 +8,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/upgrade_detector/build_state.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/update_engine/update_engine_client.h"
 
 namespace {
 
@@ -24,14 +24,12 @@
 
 InstalledVersionUpdater::InstalledVersionUpdater(BuildState* build_state)
     : build_state_(build_state) {
-  chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(
-      this);
+  chromeos::UpdateEngineClient::Get()->AddObserver(this);
 }
 
 InstalledVersionUpdater::~InstalledVersionUpdater() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(
-      this);
+  chromeos::UpdateEngineClient::Get()->RemoveObserver(this);
 }
 
 void InstalledVersionUpdater::UpdateStatusChanged(
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
index c58db79b..c4571dd 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_chromeos.cc
@@ -20,14 +20,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/upgrade_detector/build_state.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/update_engine/update_engine_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 
-using chromeos::DBusThreadManager;
 using chromeos::UpdateEngineClient;
 
 namespace {
@@ -74,7 +72,7 @@
   UpgradeDetector::Init();
   MonitorPrefChanges(prefs::kRelaunchHeadsUpPeriod);
   MonitorPrefChanges(prefs::kRelaunchNotification);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
+  UpdateEngineClient::Get()->AddObserver(this);
   auto* const build_state = g_browser_process->GetBuildState();
   build_state->AddObserver(this);
   installed_version_updater_.emplace(build_state);
@@ -87,7 +85,7 @@
     return;
   installed_version_updater_.reset();
   g_browser_process->GetBuildState()->RemoveObserver(this);
-  DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
+  UpdateEngineClient::Get()->RemoveObserver(this);
   upgrade_notification_timer_.Stop();
   UpgradeDetector::Shutdown();
   initialized_ = false;
@@ -220,7 +218,7 @@
   if (!toggled_update_flag_) {
     // Only send feature flag status one time.
     toggled_update_flag_ = true;
-    DBusThreadManager::Get()->GetUpdateEngineClient()->ToggleFeature(
+    UpdateEngineClient::Get()->ToggleFeature(
         update_engine::kFeatureRepeatedUpdates,
         base::FeatureList::IsEnabled(
             chromeos::features::kAllowRepeatedUpdates));
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 25333910..24c6bf54 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -616,34 +616,6 @@
   }
 }
 
-# Browsertest base classes that depend on //chrome/test:test_support_ui. Must
-# be separate from :web_applications_test_support because that is depended upon
-# by //chrome/test:test_support_ui.
-source_set("browser_tests_base") {
-  testonly = true
-
-  sources = [
-    "system_web_apps/test/system_web_app_browsertest_base.cc",
-    "system_web_apps/test/system_web_app_browsertest_base.h",
-  ]
-
-  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
-
-  deps = [
-    ":web_applications",
-    "//chrome/browser",
-    "//chrome/browser/ash/system_web_apps",
-    "//chrome/browser/profiles:profile",
-    "//chrome/browser/ui",
-    "//chrome/browser/web_applications:web_applications_test_support",
-    "//chrome/test:test_support_ui",
-    "//components/services/app_service/public/cpp:types",
-    "//content/test:test_support",
-    "//testing/gtest",
-    "//url",
-  ]
-}
-
 group("unit_tests") {
   testonly = true
 
@@ -690,13 +662,13 @@
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
   deps = [
-    ":browser_tests_base",
     ":web_applications",
     ":web_applications_test_support",
     "adjustments:adjustments_browser_tests",
     "//base",
     "//chrome/app:command_ids",
     "//chrome/browser/apps/app_service:test_support",
+    "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
     "//chrome/browser/profiles:profile",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 8e05f315..628a8f3 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1655812488-3e24cca7f96fde7ef392ffd74c5ba4f868ccaa05.profdata
+chrome-linux-main-1655834389-f20efa6117f81ee2f688d344652a075890d6552b.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 56eee1c..eeca1cc 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1655812488-16619c864cef3db74dd5ab8dfceb8b5f7a650066.profdata
+chrome-win32-main-1655823537-daa62db3b88be48c2a30be0206afd093cbae5b3a.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 6597f91..f0f4eb6 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1655812488-02591322faaea4b10e5f8a34f98808289fc44c22.profdata
+chrome-win64-main-1655823537-91204d4cfe59f5faebc20c310ab776ecebdc3740.profdata
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index c3d5bd5c..074ac1a 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -83,7 +83,9 @@
 const char kAppsGalleryURL[] = "apps-gallery-url";
 
 // Allowlist for Negotiate Auth servers
-const char kAuthServerAllowlist[] = "auth-server-whitelist";
+const char kAuthServerAllowlist[] = "auth-server-allowlist";
+const char kAuthServerAllowlistDeprecated[] =
+    "auth-server-whitelist";  // nocheck
 
 // This flag makes Chrome auto-open DevTools window for each tab. It is
 // intended to be used by developers and automation to not require user
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 42d445af..db1c159 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -52,6 +52,7 @@
 extern const char kAppsGalleryUpdateURL[];
 extern const char kAppsGalleryURL[];
 extern const char kAuthServerAllowlist[];
+extern const char kAuthServerAllowlistDeprecated[];
 extern const char kAutoOpenDevToolsForTabs[];
 extern const char kAutoSelectDesktopCaptureSource[];
 extern const char kAutoSelectTabCaptureSourceByTitle[];
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index 582f853..8d678a96 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -50,8 +50,7 @@
 using blink::WebString;
 using blink::WebVector;
 
-namespace autofill {
-namespace form_util {
+namespace autofill::form_util {
 
 namespace {
 
@@ -2527,6 +2526,7 @@
   expected.autocomplete_attribute = "off";
   expected.should_autocomplete = false;
   expected.is_focusable = true;
+  expected.is_visible = true;
   expected.text_direction = base::i18n::LEFT_TO_RIGHT;
 
   expected.value = u"CA";
@@ -5658,5 +5658,4 @@
   EXPECT_EQ(u"aria description", fields[2].aria_description);
 }
 
-}  // namespace form_util
-}  // namespace autofill
+}  // namespace autofill::form_util
diff --git a/chrome/services/sharing/nearby/platform/condition_variable_unittest.cc b/chrome/services/sharing/nearby/platform/condition_variable_unittest.cc
index 5729613..170eb13 100644
--- a/chrome/services/sharing/nearby/platform/condition_variable_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/condition_variable_unittest.cc
@@ -74,8 +74,8 @@
   base::flat_set<base::UnguessableToken> successful_run_attempts_;
 };
 
-// Speculatively disabled on ChromeOS MSAN bots due to https://crbug.com/1186166
-#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
+// Speculatively disabled on ChromeOS bots due to https://crbug.com/1186166
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_SingleSequence_BlocksOnWaitAndUnblocksOnNotify \
   DISABLED_SingleSequence_BlocksOnWaitAndUnblocksOnNotify
 #else
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0d5734f..e2c5bec 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1189,6 +1189,7 @@
       "//chrome/browser/accessibility:test_support",
       "//chrome/browser/apps/app_service:test_support",
       "//chrome/browser/ash/system_web_apps:browser_tests",
+      "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
       "//chrome/browser/ash/system_web_apps/types:types",
       "//chrome/browser/breadcrumbs:browser_tests",
       "//chrome/browser/browsing_data:constants",
@@ -1220,7 +1221,6 @@
       "//chrome/browser/ui/color:color_headers",
       "//chrome/browser/ui/tabs:tab_enums",
       "//chrome/browser/web_applications:browser_tests",
-      "//chrome/browser/web_applications:browser_tests_base",
       "//chrome/browser/web_applications:web_applications_test_support",
       "//chrome/browser/web_applications/extensions",
       "//chrome/browser/web_share_target:browser_tests",
@@ -4456,8 +4456,8 @@
       # TODO(crbug.com/1278123): Enable once PWAs are supported.
       deps -= [
         "//chrome/browser/ash/system_web_apps:browser_tests",
+        "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
         "//chrome/browser/web_applications:browser_tests",
-        "//chrome/browser/web_applications:browser_tests_base",
       ]
       sources -= [
         "../../apps/app_restore_service_browsertest.cc",
@@ -9093,11 +9093,11 @@
       "//chrome/app:command_ids",
       "//chrome/browser",
       "//chrome/browser:unexpire_flags",
+      "//chrome/browser/ash/system_web_apps/test_support:test_support_ui",
       "//chrome/browser/devtools",
       "//chrome/browser/devtools:test_support",
       "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
       "//chrome/browser/resource_coordinator/tab_ranker",
-      "//chrome/browser/web_applications:browser_tests_base",
       "//chrome/browser/web_applications:interactive_ui_tests",
       "//chrome/browser/web_applications:web_applications_test_support",
       "//chrome/common:version_header",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/HistoryTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/HistoryTestUtils.java
index 244c8b4..ccb398c 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/HistoryTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/browser/history/HistoryTestUtils.java
@@ -4,87 +4,14 @@
 
 package org.chromium.chrome.browser.history;
 
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.recyclerview.widget.RecyclerView;
-
 import org.junit.Assert;
 
-import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.chrome.browser.preferences.PrefChangeRegistrar.PrefObserver;
-import org.chromium.chrome.browser.signin.services.SigninManager.SignInStateObserver;
 import org.chromium.components.browser_ui.widget.DateDividedAdapter.ItemViewType;
-import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate.SelectionObserver;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-import java.util.List;
 
 /**
  * Util class for functions and helper classes that share between different test files.
  */
 public class HistoryTestUtils {
-    /**
-     * Test Observer that used to collect the callback counts used in {@link HistoryActivityTest}
-     * {@link HistoryActivityScrollingTest}.
-     */
-    static class TestObserver extends RecyclerView.AdapterDataObserver
-            implements SelectionObserver<HistoryItem>, SignInStateObserver, PrefObserver {
-        public final CallbackHelper onChangedCallback = new CallbackHelper();
-        public final CallbackHelper onSelectionCallback = new CallbackHelper();
-        public final CallbackHelper onSigninStateChangedCallback = new CallbackHelper();
-        public final CallbackHelper onPreferenceChangeCallback = new CallbackHelper();
-
-        private Handler mHandler;
-
-        public TestObserver() {
-            mHandler = new Handler(Looper.getMainLooper());
-        }
-
-        @Override
-        public void onChanged() {
-            // To guarantee that all real Observers have had a chance to react to the event, post
-            // the CallbackHelper.notifyCalled() call.
-            mHandler.post(() -> onChangedCallback.notifyCalled());
-        }
-
-        @Override
-        public void onSelectionStateChange(List<HistoryItem> selectedItems) {
-            mHandler.post(() -> onSelectionCallback.notifyCalled());
-        }
-
-        @Override
-        public void onSignedIn() {
-            mHandler.post(() -> onSigninStateChangedCallback.notifyCalled());
-        }
-
-        @Override
-        public void onSignedOut() {
-            mHandler.post(() -> onSigninStateChangedCallback.notifyCalled());
-        }
-
-        @Override
-        public void onPreferenceChange() {
-            mHandler.post(() -> onPreferenceChangeCallback.notifyCalled());
-        }
-    }
-
-    static void setupHistoryTestHeaders(HistoryAdapter adapter, TestObserver observer)
-            throws Exception {
-        if (!adapter.isClearBrowsingDataButtonVisible()) {
-            int changedCallCount = observer.onChangedCallback.getCallCount();
-            TestThreadUtils.runOnUiThreadBlocking(
-                    () -> adapter.setClearBrowsingDataButtonVisibilityForTest(true));
-            observer.onChangedCallback.waitForCallback(changedCallCount);
-        }
-
-        if (adapter.arePrivacyDisclaimersVisible()) {
-            int changedCallCount = observer.onChangedCallback.getCallCount();
-            TestThreadUtils.runOnUiThreadBlocking(() -> adapter.hasOtherFormsOfBrowsingData(false));
-            observer.onChangedCallback.waitForCallback(changedCallCount);
-        }
-    }
-
     static void checkAdapterContents(
             HistoryAdapter adapter, boolean hasHeader, boolean hasFooter, Object... items) {
         Assert.assertEquals(items.length, adapter.getItemCount());
diff --git a/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/background.js b/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/background.js
index 3641177..bbe53855 100644
--- a/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/background.js
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-var initiators = [];
+self.initiators = [];
 
 function onBeforeRequest(details) {
   if (details.initiator && details.url.includes('title1.html'))
-    initiators.push(details.initiator);
+    self.initiators.push(details.initiator);
 }
 
 chrome.webRequest.onBeforeRequest.addListener(
diff --git a/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/manifest.json b/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/manifest.json
index 099f390..961007a 100644
--- a/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/initiator_spanning/manifest.json
@@ -6,6 +6,7 @@
   "permissions": ["webRequest", "<all_urls>"],
   "incognito": "spanning",
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest/initiator_split/background.js b/chrome/test/data/extensions/api_test/webrequest/initiator_split/background.js
index d7e7ada..9700a572 100644
--- a/chrome/test/data/extensions/api_test/webrequest/initiator_split/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest/initiator_split/background.js
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-var initiators = [];
+self.initiators = [];
 
 function onBeforeRequest(details) {
   if (details.initiator && details.url.includes('title1.html'))
-    initiators.push(details.initiator);
+    self.initiators.push(details.initiator);
 }
 
 chrome.webRequest.onBeforeRequest.addListener(
diff --git a/chrome/test/data/extensions/api_test/webrequest/initiator_split/manifest.json b/chrome/test/data/extensions/api_test/webrequest/initiator_split/manifest.json
index cf859628..30068c4 100644
--- a/chrome/test/data/extensions/api_test/webrequest/initiator_split/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/initiator_split/manifest.json
@@ -6,6 +6,7 @@
   "permissions": ["webRequest", "<all_urls>"],
   "incognito": "split",
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/background.js b/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/background.js
index e063c49d..7f28daa 100644
--- a/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/background.js
@@ -13,7 +13,7 @@
 });
 
 function getAndResetRequestIntercepted() {
-  window.domAutomationController.send(interceptedRequest ? 'true' : 'false');
+  chrome.test.sendScriptResult(interceptedRequest);
   interceptedRequest = false;
 }
 
diff --git a/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/manifest.json b/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/manifest.json
index 99ece53..736edf4e 100644
--- a/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/ntp_request_interception/extension/manifest.json
@@ -4,6 +4,7 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "<all_urls>"],
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
  }
diff --git a/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_1/manifest.json b/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_1/manifest.json
index 2424b345..c535af1 100644
--- a/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_1/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_1/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_2/manifest.json b/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_2/manifest.json
index 467cbe65..afc8f7ca 100644
--- a/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_2/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/on_action_ignored/extension_2/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest/policy_blocked/background.js b/chrome/test/data/extensions/api_test/webrequest/policy_blocked/background.js
index 8a5055c..2d34182 100644
--- a/chrome/test/data/extensions/api_test/webrequest/policy_blocked/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest/policy_blocked/background.js
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.protectedOriginCount = 0;
+self.protectedOriginCount = 0;
 
 // Return messages to tell which URL requests are visible to the extension.
 chrome.webRequest.onBeforeRequest.addListener(function(details) {
    if (details.url.indexOf('example2') != -1) {
-     ++window.protectedOriginCount;
+     ++self.protectedOriginCount;
    }
    if (details.url.indexOf('protected_url') != -1) {
      chrome.test.sendMessage('protected_url');
diff --git a/chrome/test/data/extensions/api_test/webrequest/policy_blocked/manifest.json b/chrome/test/data/extensions/api_test/webrequest/policy_blocked/manifest.json
index c414d5e..fceaa4e 100644
--- a/chrome/test/data/extensions/api_test/webrequest/policy_blocked/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest/policy_blocked/manifest.json
@@ -4,6 +4,7 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "<all_urls>"],
   "background" : {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_activetab/background.js b/chrome/test/data/extensions/api_test/webrequest_activetab/background.js
index c738e95e..9995da3 100644
--- a/chrome/test/data/extensions/api_test/webrequest_activetab/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_activetab/background.js
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.webRequestCount = 0;
-window.requestedHostnames = [];
+self.webRequestCount = 0;
+self.requestedHostnames = [];
 
 chrome.webRequest.onBeforeRequest.addListener(function(details) {
-  ++window.webRequestCount;
-  window.requestedHostnames.push((new URL(details.url)).hostname);
+  ++self.webRequestCount;
+  self.requestedHostnames.push((new URL(details.url)).hostname);
 }, {urls:['<all_urls>']});
 
 chrome.test.sendMessage('ready');
diff --git a/chrome/test/data/extensions/api_test/webrequest_activetab/manifest.json b/chrome/test/data/extensions/api_test/webrequest_activetab/manifest.json
index 90d7336..923b8f1c 100644
--- a/chrome/test/data/extensions/api_test/webrequest_activetab/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_activetab/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_clients_google_com/background.js b/chrome/test/data/extensions/api_test/webrequest_clients_google_com/background.js
index 36427dc0..8796e6c 100644
--- a/chrome/test/data/extensions/api_test/webrequest_clients_google_com/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_clients_google_com/background.js
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.clientsGoogleWebRequestCount = 0;
-window.yahooWebRequestCount = 0;
+self.clientsGoogleWebRequestCount = 0;
+self.yahooWebRequestCount = 0;
 
 chrome.webRequest.onBeforeRequest.addListener(function(details) {
-  if (details.url.includes('http://clients1.google.com/'))
-    ++window.clientsGoogleWebRequestCount;
-  if (details.url.includes('http://yahoo.com'))
-    ++window.yahooWebRequestCount;
+  if (details.url.includes('http://clients1.google.com/')) {
+    ++self.clientsGoogleWebRequestCount;
+  } else if (details.url.includes('http://yahoo.com')) {
+    ++self.yahooWebRequestCount;
+  }
 }, {urls: ['<all_urls>']});
 
 chrome.test.sendMessage('ready');
diff --git a/chrome/test/data/extensions/api_test/webrequest_clients_google_com/manifest.json b/chrome/test/data/extensions/api_test/webrequest_clients_google_com/manifest.json
index 72b8de0b..2396e4d 100644
--- a/chrome/test/data/extensions/api_test/webrequest_clients_google_com/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_clients_google_com/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_cors_preflight/background.js b/chrome/test/data/extensions/api_test/webrequest_cors_preflight/background.js
index 91b3d48..1b3419c 100644
--- a/chrome/test/data/extensions/api_test/webrequest_cors_preflight/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_cors_preflight/background.js
@@ -2,25 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.preflightHeadersReceivedCount = 0
-window.preflightProxyAuthRequiredCount = 0;
-window.preflightResponseStartedCount = 0;
-window.preflightResponseStartedSuccessfullyCount = 0
+self.preflightHeadersReceivedCount = 0
+self.preflightProxyAuthRequiredCount = 0;
+self.preflightResponseStartedCount = 0;
+self.preflightResponseStartedSuccessfullyCount = 0
 
 chrome.webRequest.onHeadersReceived.addListener(function (details) {
   if (details.method === "OPTIONS") {
-    ++window.preflightHeadersReceivedCount;
+    ++self.preflightHeadersReceivedCount;
     if (details.statusCode == 407) {
-      ++window.preflightProxyAuthRequiredCount;
+      ++self.preflightProxyAuthRequiredCount;
     }
   }
 }, { urls: ['http://cors.test/*'] }, ["extraHeaders"]);
 
 chrome.webRequest.onResponseStarted.addListener(function (details) {
   if (details.method === "OPTIONS") {
-    ++window.preflightResponseStartedCount;
+    ++self.preflightResponseStartedCount;
     if (details.statusCode == 204) {
-      ++window.preflightResponseStartedSuccessfullyCount;
+      ++self.preflightResponseStartedSuccessfullyCount;
     }
   }
 }, { urls: ['http://cors.test/*'] }, ["extraHeaders"]);
diff --git a/chrome/test/data/extensions/api_test/webrequest_cors_preflight/manifest.json b/chrome/test/data/extensions/api_test/webrequest_cors_preflight/manifest.json
index e54be86..61c4f84 100644
--- a/chrome/test/data/extensions/api_test/webrequest_cors_preflight/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_cors_preflight/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": [ "webRequest", "http://127.0.0.1/*", "http://cors.test/*" ],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_dice_header/background.js b/chrome/test/data/extensions/api_test/webrequest_dice_header/background.js
index 3366083..d1bb9a8 100644
--- a/chrome/test/data/extensions/api_test/webrequest_dice_header/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_dice_header/background.js
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.diceResponseHeaderCount = 0;
-window.controlResponseHeaderCount = 0;
+self.diceResponseHeaderCount = 0;
+self.controlResponseHeaderCount = 0;
 
 chrome.webRequest.onHeadersReceived.addListener(function(details) {
   let diceHeaderFound = false;
@@ -11,11 +11,11 @@
   const diceResponseHeader = 'X-Chrome-ID-Consistency-Response';
   details.responseHeaders.forEach(function(header) {
     if (header.name == diceResponseHeader){
-      ++window.diceResponseHeaderCount;
+      ++self.diceResponseHeaderCount;
       diceHeaderFound = true;
       header.value = headerValue;
     } else if (header.name == 'X-Control'){
-      ++window.controlResponseHeaderCount;
+      ++self.controlResponseHeaderCount;
       header.value = headerValue;
     }
   });
diff --git a/chrome/test/data/extensions/api_test/webrequest_dice_header/manifest.json b/chrome/test/data/extensions/api_test/webrequest_dice_header/manifest.json
index 380aa9d..4e496dd 100644
--- a/chrome/test/data/extensions/api_test/webrequest_dice_header/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_dice_header/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_pac_request/background.js b/chrome/test/data/extensions/api_test/webrequest_pac_request/background.js
index 1157a905..7a1e1e6 100644
--- a/chrome/test/data/extensions/api_test/webrequest_pac_request/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_pac_request/background.js
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-window.pacRequestCount = 0;
-window.title2RequestCount = 0;
+self.pacRequestCount = 0;
+self.title2RequestCount = 0;
 
 chrome.webRequest.onBeforeRequest.addListener(function(details) {
-  ++window.pacRequestCount;
+  ++self.pacRequestCount;
 }, {urls: ['*://*/self.pac']});
 
 chrome.webRequest.onBeforeRequest.addListener(function(details) {
-  ++window.title2RequestCount;
+  ++self.title2RequestCount;
 }, {urls: ['*://*/title2.html']});
 
 chrome.test.sendMessage('ready');
diff --git a/chrome/test/data/extensions/api_test/webrequest_pac_request/manifest.json b/chrome/test/data/extensions/api_test/webrequest_pac_request/manifest.json
index 498470d..2278adb6 100644
--- a/chrome/test/data/extensions/api_test/webrequest_pac_request/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_pac_request/manifest.json
@@ -4,5 +4,8 @@
   "manifest_version": 2,
   "permissions": ["webRequest", "<all_urls>"],
   "version": "0.1",
-  "background": {"scripts": ["background.js"]}
+  "background": {
+    "scripts": ["background.js"],
+    "persistent": true
+  }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/background.js b/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/background.js
index e69c230..59b747f 100644
--- a/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/background.js
+++ b/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/background.js
@@ -1,10 +1,10 @@
 // Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var requestsIntercepted = 0;
+self.requestsIntercepted = 0;
 
 chrome.webRequest.onBeforeRequest.addListener((details) => {
-  requestsIntercepted++;
+  self.requestsIntercepted++;
   chrome.test.sendMessage(details.initiator);
 }, {urls: ['*://*/extensions/api_test/webrequest/xhr/data.json']}, []);
 
diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/manifest.json b/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/manifest.json
index bb1b169..b538761 100644
--- a/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_permissions/initiator/manifest.json
@@ -10,6 +10,7 @@
       "*://*.example3.com/*",
       "*://*.example4.com/*"],
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json
index f638a48..6b00e757 100644
--- a/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_permissions/spanning/manifest.json
@@ -6,6 +6,7 @@
   "permissions": ["declarativeWebRequest", "<all_urls>"],
   "incognito": "spanning",
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json b/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json
index f1d3f9e..b79d5c18 100644
--- a/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_permissions/split/manifest.json
@@ -6,6 +6,7 @@
   "permissions": ["declarativeWebRequest", "<all_urls>"],
   "incognito": "split",
   "background": {
-    "scripts": ["background.js"]
+    "scripts": ["background.js"],
+    "persistent": true
   }
 }
diff --git a/chrome/test/data/extensions/api_test/webrequest_reload/manifest.json b/chrome/test/data/extensions/api_test/webrequest_reload/manifest.json
index 0498f1b7..a3f55845 100644
--- a/chrome/test/data/extensions/api_test/webrequest_reload/manifest.json
+++ b/chrome/test/data/extensions/api_test/webrequest_reload/manifest.json
@@ -4,7 +4,8 @@
     "version": "1",
     "manifest_version": 2,
     "background": {
-        "scripts": ["background.js"]
+      "scripts": ["background.js"],
+      "persistent": true
     },
     "permissions": [
         "webRequest",
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/feedback_flow_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/feedback_flow_test.js
index 13c80d6..74844b0c 100644
--- a/chrome/test/data/webui/chromeos/os_feedback_ui/feedback_flow_test.js
+++ b/chrome/test/data/webui/chromeos/os_feedback_ui/feedback_flow_test.js
@@ -269,6 +269,8 @@
     const inputElement =
         searchPage.shadowRoot.querySelector('#descriptionText');
     assertEquals(inputElement.value, '');
+    // The description input element should have received focused.
+    assertEquals(inputElement, getDeepActiveElement());
   });
 
   // When starting a new report, the send button in share data page
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
index 543cfc1..0393796 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
@@ -19,12 +19,7 @@
   }
 
   get featureList() {
-    return {
-      enabled: [
-        'chromeos::features::kWallpaperWebUI',
-        'ash::features::kWallpaperGooglePhotosIntegration'
-      ]
-    };
+    return {enabled: ['ash::features::kWallpaperGooglePhotosIntegration']};
   }
 };
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_browsertest.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_browsertest.js
index 6abf5b05..68a34c7 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_browsertest.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_controller_browsertest.js
@@ -18,10 +18,6 @@
         '&module=chromeos/personalization_app/' +
         'personalization_app_controller_test.js';
   }
-
-  get featureList() {
-    return {enabled: ['chromeos::features::kWallpaperWebUI']};
-  }
 };
 
 TEST_F('PersonalizationAppControllerBrowserTest', 'All', () => mocha.run());
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/wrapup_repair_complete_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/wrapup_repair_complete_page_test.js
index 971d434..2034776 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/wrapup_repair_complete_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/wrapup_repair_complete_page_test.js
@@ -251,7 +251,7 @@
     assertTrue(powerwashDialog.open);
   });
 
-  test('CutoffBatteryButtonOpensCountdownDialogAndCutsOffBattery', async () => {
+  test('CutoffBatteryButtonCutsOffBattery', async () => {
     const resolver = new PromiseResolver();
     await initializeRepairCompletePage();
     let callCount = 0;
@@ -274,11 +274,11 @@
     // Cut off the battery.
     assertEquals(1, callCount);
     assertEquals(ShutdownMethod.kBatteryCutoff, shutdownMethod);
-    // Show the dialog.
+    // When the countdown is done, the battery cutoff dialog will be closed.
     const batteryCutoffDialog =
         component.shadowRoot.querySelector('#batteryCutoffDialog');
     assertTrue(!!batteryCutoffDialog);
-    assertTrue(batteryCutoffDialog.open);
+    assertFalse(batteryCutoffDialog.open);
   });
 
   test('PowerCableConnectCancelsBatteryCutoff', async () => {
@@ -308,11 +308,20 @@
     };
     await flushTasks();
 
+    // Force the battery cutoff dialog to open, to make sure that the shutdown
+    // button closes it.
+    const batteryCutoffDialog =
+        component.shadowRoot.querySelector('#batteryCutoffDialog');
+    assertTrue(!!batteryCutoffDialog);
+    batteryCutoffDialog.showModal();
+    assertTrue(batteryCutoffDialog.open);
+
     await clickButton('#batteryCutoffShutdownButton');
     await flushTasks();
 
     assertEquals(1, callCount);
     assertEquals(ShutdownMethod.kBatteryCutoff, shutdownMethod);
+    assertFalse(batteryCutoffDialog.open);
   });
 
   test('OpensRmaLogDialog', async () => {
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 209854d9..181baf7 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -28,7 +28,6 @@
 #include "chromeos/dbus/runtime_probe/runtime_probe_client.h"
 #include "chromeos/dbus/shill/shill_clients.h"
 #include "chromeos/dbus/smbprovider/smb_provider_client.h"
-#include "chromeos/dbus/update_engine/update_engine_client.h"
 
 namespace chromeos {
 
@@ -116,10 +115,6 @@
   RETURN_DBUS_CLIENT(smb_provider_client_);
 }
 
-UpdateEngineClient* DBusThreadManager::GetUpdateEngineClient() {
-  return UpdateEngineClient::Get();
-}
-
 VirtualFileProviderClient* DBusThreadManager::GetVirtualFileProviderClient() {
   return clients_browser_
              ? clients_browser_->virtual_file_provider_client_.get()
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 4178014..ff6575b 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -32,7 +32,6 @@
 class OobeConfigurationClient;
 class RuntimeProbeClient;
 class SmbProviderClient;
-class UpdateEngineClient;
 class VirtualFileProviderClient;
 
 // THIS CLASS IS BEING DEPRECATED. See README.md for guidelines and
@@ -85,7 +84,6 @@
   OobeConfigurationClient* GetOobeConfigurationClient();
   RuntimeProbeClient* GetRuntimeProbeClient();
   SmbProviderClient* GetSmbProviderClient();
-  UpdateEngineClient* GetUpdateEngineClient();
   VirtualFileProviderClient* GetVirtualFileProviderClient();
 
  private:
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index beaf07e..da4ed01 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -313,6 +313,15 @@
 
   # http://crbug.com/1338038
   "arc.IMEBlockingVK",
+
+  # http://crbug.com/1335213
+  "arc.WindowState.clamshell",
+
+  # http://crbug.com/1337191
+  "platform.Resourced.baseline",
+
+  # http://crbug.com/1338201
+  "ui.ChromeCrashLoggedIn.gpu_process_breakpad",
 ]
 
 # To create filters to be used on specific builders add them like this:
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 1b5cbac..ffb53d4 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1643,6 +1643,10 @@
 
 }  // namespace
 
+// TODO(crbug.com/1335257): This check is very similar to IsWebElementVisible()
+// (see the documentation there for the subtle differences: zoom factor and
+// scroll size). We can probably merge them but should do a Finch experiment
+// about it.
 bool IsVisibleIframe(const WebElement& element) {
   DCHECK(element.HasHTMLTagName("iframe"));
   // It is common for not-humanly-visible elements to have very small yet
@@ -1823,6 +1827,10 @@
   return element.IsCheckbox() || element.IsRadioButton();
 }
 
+bool IsCheckableElement(const WebElement& element) {
+  return IsCheckableElement(element.DynamicTo<WebInputElement>());
+}
+
 bool IsAutofillableInputElement(const WebInputElement& element) {
   return IsTextInput(element) || IsMonthInput(element) ||
          IsCheckableElement(element);
@@ -1838,6 +1846,16 @@
   return element.IsFocusable();
 }
 
+bool IsWebElementVisible(blink::WebElement element) {
+  auto HasMinSize = [](auto size) {
+    constexpr int kMinPixelSize = 10;
+    return size.width() >= kMinPixelSize && size.height() >= kMinPixelSize;
+  };
+  return !element.IsNull() && IsWebElementFocusable(element) &&
+         (IsCheckableElement(element) || HasMinSize(element.GetClientSize()) ||
+          HasMinSize(element.GetScrollSize()));
+}
+
 std::u16string GetFormIdentifier(const WebFormElement& form) {
   std::u16string identifier = form.GetName().Utf16();
   if (identifier.empty())
@@ -1973,6 +1991,7 @@
     // The browser doesn't need to differentiate between preview and autofill.
     field->is_autofilled = element.IsAutofilled();
     field->is_focusable = IsWebElementFocusable(element);
+    field->is_visible = IsWebElementVisible(element);
     field->should_autocomplete = element.AutoComplete();
 
     field->text_direction = GetTextDirectionForElement(element);
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index 6dc4996..c9ae9cee 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -85,7 +85,7 @@
 //
 // Future potential improvements include:
 // * Detect potential visibility of elements with "overflow: visible".
-//   (See Element::scrollWidth().)
+//   (See WebElement::GetScrollSize().)
 // * Detect invisibility of elements with
 //   - "position: absolute; {left,top,right,bottol}: -100px"
 //   - "opacity: 0.0"
@@ -173,6 +173,29 @@
 // descendant has a non-empty bounding client rect.
 bool IsWebElementFocusable(const blink::WebElement& element);
 
+// A heuristic visibility detection. See crbug.com/1335257 for an overview of
+// relevant aspects.
+//
+// Note that WebElement::BoundsInViewport(), WebElement::GetClientSize(), and
+// WebElement::GetScrollSize() include the padding but do not include the border
+// and margin. BoundsInViewport() additionally scales the dimensions according
+// to the zoom factor.
+//
+// It seems that invisible fields on websites typically have dimensions between
+// 0 and 10 pixels, before the zoom factor. Therefore choosing `kMinPixelSize`
+// is easier without including the zoom factor. For that reason, this function
+// prefers GetClientSize() over BoundsInViewport().
+//
+// This function does not check the position in the viewport because fields in
+// iframes commonly are visible despite the body having height zero. Therefore,
+// `e.GetDocument().Body().BoundsInViewport().Intersects(e.BoundsInViewport())`
+// yields false negatives.
+//
+// Exposed for testing purposes.
+//
+// TODO(crbug.com/1335257): Can input fields or iframes actually overflow?
+bool IsWebElementVisible(blink::WebElement element);
+
 // Returns the form's |name| attribute if non-empty; otherwise the form's |id|
 // attribute.
 std::u16string GetFormIdentifier(const blink::WebFormElement& form);
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 62445ea..12d8478 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -946,6 +946,9 @@
 }
 
 // Tests the visibility detection of iframes.
+// This test checks many scenarios. It's intentionally not a parameterized test
+// for performance reasons.
+// This test is very similar to the IsWebElementVisibleTest test.
 TEST_F(FormAutofillUtilsTest, IsVisibleIframeTest) {
   // Test cases of <iframe> elements with different styles.
   //
@@ -959,10 +962,10 @@
   // IsVisibleIframe() but invisible to the human).
   //
   // The `data-false="{POSITIVE,NEGATIVE}"` attribute indicates whether the test
-  // case to be a false positive/negative compared to human visibility
-  // perception. In such a case, not meeting the expectation actually indicates
-  // an improvement of IsVisibleIframe(), as it means a false positive/negative
-  // has been fixed.
+  // case is a false positive/negative compared to human visibility perception.
+  // In such a case, not meeting the expectation actually indicates an
+  // improvement of IsVisibleIframe(), as it means a false positive/negative has
+  // been fixed.
   //
   // The sole purpose of the `data-false` attribute is to document this and to
   // print a message when such a test fails.
@@ -996,7 +999,7 @@
         <iframe srcdoc="<input>" data-visible   style="width: 100px; height: 100px; position: absolute; right:  -200px;" data-false="POSITIVE"></iframe>
         <iframe srcdoc="<input>" data-visible   style="width: 100px; height: 100px; position: absolute; bottom: -200px;" data-false="POSITIVE"></iframe>
 
-        <iframe srcdoc="<input>" data-visible   style=""></iframe> <!-- Finish with a visible frame to make sure all <iframe>s have been closed -->
+        <iframe srcdoc="<input>" data-visible   style=""></iframe> <!-- Finish with a visible frame to make sure all <iframe> tags have been closed -->
 
         <div style="width: 10000; height: 10000"></div>
       </body>)");
@@ -1014,7 +1017,7 @@
     }
     return result;
   }();
-  ASSERT_GE(iframes.size(), 16u);
+  ASSERT_GE(iframes.size(), 23u);
 
   auto RunTestCases = [](const std::vector<WebElement>& iframes) {
     for (WebElement iframe : iframes) {
@@ -1047,6 +1050,125 @@
   }
 }
 
+// Tests the visibility detection of iframes.
+// This test checks many scenarios. It's intentionally not a parameterized test
+// for performance reasons.
+// This test is very similar to the IsVisibleIframeTest test.
+TEST_F(FormAutofillUtilsTest, IsWebElementVisibleTest) {
+  // Test cases of <input> elements with different types and styles.
+  //
+  // The `data-[in]visible` attribute represents whether IsWebElementVisible()
+  // is expected to classify the input as [in]visible.
+  //
+  // Since IsWebElementVisible() falls short of what the human user will
+  // consider visible or invisible, there are false positives and false
+  // negatives. For example, IsWebElementVisible() does not check opacity, so
+  // <input style="opacity: 0.0"> is a false positive (it's visible to
+  // IsWebElementVisible() but invisible to the human).
+  //
+  // The `data-false="{POSITIVE,NEGATIVE}"` attribute indicates whether the test
+  // case is a false positive/negative compared to human visibility perception.
+  // In such a case, not meeting the expectation actually indicates an
+  // improvement of IsWebElementVisible(), as it means a false positive/negative
+  // has been fixed.
+  //
+  // The sole purpose of the `data-false` attribute is to document this and to
+  // print a message when such a test fails.
+  LoadHTML(R"(
+      <body>
+        <input type="text" data-visible   style="">
+        <input type="text" data-visible   style="display: block;">
+        <input type="text" data-visible   style="visibility: visible;">
+
+        <input type="text" data-invisible style="display: none;">
+        <input type="text" data-invisible style="visibility: hidden;">
+        <div style="display: none;">     <input type="text" data-invisible></div>
+        <div style="visibility: hidden;"><input type="text" data-invisible></div>
+
+        <input type="text" data-visible   style="width: 15px; height: 15px;">
+        <input type="text" data-invisible style="width: 15px; height:  5px;">
+        <input type="text" data-invisible style="width:  5px; height: 15px;">
+        <input type="text" data-invisible style="width:  5px; height:  5px;">
+
+        <input type="text" data-invisible style="width: 1px; height: 1px;">
+        <input type="text" data-invisible style="width: 1px; height: 1px; overflow: visible;" data-false="NEGATIVE">
+
+        <input type="text" data-visible   style="opacity: 0.0;" data-false="POSITIVE">
+        <input type="text" data-visible   style="opacity: 0.0;" data-false="POSITIVE">
+        <input type="text" data-visible   style="position: absolute; clip: rect(0,0,0,0);" data-false="POSITIVE">
+
+        <input type="text" data-visible   style="width: 100px; position: absolute; left:    -75px;">
+        <input type="text" data-visible   style="width: 100px; position: absolute; top:     -75px;">
+        <input type="text" data-visible   style="width: 100px; position: absolute; left:   -200px;" data-false="POSITIVE">
+        <input type="text" data-visible   style="width: 100px; position: absolute; top:    -200px;" data-false="POSITIVE">
+        <input type="text" data-visible   style="width: 100px; position: absolute; right:  -200px;" data-false="POSITIVE">
+        <input type="text" data-visible   style="width: 100px; position: absolute; bottom: -200px;" data-false="POSITIVE">
+
+        <input type="checkbox" data-visible   style="">
+        <input type="checkbox" data-invisible style="display: none;">
+        <input type="checkbox" data-invisible style="visibility: hidden;">
+        <input type="checkbox" data-visible   style="width: 15px; height: 15px;">
+        <input type="checkbox" data-visible   style="width: 15px; height:  5px;">
+        <input type="checkbox" data-visible   style="width:  5px; height: 15px;">
+        <input type="checkbox" data-visible   style="width:  5px; height:  5px;">
+
+        <input type="radio" data-visible   style="">
+        <input type="radio" data-invisible style="display: none;">
+        <input type="radio" data-invisible style="visibility: hidden;">
+        <input type="radio" data-visible   style="width: 15px; height: 15px;">
+        <input type="radio" data-visible   style="width: 15px; height:  5px;">
+        <input type="radio" data-visible   style="width:  5px; height: 15px;">
+        <input type="radio" data-visible   style="width:  5px; height:  5px;">
+
+        <div style="width: 10000; height: 10000"></div>
+      </body>)");
+
+  // Ensure that Android runs at default page scale.
+  web_view_->SetPageScaleFactor(1.0);
+
+  std::vector<WebElement> inputs = [this] {
+    WebDocument doc = GetMainFrame()->GetDocument();
+    std::vector<WebElement> result;
+    WebElementCollection inputs = doc.GetElementsByHTMLTagName("input");
+    for (WebElement input = inputs.FirstItem(); !input.IsNull();
+         input = inputs.NextItem()) {
+      result.push_back(input);
+    }
+    return result;
+  }();
+  ASSERT_GE(inputs.size(), 36u);
+
+  auto RunTestCases = [](const std::vector<WebElement>& inputs) {
+    for (WebElement input : inputs) {
+      gfx::Rect bounds = input.BoundsInViewport();
+      bool expectation = input.HasAttribute("data-visible");
+      SCOPED_TRACE(
+          testing::Message()
+          << "Iframe with style \n  " << input.GetAttribute("style").Ascii()
+          << "\nwith dimensions w=" << bounds.width()
+          << ",h=" << bounds.height() << " and position x=" << bounds.x()
+          << ",y=" << bounds.y()
+          << (input.HasAttribute("data-false") ? "\nwhich used to be a FALSE "
+                                               : "")
+          << input.GetAttribute("data-false").Ascii());
+      ASSERT_TRUE(input.HasAttribute("data-visible") !=
+                  input.HasAttribute("data-invisible"));
+      EXPECT_EQ(IsWebElementVisible(input), expectation);
+    }
+  };
+
+  RunTestCases(inputs);
+
+  {
+    ExecuteJavaScriptForTests(
+        "window.scrollTo(document.body.scrollWidth,document.body.scrollHeight)"
+        ";");
+    content::RunAllTasksUntilIdle();
+    SCOPED_TRACE(testing::Message() << "Scrolled to bottom right");
+    RunTestCases(inputs);
+  }
+}
+
 // Tests `GetClosestAncestorFormElement(element)`.
 TEST_F(FormAutofillUtilsTest, GetClosestAncestorFormElement) {
   LoadHTML(R"(
diff --git a/components/autofill/core/browser/autofill_form_test_utils.cc b/components/autofill/core/browser/autofill_form_test_utils.cc
index e151487..3acab8e9 100644
--- a/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -103,6 +103,7 @@
     ff.unique_renderer_id =
         dd.unique_renderer_id.value_or(MakeFieldRendererId());
     ff.is_focusable = dd.is_focusable;
+    ff.is_visible = dd.is_visible;
     if (!dd.autocomplete_attribute.empty())
       ff.autocomplete_attribute = dd.autocomplete_attribute;
     if (dd.label)
diff --git a/components/autofill/core/browser/autofill_form_test_utils.h b/components/autofill/core/browser/autofill_form_test_utils.h
index b8c68f8..8da4714 100644
--- a/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/components/autofill/core/browser/autofill_form_test_utils.h
@@ -37,6 +37,7 @@
   absl::optional<LocalFrameToken> host_frame;
   absl::optional<FieldRendererId> unique_renderer_id;
   bool is_focusable = true;
+  bool is_visible = true;
   absl::optional<std::u16string> label;
   absl::optional<std::u16string> name;
   absl::optional<std::u16string> value;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 2ff856a..c3ba3ec 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -2870,6 +2870,10 @@
     buffer << Tr{} << "Label:" << truncated_label;
 
     buffer << Tr{} << "Is empty:" << (field->IsEmpty() ? "Yes" : "No");
+    buffer << Tr{} << "Is focusable:"
+           << (field->IsFocusable() ? "Yes (focusable)" : "No (unfocusable)");
+    buffer << Tr{} << "Is visible:"
+           << (field->is_visible ? "Yes (visible)" : "No (invisible)");
     buffer << CTag{"table"};
     buffer << CTag{"td"};
     buffer << CTag{"tr"};
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc
index 46c96e5..58b463a 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -2537,7 +2537,8 @@
 void AutofillMetrics::LogCreditCardSeamlessnessAtFillTime(
     const LogCreditCardSeamlessnessParam& p) {
   auto GetSeamlessness = [&p](bool only_newly_filled_fields,
-                              bool only_after_security_policy) {
+                              bool only_after_security_policy,
+                              bool only_visible_fields) {
     ServerFieldTypeSet autofilled_types;
     for (const auto& field : p.form) {
       FieldGlobalId id = field->global_id();
@@ -2545,6 +2546,8 @@
         continue;
       if (only_after_security_policy && !p.safe_fields.contains(id))
         continue;
+      if (only_visible_fields && !field->is_visible)
+        continue;
       autofilled_types.insert(field->Type().GetStorableType());
     }
     return CreditCardSeamlessness(autofilled_types);
@@ -2557,29 +2560,53 @@
                                   s.BitmaskExclusiveMax());
   };
 
-  if (auto s = GetSeamlessness(false, false)) {
+  if (auto s = GetSeamlessness(false, false, false)) {
     RecordUma("Fillable.AtFillTimeBeforeSecurityPolicy", s);
     p.builder.SetFillable_BeforeSecurity_Bitmask(s.BitmaskMetric());
     p.builder.SetFillable_BeforeSecurity_Qualitative(
         s.QualitativeMetricAsInt());
     p.event_logger.Log(s.QualitativeFillableFormEvent(), p.form);
   }
-  if (auto s = GetSeamlessness(false, true)) {
+  if (auto s = GetSeamlessness(false, true, false)) {
     RecordUma("Fillable.AtFillTimeAfterSecurityPolicy", s);
     p.builder.SetFillable_AfterSecurity_Bitmask(s.BitmaskMetric());
     p.builder.SetFillable_AfterSecurity_Qualitative(s.QualitativeMetricAsInt());
   }
-  if (auto s = GetSeamlessness(true, false)) {
+  if (auto s = GetSeamlessness(true, false, false)) {
     RecordUma("Fills.AtFillTimeBeforeSecurityPolicy", s);
     p.builder.SetFilled_BeforeSecurity_Bitmask(s.BitmaskMetric());
     p.builder.SetFilled_BeforeSecurity_Qualitative(s.QualitativeMetricAsInt());
   }
-  if (auto s = GetSeamlessness(true, true)) {
+  if (auto s = GetSeamlessness(true, true, false)) {
     RecordUma("Fills.AtFillTimeAfterSecurityPolicy", s);
     p.builder.SetFilled_AfterSecurity_Bitmask(s.BitmaskMetric());
     p.builder.SetFilled_AfterSecurity_Qualitative(s.QualitativeMetricAsInt());
     p.event_logger.Log(s.QualitativeFillFormEvent(), p.form);
   }
+  if (auto s = GetSeamlessness(false, false, true)) {
+    RecordUma("Fillable.AtFillTimeBeforeSecurityPolicy.Visible", s);
+    p.builder.SetFillable_BeforeSecurity_Visible_Bitmask(s.BitmaskMetric());
+    p.builder.SetFillable_BeforeSecurity_Visible_Qualitative(
+        s.QualitativeMetricAsInt());
+  }
+  if (auto s = GetSeamlessness(false, true, true)) {
+    RecordUma("Fillable.AtFillTimeAfterSecurityPolicy.Visible", s);
+    p.builder.SetFillable_AfterSecurity_Visible_Bitmask(s.BitmaskMetric());
+    p.builder.SetFillable_AfterSecurity_Visible_Qualitative(
+        s.QualitativeMetricAsInt());
+  }
+  if (auto s = GetSeamlessness(true, false, true)) {
+    RecordUma("Fills.AtFillTimeBeforeSecurityPolicy.Visible", s);
+    p.builder.SetFilled_BeforeSecurity_Visible_Bitmask(s.BitmaskMetric());
+    p.builder.SetFilled_BeforeSecurity_Visible_Qualitative(
+        s.QualitativeMetricAsInt());
+  }
+  if (auto s = GetSeamlessness(true, true, true)) {
+    RecordUma("Fills.AtFillTimeAfterSecurityPolicy.Visible", s);
+    p.builder.SetFilled_AfterSecurity_Visible_Bitmask(s.BitmaskMetric());
+    p.builder.SetFilled_AfterSecurity_Visible_Qualitative(
+        s.QualitativeMetricAsInt());
+  }
 
   // In a multi-frame form, a cross-origin field is filled only if
   // shared-autofill is enabled in the field's frame. Here, we log whether
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 51333e1..efaa5de 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/metrics/metrics_hashes.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
@@ -12249,7 +12250,8 @@
                  {.label = u"ExpDate",
                   .name = u"expdate",
                   .is_autofilled = false},
-                 {.label = u"CVC",
+                 {.is_visible = false,
+                  .label = u"CVC",
                   .name = u"cvc",
                   .is_autofilled = false,
                   .origin = other_origin},
@@ -12336,9 +12338,50 @@
   CreditCardAndCvc credit_card_with_cvc_;
 };
 
+// This fixture adds utilities for the seamlessness metric names.
+//
+// These metric names get very long, and with >16 variants the tests become
+// unreadable otherwise.
+class AutofillMetricsSeamlessnessTest
+    : public AutofillMetricsCrossFrameFormTest {
+ public:
+  struct MetricName {
+    enum class Fill { kFills, kFillable };
+    enum class Time { kBefore, kAfter, kSubmission };
+    enum class Visibility { kAll, kVisible };
+    enum class Variant { kQualitative, kBitmask };
+
+    Fill fill;
+    Time time;
+    Visibility visibility;
+    Variant variant;
+
+    std::string str() const {
+      return base::StringPrintf(
+          "Autofill.CreditCard.Seamless%s.%s%s%s",
+          fill == Fill::kFills ? "Fills" : "Fillable",
+          time == Time::kSubmission ? "AtSubmissionTime"
+          : time == Time::kBefore   ? "AtFillTimeBeforeSecurityPolicy"
+                                    : "AtFillTimeAfterSecurityPolicy",
+          visibility == Visibility::kAll ? "" : ".Visible",
+          variant == Variant::kQualitative ? "" : ".Bitmask");
+    }
+  };
+
+  static constexpr auto kFills = MetricName::Fill::kFills;
+  static constexpr auto kFillable = MetricName::Fill::kFillable;
+  static constexpr auto kBefore = MetricName::Time::kBefore;
+  static constexpr auto kAfter = MetricName::Time::kAfter;
+  static constexpr auto kSubmission = MetricName::Time::kSubmission;
+  static constexpr auto kAll = MetricName::Visibility::kAll;
+  static constexpr auto kVisible = MetricName::Visibility::kVisible;
+  static constexpr auto kQualitative = MetricName::Variant::kQualitative;
+  static constexpr auto kBitmask = MetricName::Variant::kBitmask;
+};
+
 // Tests that Autofill.CreditCard.SeamlessFills.* is not emitted for manual
 // fills.
-TEST_F(AutofillMetricsCrossFrameFormTest,
+TEST_F(AutofillMetricsSeamlessnessTest,
        DoNotLogCreditCardSeamlessFillsMetricIfNotAutofilled) {
   using UkmBuilder = ukm::builders::Autofill_CreditCardFill;
   base::HistogramTester histogram_tester;
@@ -12356,38 +12399,22 @@
   SubmitForm();
   ResetDriverToCommitMetrics();
 
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy", 0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy."
-      "Bitmask",
-      0);
-
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy", 0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy.Bitmask",
-      0);
-
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy", 0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFillable.AtFillTimeBeforeSecurityPolicy."
-      "Bitmask",
-      0);
-
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy", 0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy."
-      "Bitmask",
-      0);
+  for (auto fill : {kFills, kFillable}) {
+    for (auto time : {kBefore, kAfter, kSubmission}) {
+      for (auto visibility : {kAll, kVisible}) {
+        for (auto variant : {kQualitative, kBitmask}) {
+          histogram_tester.ExpectTotalCount(
+              MetricName{fill, time, visibility, variant}.str(), 0);
+        }
+      }
+    }
+  }
 
   VerifyUkm(test_ukm_recorder_, form_, UkmBuilder::kEntryName, {});
 }
 
 // Tests that Autofill.CreditCard.SeamlessFills.* are emitted.
-TEST_F(AutofillMetricsCrossFrameFormTest,
+TEST_F(AutofillMetricsSeamlessnessTest,
        LogCreditCardSeamlessFillsMetricIfAutofilledWithoutCvc) {
   using Metric = AutofillMetrics::CreditCardSeamlessness::Metric;
   using UkmBuilder = ukm::builders::Autofill_CreditCardFill;
@@ -12410,8 +12437,8 @@
   };
 
   base::HistogramTester histogram_tester;
-  auto SamplesOf = [&histogram_tester](base::StringPiece metric) {
-    return histogram_tester.GetAllSamples(metric);
+  auto SamplesOf = [&histogram_tester](MetricName metric) {
+    return histogram_tester.GetAllSamples(metric.str());
   };
 
   SeeForm();
@@ -12424,6 +12451,7 @@
   // - after security  and assuming a complete profile: kPartialFill;
   // - after security  and without a CVC:               kPartialFill;
   // because due to the security policy, only NAME and EXP_DATE are filled.
+  // The CVC field is invisible.
   FillForm(form_.fields[0]);
   SetFormValues({CREDIT_CARD_NAME_FULL, CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
                 /*is_autofilled=*/true, /*is_user_typed=*/false);
@@ -12435,6 +12463,7 @@
   // - after security  and without a CVC:               kPartialFill;
   // because the due to the security policy, only NUMBER and CVC could be
   // filled.
+  // The CVC field is invisible.
   FillForm(form_.fields[1]);
   SetFormValues({CREDIT_CARD_NUMBER},
                 /*is_autofilled=*/true, /*is_user_typed=*/false);
@@ -12442,47 +12471,51 @@
   SubmitForm();
   ResetDriverToCommitMetrics();
 
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFillable."
-                        "AtFillTimeBeforeSecurityPolicy"),
-              BucketsAre(Bucket(Metric::kFullFill, 2)));
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFillable."
-                        "AtFillTimeBeforeSecurityPolicy"),
-              BucketsAre(Bucket(Metric::kFullFill, 2)));
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFillable."
-                        "AtFillTimeBeforeSecurityPolicy.Bitmask"),
+  // Bitmask metrics.
+  EXPECT_THAT(SamplesOf({kFillable, kBefore, kAll, kBitmask}),
               BucketsAre(Bucket(kName | kNumber | kExp | kCvc, 2)));
-
-  EXPECT_THAT(
-      SamplesOf(
-          "Autofill.CreditCard.SeamlessFillable.AtFillTimeAfterSecurityPolicy"),
-      BucketsAre(Bucket(Metric::kPartialFill, 2)));
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFillable."
-                        "AtFillTimeAfterSecurityPolicy.Bitmask"),
+  EXPECT_THAT(SamplesOf({kFillable, kAfter, kAll, kBitmask}),
               BucketsAre(Bucket(kName | kExp, 1), Bucket(kNumber | kCvc, 1)));
-
   EXPECT_THAT(
-      SamplesOf(
-          "Autofill.CreditCard.SeamlessFills.AtFillTimeBeforeSecurityPolicy"),
-      BucketsAre(Bucket(Metric::kOptionalCvcMissing, 1),
-                 Bucket(Metric::kPartialFill, 1)));
-  EXPECT_THAT(
-      SamplesOf("Autofill.CreditCard.SeamlessFills."
-                "AtFillTimeBeforeSecurityPolicy.Bitmask"),
+      SamplesOf({kFills, kBefore, kAll, kBitmask}),
       BucketsAre(Bucket(kName | kNumber | kExp, 1), Bucket(kNumber, 1)));
-
+  EXPECT_THAT(SamplesOf({kFills, kAfter, kAll, kBitmask}),
+              BucketsAre(Bucket(kName | kExp, 1), Bucket(kNumber, 1)));
+  EXPECT_THAT(SamplesOf({kFills, kSubmission, kAll, kBitmask}),
+              BucketsAre(Bucket(kName | kNumber | kExp, 1)));
+  // Bitmask metrics restricted to visible fields.
+  EXPECT_THAT(SamplesOf({kFillable, kBefore, kVisible, kBitmask}),
+              BucketsAre(Bucket(kName | kNumber | kExp, 2)));
+  EXPECT_THAT(SamplesOf({kFillable, kAfter, kVisible, kBitmask}),
+              BucketsAre(Bucket(kName | kExp, 1), Bucket(kNumber, 1)));
   EXPECT_THAT(
-      SamplesOf(
-          "Autofill.CreditCard.SeamlessFills.AtFillTimeAfterSecurityPolicy"),
-      BucketsAre(Bucket(Metric::kPartialFill, 2)));
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFills."
-                        "AtFillTimeAfterSecurityPolicy.Bitmask"),
+      SamplesOf({kFills, kBefore, kVisible, kBitmask}),
+      BucketsAre(Bucket(kName | kNumber | kExp, 1), Bucket(kNumber, 1)));
+  EXPECT_THAT(SamplesOf({kFills, kAfter, kVisible, kBitmask}),
               BucketsAre(Bucket(kName | kExp, 1), Bucket(kNumber, 1)));
 
-  EXPECT_THAT(SamplesOf("Autofill.CreditCard.SeamlessFills.AtSubmissionTime"),
+  // Qualitative metrics.
+  EXPECT_THAT(SamplesOf({kFillable, kBefore, kAll, kQualitative}),
+              BucketsAre(Bucket(Metric::kFullFill, 2)));
+  EXPECT_THAT(SamplesOf({kFillable, kAfter, kAll, kQualitative}),
+              BucketsAre(Bucket(Metric::kPartialFill, 2)));
+  EXPECT_THAT(SamplesOf({kFills, kBefore, kAll, kQualitative}),
+              BucketsAre(Bucket(Metric::kOptionalCvcMissing, 1),
+                         Bucket(Metric::kPartialFill, 1)));
+  EXPECT_THAT(SamplesOf({kFills, kAfter, kAll, kQualitative}),
+              BucketsAre(Bucket(Metric::kPartialFill, 2)));
+  EXPECT_THAT(SamplesOf({kFills, kSubmission, kAll, kQualitative}),
               BucketsAre(Bucket(Metric::kOptionalCvcMissing, 1)));
-  EXPECT_THAT(
-      SamplesOf("Autofill.CreditCard.SeamlessFills.AtSubmissionTime.Bitmask"),
-      BucketsAre(Bucket(kName | kNumber | kExp, 1)));
+  // Qualitative metrics restricted to visible fields.
+  EXPECT_THAT(SamplesOf({kFillable, kBefore, kVisible, kQualitative}),
+              BucketsAre(Bucket(Metric::kOptionalCvcMissing, 2)));
+  EXPECT_THAT(SamplesOf({kFillable, kAfter, kVisible, kQualitative}),
+              BucketsAre(Bucket(Metric::kPartialFill, 2)));
+  EXPECT_THAT(SamplesOf({kFills, kBefore, kVisible, kQualitative}),
+              BucketsAre(Bucket(Metric::kOptionalCvcMissing, 1),
+                         Bucket(Metric::kPartialFill, 1)));
+  EXPECT_THAT(SamplesOf({kFills, kAfter, kVisible, kQualitative}),
+              BucketsAre(Bucket(Metric::kPartialFill, 2)));
 
   VerifyUkm(
       test_ukm_recorder_, form_, UkmBuilder::kEntryName,
@@ -12500,6 +12533,24 @@
             kName | kNumber | kExp},
            {UkmBuilder::kFilled_AfterSecurity_BitmaskName, kName | kExp},
 
+           {UkmBuilder::kFillable_BeforeSecurity_Visible_QualitativeName,
+            kOptionalCvcMissing},
+           {UkmBuilder::kFillable_AfterSecurity_Visible_QualitativeName,
+            kPartialFill},
+           {UkmBuilder::kFilled_BeforeSecurity_Visible_QualitativeName,
+            kOptionalCvcMissing},
+           {UkmBuilder::kFilled_AfterSecurity_Visible_QualitativeName,
+            kPartialFill},
+
+           {UkmBuilder::kFillable_BeforeSecurity_Visible_BitmaskName,
+            kName | kNumber | kExp},
+           {UkmBuilder::kFillable_AfterSecurity_Visible_BitmaskName,
+            kName | kExp},
+           {UkmBuilder::kFilled_BeforeSecurity_Visible_BitmaskName,
+            kName | kNumber | kExp},
+           {UkmBuilder::kFilled_AfterSecurity_Visible_BitmaskName,
+            kName | kExp},
+
            {UkmBuilder::kSharedAutofillName, kSharedAutofillWouldHelp},
 
            {UkmBuilder::kFormSignatureName,
@@ -12517,6 +12568,21 @@
            {UkmBuilder::kFilled_BeforeSecurity_BitmaskName, kNumber},
            {UkmBuilder::kFilled_AfterSecurity_BitmaskName, kNumber},
 
+           {UkmBuilder::kFillable_BeforeSecurity_Visible_QualitativeName,
+            kOptionalCvcMissing},
+           {UkmBuilder::kFillable_AfterSecurity_Visible_QualitativeName,
+            kPartialFill},
+           {UkmBuilder::kFilled_BeforeSecurity_Visible_QualitativeName,
+            kPartialFill},
+           {UkmBuilder::kFilled_AfterSecurity_Visible_QualitativeName,
+            kPartialFill},
+
+           {UkmBuilder::kFillable_BeforeSecurity_Visible_BitmaskName,
+            kName | kNumber | kExp},
+           {UkmBuilder::kFillable_AfterSecurity_Visible_BitmaskName, kNumber},
+           {UkmBuilder::kFilled_BeforeSecurity_Visible_BitmaskName, kNumber},
+           {UkmBuilder::kFilled_AfterSecurity_Visible_BitmaskName, kNumber},
+
            {UkmBuilder::kSharedAutofillName, kSharedAutofillIsIrrelevant},
 
            {UkmBuilder::kFormSignatureName,
diff --git a/components/autofill/core/common/form_field_data.h b/components/autofill/core/common/form_field_data.h
index 381b0528..de784bca 100644
--- a/components/autofill/core/common/form_field_data.h
+++ b/components/autofill/core/common/form_field_data.h
@@ -207,6 +207,7 @@
   bool is_autofilled = false;
   CheckStatus check_status = CheckStatus::kNotCheckable;
   bool is_focusable = true;
+  bool is_visible = true;
   bool should_autocomplete = true;
   RoleAttribute role = RoleAttribute::kOther;
   base::i18n::TextDirection text_direction = base::i18n::UNKNOWN_DIRECTION;
@@ -258,6 +259,7 @@
 
 // Prefer to use this macro in place of |EXPECT_EQ()| for comparing
 // |FormFieldData|s in test code.
+// TODO(crbug.com/1208354): Replace this with FormData::DeepEqual().
 #define EXPECT_FORM_FIELD_DATA_EQUALS(expected, actual)                        \
   do {                                                                         \
     EXPECT_EQ_UNIQUE_ID(expected, actual);                                     \
diff --git a/components/autofill/core/common/mojom/autofill_types.mojom b/components/autofill/core/common/mojom/autofill_types.mojom
index 249aaa6e..609485f 100644
--- a/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/components/autofill/core/common/mojom/autofill_types.mojom
@@ -189,6 +189,7 @@
   string section;
   CheckStatus check_status;
   bool is_focusable;
+  bool is_visible;
   bool should_autocomplete;
   RoleAttribute role;
   mojo_base.mojom.TextDirection text_direction;
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 3944958..88fe33bc 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -120,6 +120,7 @@
     return false;
 
   out->is_focusable = data.is_focusable();
+  out->is_visible = data.is_visible();
   out->should_autocomplete = data.should_autocomplete();
 
   if (!data.ReadRole(&out->role))
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 0d882e6..9060cf6 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -181,6 +181,10 @@
     return r.is_focusable;
   }
 
+  static bool is_visible(const autofill::FormFieldData& r) {
+    return r.is_visible;
+  }
+
   static bool should_autocomplete(const autofill::FormFieldData& r) {
     return r.should_autocomplete;
   }
diff --git a/components/background_fetch/background_fetch_delegate_base.cc b/components/background_fetch/background_fetch_delegate_base.cc
index 9e1a767..e3994b9 100644
--- a/components/background_fetch/background_fetch_delegate_base.cc
+++ b/components/background_fetch/background_fetch_delegate_base.cc
@@ -101,6 +101,7 @@
                           weak_ptr_factory_.GetWeakPtr());
   params.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
+  params.request_params.update_first_party_url_on_redirect = false;
 
   JobDetails* job_details = GetJobDetails(job_id);
   if (job_details->job_state == JobDetails::State::kPendingWillStartPaused ||
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index abb5f66f..7539d7e 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "10.18",
-  "log_list_timestamp": "2022-06-20T12:58:57Z",
+  "version": "10.19",
+  "log_list_timestamp": "2022-06-21T12:54:51Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 2b2da55b..b207ce5 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -229,6 +229,8 @@
     download_url_params->set_isolation_info(
         request_params.isolation_info.value());
   }
+  download_url_params->set_update_first_party_url_on_redirect(
+      request_params.update_first_party_url_on_redirect);
 
   download_manager_coordinator_->DownloadUrl(std::move(download_url_params));
 }
diff --git a/components/download/internal/common/download_utils.cc b/components/download/internal/common/download_utils.cc
index 11f52486..45432672 100644
--- a/components/download/internal/common/download_utils.cc
+++ b/components/download/internal/common/download_utils.cc
@@ -386,8 +386,10 @@
     // cross-site URL has been visited before.
     url::Origin origin = url::Origin::Create(params->url());
     request->trusted_params->isolation_info = net::IsolationInfo::Create(
-        net::IsolationInfo::RequestType::kMainFrame, origin, origin,
-        net::SiteForCookies::FromOrigin(origin));
+        params->update_first_party_url_on_redirect()
+            ? net::IsolationInfo::RequestType::kMainFrame
+            : net::IsolationInfo::RequestType::kOther,
+        origin, origin, net::SiteForCookies::FromOrigin(origin));
     request->site_for_cookies = net::SiteForCookies::FromUrl(params->url());
   }
 
@@ -395,7 +397,8 @@
   request->referrer = params->referrer();
   request->referrer_policy = params->referrer_policy();
   request->is_outermost_main_frame = true;
-  request->update_first_party_url_on_redirect = true;
+  request->update_first_party_url_on_redirect =
+      params->update_first_party_url_on_redirect();
 
   // Downloads should be treated as navigations from Fetch spec perspective.
   // See also:
diff --git a/components/download/public/background_service/download_params.h b/components/download/public/background_service/download_params.h
index 8b911276..a976d47 100644
--- a/components/download/public/background_service/download_params.h
+++ b/components/download/public/background_service/download_params.h
@@ -126,6 +126,12 @@
   // be invalidate during download resumption in new browser session. Not
   // supported on iOS.
   absl::optional<net::IsolationInfo> isolation_info;
+
+  // First-party URL redirect policy: During server redirects, whether the
+  // first-party URL for cookies will need to be changed. Download is normally
+  // considered a main frame navigation. However, this is not true for
+  // background fetch.
+  bool update_first_party_url_on_redirect = true;
 };
 
 // The parameters that describe a download request made to the DownloadService.
diff --git a/components/download/public/common/download_url_parameters.cc b/components/download/public/common/download_url_parameters.cc
index 3dec7148..25ea6f13 100644
--- a/components/download/public/common/download_url_parameters.cc
+++ b/components/download/public/common/download_url_parameters.cc
@@ -34,7 +34,8 @@
       traffic_annotation_(traffic_annotation),
       download_source_(DownloadSource::UNKNOWN),
       require_safety_checks_(true),
-      has_user_gesture_(false) {}
+      has_user_gesture_(false),
+      update_first_party_url_on_redirect_(true) {}
 
 DownloadUrlParameters::~DownloadUrlParameters() = default;
 
diff --git a/components/download/public/common/download_url_parameters.h b/components/download/public/common/download_url_parameters.h
index ba0a03c..61eb9af 100644
--- a/components/download/public/common/download_url_parameters.h
+++ b/components/download/public/common/download_url_parameters.h
@@ -279,6 +279,11 @@
     has_user_gesture_ = has_user_gesture;
   }
 
+  void set_update_first_party_url_on_redirect(
+      bool update_first_party_url_on_redirect) {
+    update_first_party_url_on_redirect_ = update_first_party_url_on_redirect;
+  }
+
   OnStartedCallback& callback() { return callback_; }
   bool content_initiated() const { return content_initiated_; }
   const std::string& last_modified() const { return last_modified_; }
@@ -335,6 +340,9 @@
     return isolation_info_;
   }
   bool has_user_gesture() const { return has_user_gesture_; }
+  bool update_first_party_url_on_redirect() const {
+    return update_first_party_url_on_redirect_;
+  }
 
   // STATE CHANGING: All save_info_ sub-objects will be in an indeterminate
   // state following this call.
@@ -383,6 +391,7 @@
   bool require_safety_checks_;
   absl::optional<net::IsolationInfo> isolation_info_;
   bool has_user_gesture_;
+  bool update_first_party_url_on_redirect_;
 };
 
 }  // namespace download
diff --git a/components/installedapp/android/BUILD.gn b/components/installedapp/android/BUILD.gn
index e8d8b20..2c772db 100644
--- a/components/installedapp/android/BUILD.gn
+++ b/components/installedapp/android/BUILD.gn
@@ -44,7 +44,7 @@
   ]
 }
 
-android_library("javatests") {
+android_library("unit_device_javatests") {
   testonly = true
 
   sources = [ "java/src/org/chromium/components/installedapp/InstalledAppProviderTest.java" ]
diff --git a/components/os_crypt/os_crypt_win.cc b/components/os_crypt/os_crypt_win.cc
index 305a8ca..018a4322 100644
--- a/components/os_crypt/os_crypt_win.cc
+++ b/components/os_crypt/os_crypt_win.cc
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/wincrypt_shim.h"
@@ -42,9 +43,14 @@
       const_cast<BYTE*>(reinterpret_cast<const BYTE*>(plaintext.data()));
   input.cbData = static_cast<DWORD>(plaintext.length());
 
+  BOOL result = FALSE;
   DATA_BLOB output;
-  const BOOL result =
-      CryptProtectData(&input, L"", nullptr, nullptr, nullptr, 0, &output);
+  {
+    SCOPED_UMA_HISTOGRAM_TIMER("OSCrypt.Win.Encrypt.Time");
+    result =
+        CryptProtectData(&input, L"", nullptr, nullptr, nullptr, 0, &output);
+  }
+  base::UmaHistogramBoolean("OSCrypt.Win.Encrypt.Result", result);
   if (!result) {
     PLOG(ERROR) << "Failed to encrypt";
     return false;
@@ -65,9 +71,14 @@
       const_cast<BYTE*>(reinterpret_cast<const BYTE*>(ciphertext.data()));
   input.cbData = static_cast<DWORD>(ciphertext.length());
 
+  BOOL result = FALSE;
   DATA_BLOB output;
-  const BOOL result = CryptUnprotectData(&input, nullptr, nullptr, nullptr,
-                                         nullptr, 0, &output);
+  {
+    SCOPED_UMA_HISTOGRAM_TIMER("OSCrypt.Win.Decrypt.Time");
+    result = CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr, 0,
+                                &output);
+  }
+  base::UmaHistogramBoolean("OSCrypt.Win.Decrypt.Result", result);
   if (!result) {
     PLOG(ERROR) << "Failed to decrypt";
     return false;
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index b0c5f4d..9fe9887 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -120,7 +120,7 @@
     return true;
 
   // Filter the list, rejecting any invalid strings.
-  base::Value::ConstListView list = value->GetListDeprecated();
+  const base::Value::List& list = value->GetList();
   if (filtered_list)
     *filtered_list = base::Value(base::Value::Type::LIST);
   for (size_t list_index = 0; list_index < list.size(); ++list_index) {
@@ -142,7 +142,7 @@
     }
 
     if (filtered_list)
-      filtered_list->Append(entry.Clone());
+      filtered_list->GetList().Append(entry.Clone());
   }
 
   return true;
@@ -539,7 +539,7 @@
 
   // If that succeeds, validate all the list items are strings and validate
   // the JSON inside the strings.
-  base::Value::ConstListView list = root_value->GetListDeprecated();
+  const base::Value::List& list = root_value->GetList();
   bool json_error_seen = false;
 
   for (size_t index = 0; index < list.size(); ++index) {
diff --git a/components/policy/core/browser/configuration_policy_handler_list_unittest.cc b/components/policy/core/browser/configuration_policy_handler_list_unittest.cc
index aaf0602..070d45a 100644
--- a/components/policy/core/browser/configuration_policy_handler_list_unittest.cc
+++ b/components/policy/core/browser/configuration_policy_handler_list_unittest.cc
@@ -148,10 +148,10 @@
                       /* in_deprecated */ false, /* in_future */ true);
 
   // Whitelist a different policy.
-  base::Value::ListStorage enabled_future_policies;
-  enabled_future_policies.push_back(base::Value(kPolicyName2));
+  base::Value::List enabled_future_policies;
+  enabled_future_policies.Append(kPolicyName2);
   AddPolicy(key::kEnableExperimentalPolicies, /* is_cloud */ true,
-            base::Value(enabled_future_policies));
+            base::Value(enabled_future_policies.Clone()));
 
   ApplySettings();
 
@@ -159,9 +159,9 @@
                       /* in_deprecated */ false, /* in_future */ true);
 
   // Whitelist the policy.
-  enabled_future_policies.push_back(base::Value(kPolicyName));
+  enabled_future_policies.Append(base::Value(kPolicyName));
   AddPolicy(key::kEnableExperimentalPolicies, /* is_cloud */ true,
-            base::Value(enabled_future_policies));
+            base::Value(std::move(enabled_future_policies)));
 
   ApplySettings();
 
diff --git a/components/policy/core/browser/policy_conversions_client_unittest.cc b/components/policy/core/browser/policy_conversions_client_unittest.cc
index 2f904fa..3c2ac60 100644
--- a/components/policy/core/browser/policy_conversions_client_unittest.cc
+++ b/components/policy/core/browser/policy_conversions_client_unittest.cc
@@ -47,7 +47,7 @@
     PolicyMap::Entry entry(policy::POLICY_LEVEL_MANDATORY,
                            policy::POLICY_SCOPE_MACHINE,
                            policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
-                           base::Value(std::vector<base::Value>()), nullptr);
+                           base::Value(base::Value::List()), nullptr);
     if (set_is_default)
       entry.SetIsDefaultValue();
     return entry;
diff --git a/components/policy/core/browser/policy_pref_mapping_test.cc b/components/policy/core/browser/policy_pref_mapping_test.cc
index a212bb2..b09dad9 100644
--- a/components/policy/core/browser/policy_pref_mapping_test.cc
+++ b/components/policy/core/browser/policy_pref_mapping_test.cc
@@ -223,8 +223,7 @@
     const base::Value* required_preprocessor_macros_value =
         mapping.FindListKey("required_preprocessor_macros");
     if (required_preprocessor_macros_value) {
-      for (const auto& macro :
-           required_preprocessor_macros_value->GetListDeprecated())
+      for (const auto& macro : required_preprocessor_macros_value->GetList())
         required_preprocessor_macros_.push_back(macro.GetString());
     }
   }
diff --git a/components/policy/core/browser/url_allowlist_policy_handler.cc b/components/policy/core/browser/url_allowlist_policy_handler.cc
index 3ff2ac2f..ce015d62 100644
--- a/components/policy/core/browser/url_allowlist_policy_handler.cc
+++ b/components/policy/core/browser/url_allowlist_policy_handler.cc
@@ -83,10 +83,10 @@
     return;
   }
 
-  std::vector<base::Value> filtered_url_allowlist;
-  for (const auto& entry : url_allowlist->GetListDeprecated()) {
+  base::Value::List filtered_url_allowlist;
+  for (const auto& entry : url_allowlist->GetList()) {
     if (entry.is_string())
-      filtered_url_allowlist.push_back(entry.Clone());
+      filtered_url_allowlist.Append(entry.Clone());
   }
 
   prefs->SetValue(policy_prefs::kUrlAllowlist,
diff --git a/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc b/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc
index 36657a6..0b4bc8f 100644
--- a/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc
+++ b/components/policy/core/browser/url_allowlist_policy_handler_unittest.cc
@@ -48,9 +48,9 @@
     return handler_->ValidatePolicy(policy);
   }
   base::Value GetURLAllowlistPolicyValueWithEntries(size_t len) {
-    std::vector<base::Value> allowlist(len);
-    for (auto& entry : allowlist)
-      entry = base::Value(kTestAllowlistValue);
+    base::Value::List allowlist;
+    for (size_t i = 0; i < len; ++i)
+      allowlist.Append(kTestAllowlistValue);
     return base::Value(std::move(allowlist));
   }
 
diff --git a/components/policy/core/browser/url_blocklist_policy_handler.cc b/components/policy/core/browser/url_blocklist_policy_handler.cc
index d701df8..ccd670e 100644
--- a/components/policy/core/browser/url_blocklist_policy_handler.cc
+++ b/components/policy/core/browser/url_blocklist_policy_handler.cc
@@ -101,27 +101,26 @@
   const base::Value* disabled_schemes_policy =
       policies.GetValue(key::kDisabledSchemes, base::Value::Type::LIST);
 
-  absl::optional<std::vector<base::Value>> merged_url_blocklist;
+  absl::optional<base::Value::List> merged_url_blocklist;
 
   // We start with the DisabledSchemes because we have size limit when
   // handling URLBlocklists.
   if (disabled_schemes_policy) {
-    merged_url_blocklist = std::vector<base::Value>();
-    for (const auto& entry : disabled_schemes_policy->GetListDeprecated()) {
+    merged_url_blocklist.emplace();
+    for (const auto& entry : disabled_schemes_policy->GetList()) {
       if (entry.is_string()) {
-        merged_url_blocklist->emplace_back(
-            base::StrCat({entry.GetString(), "://*"}));
+        merged_url_blocklist->Append(base::StrCat({entry.GetString(), "://*"}));
       }
     }
   }
 
   if (url_blocklist_policy) {
     if (!merged_url_blocklist)
-      merged_url_blocklist = std::vector<base::Value>();
+      merged_url_blocklist.emplace();
 
-    for (const auto& entry : url_blocklist_policy->GetListDeprecated()) {
+    for (const auto& entry : url_blocklist_policy->GetList()) {
       if (entry.is_string())
-        merged_url_blocklist->push_back(entry.Clone());
+        merged_url_blocklist->Append(entry.Clone());
     }
   }
 
diff --git a/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc b/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc
index b693f46..c83e91a 100644
--- a/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc
+++ b/components/policy/core/browser/url_blocklist_policy_handler_unittest.cc
@@ -54,9 +54,9 @@
     return handler_->ValidatePolicy(policy);
   }
   base::Value GetURLBlocklistPolicyValueWithEntries(size_t len) {
-    std::vector<base::Value> blocklist(len);
-    for (auto& entry : blocklist)
-      entry = base::Value(kTestBlocklistValue);
+    base::Value::List blocklist;
+    for (size_t i = 0; i < len; ++i)
+      blocklist.Append(kTestBlocklistValue);
     return base::Value(std::move(blocklist));
   }
 
diff --git a/components/policy/core/browser/url_scheme_list_policy_handler.cc b/components/policy/core/browser/url_scheme_list_policy_handler.cc
index 5b6f4dc..ff31536 100644
--- a/components/policy/core/browser/url_scheme_list_policy_handler.cc
+++ b/components/policy/core/browser/url_scheme_list_policy_handler.cc
@@ -68,13 +68,14 @@
       policies.GetValue(policy_name(), base::Value::Type::LIST);
   if (!schemes)
     return;
-  std::vector<base::Value> filtered_schemes;
-  for (const auto& entry : schemes->GetListDeprecated()) {
+  base::Value::List filtered_schemes;
+  for (const auto& entry : schemes->GetList()) {
+    if (filtered_schemes.size() >= policy::kMaxUrlFiltersPerPolicy)
+      break;
+
     if (ValidatePolicyEntry(entry.GetIfString()))
-      filtered_schemes.push_back(entry.Clone());
+      filtered_schemes.Append(entry.Clone());
   }
-  if (filtered_schemes.size() > policy::kMaxUrlFiltersPerPolicy)
-    filtered_schemes.resize(policy::kMaxUrlFiltersPerPolicy);
 
   prefs->SetValue(pref_path_, base::Value(std::move(filtered_schemes)));
 }
diff --git a/components/policy/core/browser/url_scheme_list_policy_handler_unittest.cc b/components/policy/core/browser/url_scheme_list_policy_handler_unittest.cc
index 6199210..d48a888 100644
--- a/components/policy/core/browser/url_scheme_list_policy_handler_unittest.cc
+++ b/components/policy/core/browser/url_scheme_list_policy_handler_unittest.cc
@@ -52,9 +52,9 @@
   }
   void ApplyPolicies() { handler_->ApplyPolicySettings(policies_, &prefs_); }
   base::Value GetPolicyValueWithEntries(size_t len) {
-    std::vector<base::Value> blocklist(len);
-    for (auto& entry : blocklist)
-      entry = base::Value(kTestUrl);
+    base::Value::List blocklist;
+    for (size_t i = 0; i < len; ++i)
+      blocklist.Append(kTestUrl);
     return base::Value(std::move(blocklist));
   }
 
diff --git a/components/policy/core/common/android/policy_map_android_unittest.cc b/components/policy/core/common/android/policy_map_android_unittest.cc
index 1413bef..ee8a383 100644
--- a/components/policy/core/common/android/policy_map_android_unittest.cc
+++ b/components/policy/core/common/android/policy_map_android_unittest.cc
@@ -92,10 +92,10 @@
 TEST_F(PolicyMapAndroidTest, ListPolicy) {
   Java_PolicyMapTestSupporter_verifyListPolicy(env_, j_support_,
                                                policy_name_android_, nullptr);
-  std::vector<base::Value> value;
-  value.push_back(base::Value("value-1"));
-  value.push_back(base::Value("value-2"));
-  SetPolicy(base::Value(value));
+  base::Value::List value;
+  value.Append("value-1");
+  value.Append("value-2");
+  SetPolicy(base::Value(std::move(value)));
   Java_PolicyMapTestSupporter_verifyListPolicy(
       env_, j_support_, policy_name_android_,
       base::android::ConvertUTF8ToJavaString(env_, R"(["value-1","value-2"])"));
diff --git a/components/policy/core/common/policy_loader_command_line_unittest.cc b/components/policy/core/common/policy_loader_command_line_unittest.cc
index 281fac8..3c60db30 100644
--- a/components/policy/core/common/policy_loader_command_line_unittest.cc
+++ b/components/policy/core/common/policy_loader_command_line_unittest.cc
@@ -75,22 +75,23 @@
     "list_policy": [1,2],
     "dict_policy": {"k1":1, "k2": {"k3":true}}
   })");
-  base::Value policies(base::Value::Type::DICTIONARY);
-  policies.SetIntKey("int_policy", 42);
-  policies.SetStringKey("string_policy", "string");
-  policies.SetBoolKey("bool_policy", true);
+  base::Value::Dict policies;
+  policies.Set("int_policy", 42);
+  policies.Set("string_policy", "string");
+  policies.Set("bool_policy", true);
 
   // list policy
-  base::Value::ListStorage list_storage;
-  list_storage.emplace_back(1);
-  list_storage.emplace_back(2);
-  policies.SetKey("list_policy", base::Value(list_storage));
+  base::Value::List list;
+  list.Append(1);
+  list.Append(2);
+  policies.Set("list_policy", std::move(list));
 
   // dict policy
-  policies.SetIntPath({"dict_policy.k1"}, 1);
-  policies.SetBoolPath({"dict_policy.k2.k3"}, true);
+  policies.SetByDottedPath("dict_policy.k1", 1);
+  policies.SetByDottedPath("dict_policy.k2.k3", true);
 
-  LoadAndVerifyPolicies(CreatePolicyLoader().get(), policies);
+  LoadAndVerifyPolicies(CreatePolicyLoader().get(),
+                        base::Value(std::move(policies)));
 }
 
 }  // namespace policy
diff --git a/components/policy/core/common/policy_loader_common_unittest.cc b/components/policy/core/common/policy_loader_common_unittest.cc
index 92c3ecd7..729ab4b 100644
--- a/components/policy/core/common/policy_loader_common_unittest.cc
+++ b/components/policy/core/common/policy_loader_common_unittest.cc
@@ -17,11 +17,12 @@
 namespace policy {
 namespace {
 base::Value ToListValue(const std::vector<std::string>& values) {
-  base::Value::ListStorage storage(values.size());
-  std::transform(values.begin(), values.end(), storage.begin(),
-                 [](const auto& value) { return base::Value(value); });
+  base::Value::List storage;
+  storage.reserve(values.size());
+  for (const auto& value : values)
+    storage.Append(value);
 
-  return base::Value(storage);
+  return base::Value(std::move(storage));
 }
 
 base::Value ToDictValue(const std::string& json) {
diff --git a/components/policy/core/common/policy_loader_win_unittest.cc b/components/policy/core/common/policy_loader_win_unittest.cc
index 23a176e..b5a92583 100644
--- a/components/policy/core/common/policy_loader_win_unittest.cc
+++ b/components/policy/core/common/policy_loader_win_unittest.cc
@@ -110,9 +110,9 @@
     case base::Value::Type::LIST: {
       if (!value.is_list())
         return false;
-      const base::Value::ConstListView& list_view = value.GetListDeprecated();
-      for (size_t i = 0; i < list_view.size(); ++i) {
-        if (!InstallValue(list_view[i], hive, path + kPathSep + name,
+      const base::Value::List& list = value.GetList();
+      for (size_t i = 0; i < list.size(); ++i) {
+        if (!InstallValue(list[i], hive, path + kPathSep + name,
                           base::NumberToWString(i + 1))) {
           return false;
         }
diff --git a/components/policy/core/common/policy_map_unittest.cc b/components/policy/core/common/policy_map_unittest.cc
index 6501adf..453fe38 100644
--- a/components/policy/core/common/policy_map_unittest.cc
+++ b/components/policy/core/common/policy_map_unittest.cc
@@ -53,10 +53,10 @@
 }
 
 template <class T>
-std::vector<base::Value> GetListStorage(const std::vector<T> entry) {
-  std::vector<base::Value> result;
+base::Value::List GetList(const std::vector<T>& entry) {
+  base::Value::List result;
   for (const auto& it : entry)
-    result.emplace_back(base::Value(it));
+    result.Append(it);
   return result;
 }
 
@@ -486,90 +486,91 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 TEST_F(PolicyMapTest, MergeValuesList) {
-  std::vector<base::Value> abcd =
-      GetListStorage<std::string>({"a", "b", "c", "d"});
-  std::vector<base::Value> abc = GetListStorage<std::string>({"a", "b", "c"});
-  std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"});
-  std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"});
-  std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"});
+  base::Value::List abcd = GetList<std::string>({"a", "b", "c", "d"});
+  base::Value::List abc = GetList<std::string>({"a", "b", "c"});
+  base::Value::List ab = GetList<std::string>({"a", "b"});
+  base::Value::List cd = GetList<std::string>({"c", "d"});
+  base::Value::List ef = GetList<std::string>({"e", "f"});
 
-  std::vector<base::Value> int12 = GetListStorage<int>({1, 2});
-  std::vector<base::Value> int34 = GetListStorage<int>({3, 4});
-  std::vector<base::Value> int56 = GetListStorage<int>({5, 6});
-  std::vector<base::Value> int1234 = GetListStorage<int>({1, 2, 3, 4});
+  base::Value::List int12 = GetList<int>({1, 2});
+  base::Value::List int34 = GetList<int>({3, 4});
+  base::Value::List int56 = GetList<int>({5, 6});
+  base::Value::List int1234 = GetList<int>({1, 2, 3, 4});
 
-  base::Value dict_ab(base::Value::Type::DICTIONARY);
-  dict_ab.SetBoolKey("a", true);
-  dict_ab.SetBoolKey("b", false);
-  base::Value dict_c(base::Value::Type::DICTIONARY);
-  dict_c.SetBoolKey("c", false);
-  base::Value dict_d(base::Value::Type::DICTIONARY);
-  dict_d.SetBoolKey("d", false);
+  base::Value::Dict dict_ab;
+  dict_ab.Set("a", true);
+  dict_ab.Set("b", false);
+  base::Value::Dict dict_c;
+  dict_c.Set("c", false);
+  base::Value::Dict dict_d;
+  dict_d.Set("d", false);
 
-  std::vector<base::Value> list_dict_abd;
-  list_dict_abd.emplace_back(dict_ab.Clone());
-  list_dict_abd.emplace_back(dict_d.Clone());
-  std::vector<base::Value> list_dict_c;
-  list_dict_c.emplace_back(dict_c.Clone());
+  base::Value::List list_dict_abd;
+  list_dict_abd.Append(dict_ab.Clone());
+  list_dict_abd.Append(dict_d.Clone());
+  base::Value::List list_dict_c;
+  list_dict_c.Append(dict_c.Clone());
 
-  std::vector<base::Value> list_dict_abcd;
-  list_dict_abcd.emplace_back(dict_ab.Clone());
-  list_dict_abcd.emplace_back(dict_d.Clone());
-  list_dict_abcd.emplace_back(dict_c.Clone());
+  base::Value::List list_dict_abcd;
+  list_dict_abcd.Append(dict_ab.Clone());
+  list_dict_abcd.Append(dict_d.Clone());
+  list_dict_abcd.Append(dict_c.Clone());
 
   // Case 1 - kTestPolicyName1
   // Enterprise default policies should not be merged with other sources.
   PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                         POLICY_SOURCE_PLATFORM, base::Value(abc), nullptr);
+                         POLICY_SOURCE_PLATFORM, base::Value(abc.Clone()),
+                         nullptr);
 
-  case1.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                       POLICY_SOURCE_COMMAND_LINE, base::Value(cd), nullptr));
+  case1.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_COMMAND_LINE,
+      base::Value(cd.Clone()), nullptr));
 
   case1.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr));
+      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef.Clone()), nullptr));
 
   case1.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
-      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr));
+      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef.Clone()), nullptr));
 
   PolicyMap::Entry expected_case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                                  POLICY_SOURCE_MERGED, base::Value(abcd),
-                                  nullptr);
+                                  POLICY_SOURCE_MERGED,
+                                  base::Value(abcd.Clone()), nullptr);
   expected_case1.AddConflictingPolicy(case1.DeepCopy());
 
   // Case 2 - kTestPolicyName2
   // Policies should only be merged with other policies with the same target,
   // level and scope.
   PolicyMap::Entry case2(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
-                         POLICY_SOURCE_CLOUD, base::Value(int12), nullptr);
+                         POLICY_SOURCE_CLOUD, base::Value(int12.Clone()),
+                         nullptr);
 
-  case2.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
-                       POLICY_SOURCE_PLATFORM, base::Value(int34), nullptr));
+  case2.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
+      base::Value(int34.Clone()), nullptr));
 
-  case2.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_PLATFORM, base::Value(int56), nullptr));
+  case2.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
+      base::Value(int56.Clone()), nullptr));
 
   PolicyMap::Entry expected_case2(POLICY_LEVEL_RECOMMENDED,
                                   POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED,
-                                  base::Value(int1234), nullptr);
+                                  base::Value(int1234.Clone()), nullptr);
   expected_case2.AddConflictingPolicy(case2.DeepCopy());
 
   // Case 3 - kTestPolicyName3
   // Trivial case with 2 sources.
   PolicyMap::Entry case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                         POLICY_SOURCE_CLOUD, base::Value(ab), nullptr);
+                         POLICY_SOURCE_CLOUD, base::Value(ab.Clone()), nullptr);
 
-  case3.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                       POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr));
+  case3.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
+      base::Value(cd.Clone()), nullptr));
 
   PolicyMap::Entry expected_case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                                  POLICY_SOURCE_MERGED, base::Value(abcd),
-                                  nullptr);
+                                  POLICY_SOURCE_MERGED,
+                                  base::Value(abcd.Clone()), nullptr);
   auto case3_blocked_by_group = expected_case3.DeepCopy();
   case3_blocked_by_group.SetIgnoredByPolicyAtomicGroup();
   expected_case3.AddConflictingPolicy(case3.DeepCopy());
@@ -577,9 +578,9 @@
   // Case 4 - kTestPolicyName4
   // Policies with a single source should stay the same.
   PolicyMap::Entry case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                         POLICY_SOURCE_CLOUD, base::Value(ef), nullptr);
+                         POLICY_SOURCE_CLOUD, base::Value(ef.Clone()), nullptr);
   PolicyMap::Entry expected_case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                                  POLICY_SOURCE_MERGED, base::Value(ef),
+                                  POLICY_SOURCE_MERGED, base::Value(ef.Clone()),
                                   nullptr);
   expected_case4.AddConflictingPolicy(case4.DeepCopy());
 
@@ -601,56 +602,58 @@
   // Case 6 - kTestPolicyName6
   // User cloud policies should not be merged with other sources.
   PolicyMap::Entry case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                         POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr);
+                         POLICY_SOURCE_PLATFORM, base::Value(ab.Clone()),
+                         nullptr);
   case6.AddConflictingPolicy(
       PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_CLOUD, base::Value(cd), nullptr));
+                       POLICY_SOURCE_CLOUD, base::Value(cd.Clone()), nullptr));
   case6.AddConflictingPolicy(
       PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_CLOUD, base::Value(ef), nullptr));
+                       POLICY_SOURCE_CLOUD, base::Value(ef.Clone()), nullptr));
   PolicyMap::Entry expected_case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                                  POLICY_SOURCE_MERGED, base::Value(ab),
+                                  POLICY_SOURCE_MERGED, base::Value(ab.Clone()),
                                   nullptr);
   expected_case6.AddConflictingPolicy(case6.DeepCopy());
 
   // Case 7 - kTestPolicyName7
   // User platform policies should not be merged under any circumstances.
   PolicyMap::Entry case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                         POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr);
+                         POLICY_SOURCE_PLATFORM, base::Value(ab.Clone()),
+                         nullptr);
+  case7.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
+      base::Value(cd.Clone()), nullptr));
   case7.AddConflictingPolicy(
       PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr));
-  case7.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_CLOUD, base::Value(cd), nullptr));
-  case7.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                       POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr));
-  case7.AddConflictingPolicy(
-      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_COMMAND_LINE, base::Value(ef), nullptr));
+                       POLICY_SOURCE_CLOUD, base::Value(cd.Clone()), nullptr));
+  case7.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
+      base::Value(ef.Clone()), nullptr));
+  case7.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_COMMAND_LINE,
+      base::Value(ef.Clone()), nullptr));
   PolicyMap::Entry expected_case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                                  POLICY_SOURCE_MERGED, base::Value(ab),
+                                  POLICY_SOURCE_MERGED, base::Value(ab.Clone()),
                                   nullptr);
   expected_case7.AddConflictingPolicy(case7.DeepCopy());
 
   // Case 8 - kTestPolicyName8
   // Lists of dictionaries should not have duplicates.
   PolicyMap::Entry case8(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                         POLICY_SOURCE_PLATFORM, base::Value(list_dict_abd),
-                         nullptr);
+                         POLICY_SOURCE_PLATFORM,
+                         base::Value(list_dict_abd.Clone()), nullptr);
 
   case8.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-      base::Value(list_dict_abd), nullptr));
+      base::Value(list_dict_abd.Clone()), nullptr));
 
   case8.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_COMMAND_LINE,
-      base::Value(list_dict_c), nullptr));
+      base::Value(list_dict_c.Clone()), nullptr));
 
   PolicyMap::Entry expected_case8(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                                   POLICY_SOURCE_MERGED,
-                                  base::Value(list_dict_abcd), nullptr);
+                                  base::Value(list_dict_abcd.Clone()), nullptr);
   expected_case8.AddConflictingPolicy(case8.DeepCopy());
 
   PolicyMap policy_not_merged;
@@ -926,39 +929,39 @@
 }
 
 TEST_F(PolicyMapTest, MergeValuesGroup) {
-  std::vector<base::Value> abc = GetListStorage<std::string>({"a", "b", "c"});
-  std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"});
-  std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"});
-  std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"});
+  base::Value::List abc = GetList<std::string>({"a", "b", "c"});
+  base::Value::List ab = GetList<std::string>({"a", "b"});
+  base::Value::List cd = GetList<std::string>({"c", "d"});
+  base::Value::List ef = GetList<std::string>({"e", "f"});
 
   // Case 1 - kTestPolicyName1
   // Should not be affected by the atomic groups
   PolicyMap::Entry platform_user_mandatory(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
-      base::Value(abc), nullptr);
+      base::Value(abc.Clone()), nullptr);
 
   platform_user_mandatory.AddConflictingPolicy(
       PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_CLOUD, base::Value(cd), nullptr));
+                       POLICY_SOURCE_CLOUD, base::Value(cd.Clone()), nullptr));
 
   platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr));
+      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef.Clone()), nullptr));
 
   platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry(
       POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
-      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef), nullptr));
+      POLICY_SOURCE_ENTERPRISE_DEFAULT, base::Value(ef.Clone()), nullptr));
 
   // Case 2 - policy::key::kExtensionInstallBlocklist
   // This policy is part of the atomic group "Extensions" and has the highest
   // source in its group, its value should remain the same.
   PolicyMap::Entry platform_machine_mandatory(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
-      base::Value(ab), nullptr);
+      base::Value(ab.Clone()), nullptr);
 
   platform_machine_mandatory.AddConflictingPolicy(
       PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                       POLICY_SOURCE_CLOUD, base::Value(cd), nullptr));
+                       POLICY_SOURCE_CLOUD, base::Value(cd.Clone()), nullptr));
 
   // Case 3 - policy::key::kExtensionInstallAllowlist
   // This policy is part of the atomic group "Extensions" and has a lower
@@ -966,7 +969,7 @@
   // its value should be ignored.
   PolicyMap::Entry cloud_machine_mandatory(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-      base::Value(ef), nullptr);
+      base::Value(ef.Clone()), nullptr);
   auto cloud_machine_mandatory_ignored = cloud_machine_mandatory.DeepCopy();
   cloud_machine_mandatory_ignored.SetIgnoredByPolicyAtomicGroup();
 
@@ -975,7 +978,7 @@
   // source in its group, its value should remain the same.
   PolicyMap::Entry platform_machine_recommended(
       POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
-      base::Value(ab), nullptr);
+      base::Value(ab.Clone()), nullptr);
 
   PolicyMap policy_not_merged;
   policy_not_merged.Set(kTestPolicyName1, platform_user_mandatory.DeepCopy());
@@ -1045,22 +1048,27 @@
 }
 
 TEST_F(PolicyMapTest, EntryAddConflict) {
-  std::vector<base::Value> ab = GetListStorage<std::string>({"a", "b"});
-  std::vector<base::Value> cd = GetListStorage<std::string>({"c", "d"});
-  std::vector<base::Value> ef = GetListStorage<std::string>({"e", "f"});
-  std::vector<base::Value> gh = GetListStorage<std::string>({"g", "h"});
+  base::Value::List ab = GetList<std::string>({"a", "b"});
+  base::Value::List cd = GetList<std::string>({"c", "d"});
+  base::Value::List ef = GetList<std::string>({"e", "f"});
+  base::Value::List gh = GetList<std::string>({"g", "h"});
 
   // Case 1: Non-nested conflicts
   PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                         POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr);
+                         POLICY_SOURCE_PLATFORM, base::Value(ab.Clone()),
+                         nullptr);
   PolicyMap::Entry conflict11(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(cd.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict12(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(ef.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict13(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(gh), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(gh.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict14(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(ab.Clone()),
+                              nullptr);
 
   case1.AddConflictingPolicy(conflict11.DeepCopy());
   case1.AddConflictingPolicy(conflict12.DeepCopy());
@@ -1083,15 +1091,20 @@
 
   // Case 2: Nested conflicts
   PolicyMap::Entry case2(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                         POLICY_SOURCE_PLATFORM, base::Value(ab), nullptr);
+                         POLICY_SOURCE_PLATFORM, base::Value(ab.Clone()),
+                         nullptr);
   PolicyMap::Entry conflict21(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(cd.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict22(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(cd), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(cd.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict23(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(ef), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(ef.Clone()),
+                              nullptr);
   PolicyMap::Entry conflict24(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                              POLICY_SOURCE_PLATFORM, base::Value(gh), nullptr);
+                              POLICY_SOURCE_PLATFORM, base::Value(gh.Clone()),
+                              nullptr);
 
   conflict21.AddConflictingPolicy(conflict22.DeepCopy());
   conflict21.AddConflictingPolicy(conflict23.DeepCopy());
@@ -1443,12 +1456,11 @@
 #endif  // !BUILDFLAG(IS_CHROMEOS)
   }
 
-  void PopulateExpectedMetapolicyMap(
-      PolicyMap& policy_map_expected,
-      const PolicyMap& policy_map_1,
-      const PolicyMap& policy_map_2,
-      std::unique_ptr<base::ListValue> merge_list_1,
-      std::unique_ptr<base::ListValue> merge_list_2) {
+  void PopulateExpectedMetapolicyMap(PolicyMap& policy_map_expected,
+                                     const PolicyMap& policy_map_1,
+                                     const PolicyMap& policy_map_2,
+                                     base::Value::List merge_list_1,
+                                     base::Value::List merge_list_2) {
     // Platform machine overrides cloud machine because modified priorities
     // don't apply to precedence metapolicies.
     policy_map_expected.Set(
@@ -1489,8 +1501,8 @@
       // apply to merging metapolicies.
       policy_map_expected.Set(key::kPolicyListMultipleSourceMergeList,
                               POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                              POLICY_SOURCE_CLOUD, merge_list_2->Clone(),
-                              nullptr);
+                              POLICY_SOURCE_CLOUD,
+                              base::Value(std::move(merge_list_2)), nullptr);
       policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList)
           ->AddMessage(PolicyMap::MessageType::kWarning,
                        IDS_POLICY_CONFLICT_DIFF_VALUE);
@@ -1503,8 +1515,8 @@
       // Platform machine overrides cloud machine with default precedence.
       policy_map_expected.Set(key::kPolicyListMultipleSourceMergeList,
                               POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                              POLICY_SOURCE_PLATFORM, merge_list_1->Clone(),
-                              nullptr);
+                              POLICY_SOURCE_PLATFORM,
+                              base::Value(std::move(merge_list_1)), nullptr);
       policy_map_expected.GetMutable(key::kPolicyListMultipleSourceMergeList)
           ->AddMessage(PolicyMap::MessageType::kWarning,
                        IDS_POLICY_CONFLICT_DIFF_VALUE);
@@ -1608,12 +1620,10 @@
 
 TEST_P(PolicyMapMergeTest, MergeFrom_Metapolicies) {
   // Define the lists of policies that will be used by the merging metapolicies.
-  std::unique_ptr<base::ListValue> merge_list_1 =
-      std::make_unique<base::ListValue>();
-  merge_list_1->Append(base::Value(kTestPolicyName1));
-  std::unique_ptr<base::ListValue> merge_list_2 =
-      std::make_unique<base::ListValue>();
-  merge_list_2->Append(base::Value(kTestPolicyName2));
+  base::Value::List merge_list_1;
+  merge_list_1.Append(kTestPolicyName1);
+  base::Value::List merge_list_2;
+  merge_list_2.Append(kTestPolicyName2);
 
   PolicyMap policy_map_1;
   if (IsUserAffiliated()) {
@@ -1631,7 +1641,8 @@
                    POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
   policy_map_1.Set(key::kPolicyListMultipleSourceMergeList,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                   POLICY_SOURCE_PLATFORM, merge_list_1->Clone(), nullptr);
+                   POLICY_SOURCE_PLATFORM, base::Value(merge_list_1.Clone()),
+                   nullptr);
 
   PolicyMap policy_map_2;
   policy_map_2.Set(key::kCloudPolicyOverridesPlatformPolicy,
@@ -1643,7 +1654,8 @@
       base::Value(CloudUserPolicyOverridesCloudMachinePolicy()), nullptr);
   policy_map_2.Set(key::kPolicyListMultipleSourceMergeList,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                   POLICY_SOURCE_CLOUD, merge_list_2->Clone(), nullptr);
+                   POLICY_SOURCE_CLOUD, base::Value(merge_list_2.Clone()),
+                   nullptr);
 
   PolicyMap policy_map_expected;
   PopulateExpectedMetapolicyMap(policy_map_expected, policy_map_1, policy_map_2,
diff --git a/components/policy/core/common/policy_proto_decoders_unittest.cc b/components/policy/core/common/policy_proto_decoders_unittest.cc
index afba91ee..1c2f985 100644
--- a/components/policy/core/common/policy_proto_decoders_unittest.cc
+++ b/components/policy/core/common/policy_proto_decoders_unittest.cc
@@ -67,12 +67,13 @@
 }
 
 TEST_F(PolicyProtoDecodersTest, StringListPolicy) {
-  std::vector<base::Value> expected_disabled_sync_types;
-  expected_disabled_sync_types.emplace_back(base::Value("bookmarks"));
-  expected_disabled_sync_types.emplace_back(base::Value("readingList"));
+  base::Value::List expected_disabled_sync_types;
+  expected_disabled_sync_types.Append("bookmarks");
+  expected_disabled_sync_types.Append("readingList");
   expected_policy_map_.Set(key::kSyncTypesListDisabled, POLICY_LEVEL_MANDATORY,
                            POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-                           base::Value(expected_disabled_sync_types), nullptr);
+                           base::Value(std::move(expected_disabled_sync_types)),
+                           nullptr);
 
   auto* disabled_sync_types =
       user_policy_.payload().mutable_synctypeslistdisabled()->mutable_value();
diff --git a/components/policy/core/common/policy_test_utils.cc b/components/policy/core/common/policy_test_utils.cc
index 59cf85c..8787ef43 100644
--- a/components/policy/core/common/policy_test_utils.cc
+++ b/components/policy/core/common/policy_test_utils.cc
@@ -101,10 +101,10 @@
     }
 
     case base::Value::Type::LIST: {
-      base::Value::ConstListView list_view = value.GetListDeprecated();
+      const base::Value::List& list = value.GetList();
       CFMutableArrayRef array =
-          CFArrayCreateMutable(NULL, list_view.size(), &kCFTypeArrayCallBacks);
-      for (const base::Value& entry : list_view) {
+          CFArrayCreateMutable(NULL, list.size(), &kCFTypeArrayCallBacks);
+      for (const base::Value& entry : list) {
         // CFArrayAppendValue() retains |cf_value|, so make sure the reference
         // created by ValueToProperty() is released.
         base::ScopedCFTypeRef<CFPropertyListRef> cf_value(
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc
index ff75b196..b5d4385 100644
--- a/components/policy/core/common/schema.cc
+++ b/components/policy/core/common/schema.cc
@@ -1362,7 +1362,8 @@
       value->RemoveKey(drop_key);
     return true;
   } else if (value->is_list()) {
-    base::Value::ListStorage list = std::move(*value).TakeListDeprecated();
+    base::Value::List& list = value->GetList();
+
     // Instead of removing invalid list items afterwards, we push valid items
     // forward in the list by overriding invalid items. The next free position
     // is indicated by |write_index|, which gets increased for every valid item.
@@ -1390,8 +1391,9 @@
     }
     if (out_changed && write_index < list.size())
       *out_changed = true;
-    list.resize(write_index);
-    *value = base::Value(std::move(list));
+    while (write_index < list.size()) {
+      list.erase(list.end() - 1);
+    }
     return true;
   }
 
diff --git a/components/policy/core/common/schema_unittest.cc b/components/policy/core/common/schema_unittest.cc
index bc2b6a2..8a94b00 100644
--- a/components/policy/core/common/schema_unittest.cc
+++ b/components/policy/core/common/schema_unittest.cc
@@ -841,13 +841,13 @@
   {
     Schema subschema = schema.GetProperty("ArrayOfObjects");
     ASSERT_TRUE(subschema.valid());
-    base::ListValue root;
-    base::Value::ListView root_view = root.GetListDeprecated();
+    base::Value root(base::Value::Type::LIST);
+    base::Value::List& root_list = root.GetList();
 
     // Unknown property.
     base::Value dict_value(base::Value::Type::DICTIONARY);
     dict_value.SetBoolKey("three", true);
-    root.Append(std::move(dict_value));
+    root_list.Append(std::move(dict_value));
     TestSchemaValidation(subschema, root, SCHEMA_STRICT, false);
     TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true);
     TestSchemaValidation(subschema, root,
@@ -855,12 +855,12 @@
     TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_WITHOUT_WARNING,
                          true);
     TestSchemaValidationWithPath(subschema, root, "items[0]");
-    root.EraseListIter(root_view.begin() + (root_view.size() - 1));
+    root_list.erase(root_list.end() - 1);
 
     // Invalid property.
     dict_value = base::Value(base::Value::Type::DICTIONARY);
     dict_value.SetBoolKey("two", true);
-    root.Append(std::move(dict_value));
+    root_list.Append(std::move(dict_value));
     TestSchemaValidation(subschema, root, SCHEMA_STRICT, false);
     TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, false);
     TestSchemaValidation(subschema, root,
@@ -868,7 +868,6 @@
     TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_WITHOUT_WARNING,
                          false);
     TestSchemaValidationWithPath(subschema, root, "items[0].two");
-    root.EraseListIter(root_view.begin() + (root_view.size() - 1));
   }
 
   // Tests on ObjectOfArray.
diff --git a/components/policy/core/common/values_util_unittest.cc b/components/policy/core/common/values_util_unittest.cc
index 58f96962..cee5fa47 100644
--- a/components/policy/core/common/values_util_unittest.cc
+++ b/components/policy/core/common/values_util_unittest.cc
@@ -11,28 +11,28 @@
 namespace policy {
 
 TEST(PolicyValuesToStringSetTest, Convert) {
-  base::Value::ListStorage items;
-  items.push_back(base::Value("1"));
-  items.push_back(base::Value("2"));
-  items.push_back(base::Value("3"));
-  base::Value value(items);
+  base::Value::List items;
+  items.Append("1");
+  items.Append("2");
+  items.Append("3");
+  base::Value value(std::move(items));
   base::flat_set<std::string> expected_set = {"1", "2", "3"};
   EXPECT_EQ(expected_set, ValueToStringSet(&value));
 }
 
 TEST(PolicyValuesToStringSetTest, SkipInvalidItem) {
-  base::Value::ListStorage items;
-  items.push_back(base::Value("1"));
-  items.push_back(base::Value());
-  items.push_back(base::Value(0));
-  items.push_back(base::Value(true));
-  items.push_back(base::Value(base::Value::Type::BINARY));
-  items.push_back(base::Value(base::Value::Type::LIST));
-  items.push_back(base::Value(base::Value::Type::DICTIONARY));
-  items.push_back(base::Value("2"));
-  items.push_back(base::Value("3"));
-  items.push_back(base::Value(""));
-  base::Value value(items);
+  base::Value::List items;
+  items.Append("1");
+  items.Append(base::Value());
+  items.Append(0);
+  items.Append(true);
+  items.Append(base::Value(base::Value::Type::BINARY));
+  items.Append(base::Value::List());
+  items.Append(base::Value::Dict());
+  items.Append("2");
+  items.Append("3");
+  items.Append("");
+  base::Value value(std::move(items));
   base::flat_set<std::string> expected_set = {"1", "2", "3", ""};
   EXPECT_EQ(expected_set, ValueToStringSet(&value));
 }
diff --git a/components/resources/default_100_percent/neterror/OWNERS b/components/resources/default_100_percent/neterror/OWNERS
index 3546fc7..fb59c70 100644
--- a/components/resources/default_100_percent/neterror/OWNERS
+++ b/components/resources/default_100_percent/neterror/OWNERS
@@ -1,2 +1 @@
-mmenke@chromium.org
 file://net/OWNERS
diff --git a/components/resources/default_200_percent/neterror/OWNERS b/components/resources/default_200_percent/neterror/OWNERS
index 3546fc7..fb59c70 100644
--- a/components/resources/default_200_percent/neterror/OWNERS
+++ b/components/resources/default_200_percent/neterror/OWNERS
@@ -1,2 +1 @@
-mmenke@chromium.org
 file://net/OWNERS
diff --git a/components/security_interstitials/DEPS b/components/security_interstitials/DEPS
index 66cf581..02c972f2 100644
--- a/components/security_interstitials/DEPS
+++ b/components/security_interstitials/DEPS
@@ -3,6 +3,7 @@
   "+components/google/core",
   "+components/history/core/browser",
   "+components/metrics",
+  "+components/policy",
   "+components/prefs",
   "+components/safe_browsing/core/common",
   "+components/safe_browsing/core/browser/db",
diff --git a/components/security_interstitials/core/BUILD.gn b/components/security_interstitials/core/BUILD.gn
index 2f073cf..28940817 100644
--- a/components/security_interstitials/core/BUILD.gn
+++ b/components/security_interstitials/core/BUILD.gn
@@ -18,6 +18,8 @@
     "https_only_mode_allowlist.h",
     "https_only_mode_metrics.cc",
     "https_only_mode_metrics.h",
+    "https_only_mode_policy_handler.cc",
+    "https_only_mode_policy_handler.h",
     "https_only_mode_ui_util.cc",
     "https_only_mode_ui_util.h",
     "metrics_helper.cc",
@@ -56,6 +58,8 @@
     "//components/google/core/common",
     "//components/history/core/browser",
     "//components/metrics",
+    "//components/policy/core/browser",
+    "//components/policy/core/common",
     "//components/prefs",
     "//components/resources",
     "//components/ssl_errors",
diff --git a/chrome/browser/ssl/https_only_mode_policy_handler.cc b/components/security_interstitials/core/https_only_mode_policy_handler.cc
similarity index 70%
rename from chrome/browser/ssl/https_only_mode_policy_handler.cc
rename to components/security_interstitials/core/https_only_mode_policy_handler.cc
index e209596b..87ed18cf 100644
--- a/chrome/browser/ssl/https_only_mode_policy_handler.cc
+++ b/components/security_interstitials/core/https_only_mode_policy_handler.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ssl/https_only_mode_policy_handler.h"
+#include "components/security_interstitials/core/https_only_mode_policy_handler.h"
 
-#include "chrome/common/pref_names.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_value_map.h"
 
 namespace policy {
 
-HttpsOnlyModePolicyHandler::HttpsOnlyModePolicyHandler()
-    : TypeCheckingPolicyHandler(key::kHttpsOnlyMode,
-                                base::Value::Type::STRING) {}
+HttpsOnlyModePolicyHandler::HttpsOnlyModePolicyHandler(
+    const char* const pref_name)
+    : TypeCheckingPolicyHandler(key::kHttpsOnlyMode, base::Value::Type::STRING),
+      pref_name_(pref_name) {}
 
 HttpsOnlyModePolicyHandler::~HttpsOnlyModePolicyHandler() = default;
 
@@ -23,7 +23,7 @@
       policies.GetValue(key::kHttpsOnlyMode, base::Value::Type::STRING);
   if (value && value->GetString() == "disallowed") {
     // Only apply the policy to the pref if it is set to "disallowed".
-    prefs->SetBoolean(prefs::kHttpsOnlyModeEnabled, false);
+    prefs->SetBoolean(pref_name_, false);
   }
 }
 
diff --git a/chrome/browser/ssl/https_only_mode_policy_handler.h b/components/security_interstitials/core/https_only_mode_policy_handler.h
similarity index 71%
rename from chrome/browser/ssl/https_only_mode_policy_handler.h
rename to components/security_interstitials/core/https_only_mode_policy_handler.h
index 5ef27376..0660c2c 100644
--- a/chrome/browser/ssl/https_only_mode_policy_handler.h
+++ b/components/security_interstitials/core/https_only_mode_policy_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_SSL_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
-#define CHROME_BROWSER_SSL_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
+#ifndef COMPONENTS_SECURITY_INTERSTITIALS_CORE_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
+#define COMPONENTS_SECURITY_INTERSTITIALS_CORE_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
 
 #include "components/policy/core/browser/configuration_policy_handler.h"
 
@@ -15,7 +15,7 @@
 // effect.
 class HttpsOnlyModePolicyHandler : public TypeCheckingPolicyHandler {
  public:
-  HttpsOnlyModePolicyHandler();
+  explicit HttpsOnlyModePolicyHandler(const char* const pref_name);
   ~HttpsOnlyModePolicyHandler() override;
   HttpsOnlyModePolicyHandler(const HttpsOnlyModePolicyHandler&) = delete;
   HttpsOnlyModePolicyHandler& operator=(const HttpsOnlyModePolicyHandler&) =
@@ -24,8 +24,12 @@
   // ConfigurationPolicyHandler methods:
   void ApplyPolicySettings(const PolicyMap& policies,
                            PrefValueMap* prefs) override;
+
+ private:
+  // Name of the HTTPS-Only pref.
+  const char* const pref_name_;
 };
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_SSL_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
+#endif  // COMPONENTS_SECURITY_INTERSTITIALS_CORE_HTTPS_ONLY_MODE_POLICY_HANDLER_H_
diff --git a/components/sync/driver/resources/BUILD.gn b/components/sync/driver/resources/BUILD.gn
index 0dcf657..815de12 100644
--- a/components/sync/driver/resources/BUILD.gn
+++ b/components/sync/driver/resources/BUILD.gn
@@ -23,13 +23,13 @@
 preprocessed_files = [ "sync_index.js" ]
 non_preprocessed_files = [
   "about.js",
-  "chrome_sync.js",
+  "chrome_sync.ts",
   "data.js",
   "invalidations.js",
-  "search.js",
+  "search.ts",
   "sync_log.js",
   "sync_node_browser.js",
-  "sync_search.js",
+  "sync_search.ts",
   "traffic_log.js",
   "user_events.js",
 ]
@@ -50,6 +50,10 @@
   in_files = non_preprocessed_files + preprocessed_files
   out_dir = "$target_gen_dir/tsc"
   tsconfig_base = "tsconfig_base.json"
+  definitions = [
+    "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/pending.d.ts",
+  ]
   deps = [ "//ui/webui/resources:library" ]
   extra_deps = [
     ":copy_files",
diff --git a/components/sync/driver/resources/chrome_sync.js b/components/sync/driver/resources/chrome_sync.js
deleted file mode 100644
index bf36614..0000000
--- a/components/sync/driver/resources/chrome_sync.js
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
-
-/**
- * A simple timer to measure elapsed time.
- */
-export class Timer {
-  constructor() {
-    /**
-     * The time that this Timer was created.
-     * @type {number}
-     * @private
-     */
-    this.start_ = Date.now();
-  }
-
-  /**
-   * @return {number} The elapsed seconds since this Timer was created.
-   */
-  getElapsedSeconds() {
-    return (Date.now() - this.start_) / 1000;
-  }
-}
-
-  /**
-   * Requests the sync state, which is sent via onAboutInfoUpdated and
-   * onEntityCountsUpdated events. New events will be emitted whenever the
-   * state changes.
-   */
-export function requestDataAndRegisterForUpdates() {
-  chrome.send('requestDataAndRegisterForUpdates');
-}
-
-
-  /**
-   * Asks the browser to send us the list of registered types. Should result
-   * in an onReceivedListOfTypes event being emitted.
-   */
-export function requestListOfTypes() {
-  chrome.send('requestListOfTypes');
-}
-
-  /**
-   * Asks the browser to send us the initial state of the "include specifics"
-   * flag. Should result in an onReceivedIncludeSpecificsInitialState event
-   * being emitted.
-   */
-export function requestIncludeSpecificsInitialState() {
-  chrome.send('requestIncludeSpecificsInitialState');
-}
-
-  /**
-   * Updates the logic sending events to the protocol logic if they should
-   * include specifics or not when converting to a human readable format.
-   *
-   * @param {boolean} includeSpecifics Whether protocol events include
-   *     specifics.
-   */
-export function setIncludeSpecifics(includeSpecifics) {
-  chrome.send('setIncludeSpecifics', [includeSpecifics]);
-}
-
-  /**
-   * Sends data to construct a user event that should be committed.
-   *
-   * @param {string} eventTimeUsec Timestamp for the new event.
-   * @param {string} navigationId Timestamp of linked sessions navigation.
-   */
-export function writeUserEvent(eventTimeUsec, navigationId) {
-  chrome.send('writeUserEvent', [eventTimeUsec, navigationId]);
-}
-
-  /**
-   * Triggers a RequestStart call on the SyncService.
-   */
-export function requestStart() {
-  chrome.send('requestStart');
-}
-
-  /**
-   * Stops the SyncService while keeping the sync data around.
-   */
-export function requestStopKeepData() {
-  chrome.send('requestStopKeepData');
-}
-
-  /**
-   * Stops the SyncService and clears the sync data.
-   */
-export function requestStopClearData() {
-  chrome.send('requestStopClearData');
-}
-
-  /**
-   * Triggers a GetUpdates call for all enabled datatypes.
-   */
-export function triggerRefresh() {
-  chrome.send('triggerRefresh');
-}
-
-let nodesForTest = null;
-
-/**
- * Asks the browser to send us a copy of all existing sync nodes.
- * Will eventually invoke the given callback with the results.
- *
- * @param {function(!Object)} callback The function to call with the response.
- */
-export function getAllNodes(callback) {
-  if (nodesForTest) {
-    callback(nodesForTest);
-    return;
-  }
-  sendWithPromise('getAllNodes').then(callback);
-}
-
-window.setAllNodesForTest = function(nodes) {
-  nodesForTest = nodes;
-};
diff --git a/components/sync/driver/resources/chrome_sync.ts b/components/sync/driver/resources/chrome_sync.ts
new file mode 100644
index 0000000..d7f2394
--- /dev/null
+++ b/components/sync/driver/resources/chrome_sync.ts
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+
+/**
+ * A simple timer to measure elapsed time.
+ */
+export class Timer {
+  /* The time that this Timer was created. */
+  private start_: number;
+
+  constructor() {
+    this.start_ = Date.now();
+  }
+
+  /**
+   * @return The elapsed seconds since this Timer was created.
+   */
+  getElapsedSeconds(): number {
+    return (Date.now() - this.start_) / 1000;
+  }
+}
+
+/**
+ * Requests the sync state, which is sent via onAboutInfoUpdated and
+ * onEntityCountsUpdated events. New events will be emitted whenever the
+ * state changes.
+ */
+export function requestDataAndRegisterForUpdates() {
+  chrome.send('requestDataAndRegisterForUpdates');
+}
+
+
+/**
+ * Asks the browser to send us the list of registered types. Should result
+ * in an onReceivedListOfTypes event being emitted.
+ */
+export function requestListOfTypes() {
+  chrome.send('requestListOfTypes');
+}
+
+/**
+ * Asks the browser to send us the initial state of the "include specifics"
+ * flag. Should result in an onReceivedIncludeSpecificsInitialState event
+ * being emitted.
+ */
+export function requestIncludeSpecificsInitialState() {
+  chrome.send('requestIncludeSpecificsInitialState');
+}
+
+/**
+ * Updates the logic sending events to the protocol logic if they should
+ * include specifics or not when converting to a human readable format.
+ *
+ * @param includeSpecifics Whether protocol events include specifics.
+ */
+export function setIncludeSpecifics(includeSpecifics: boolean) {
+  chrome.send('setIncludeSpecifics', [includeSpecifics]);
+}
+
+/**
+ * Sends data to construct a user event that should be committed.
+ *
+ * @param eventTimeUsec Timestamp for the new event.
+ * @param navigationId Timestamp of linked sessions navigation.
+ */
+export function writeUserEvent(eventTimeUsec: string, navigationId: string) {
+  chrome.send('writeUserEvent', [eventTimeUsec, navigationId]);
+}
+
+/**
+ * Triggers a RequestStart call on the SyncService.
+ */
+export function requestStart() {
+  chrome.send('requestStart');
+}
+
+/**
+ * Stops the SyncService while keeping the sync data around.
+ */
+export function requestStopKeepData() {
+  chrome.send('requestStopKeepData');
+}
+
+/**
+ * Stops the SyncService and clears the sync data.
+ */
+export function requestStopClearData() {
+  chrome.send('requestStopClearData');
+}
+
+/**
+ * Triggers a GetUpdates call for all enabled datatypes.
+ */
+export function triggerRefresh() {
+  chrome.send('triggerRefresh');
+}
+
+export type SyncNodeList = Array<{NON_UNIQUE_NAME: string}>;
+export type SyncNodeMap = Array<{nodes: SyncNodeList}>;
+
+let nodesForTest: SyncNodeMap|null = null;
+
+/**
+ * Asks the browser to send us a copy of all existing sync nodes.
+ * Will eventually invoke the given callback with the results.
+ *
+ * @param callback The function to call with the response.
+ */
+export function getAllNodes(callback: (p: SyncNodeMap) => void) {
+  if (nodesForTest) {
+    callback(nodesForTest);
+    return;
+  }
+  sendWithPromise('getAllNodes').then(callback);
+}
+
+function setAllNodesForTest(nodes: SyncNodeMap) {
+  nodesForTest = nodes;
+}
+
+Object.assign(window, {setAllNodesForTest});
diff --git a/components/sync/driver/resources/search.js b/components/sync/driver/resources/search.js
deleted file mode 100644
index 70d1a9bf..0000000
--- a/components/sync/driver/resources/search.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://resources/cr_elements/cr_splitter/cr_splitter.js';
-
-import {$, getRequiredElement} from 'chrome://resources/js/util.m.js';
-
-import {decorateQuickQueryControls, SyncSearchManager} from './sync_search.js';
-
-decorateQuickQueryControls(
-    document.getElementsByClassName('sync-search-quicklink'),
-    /** @type {!HTMLButtonElement} */ ($('sync-search-submit')),
-    /** @type {!HTMLInputElement} */ ($('sync-search-query')));
-
-const manager = new SyncSearchManager(
-    /** @type {!HTMLInputElement} */ ($('sync-search-query')),
-    /** @type {!HTMLButtonElement} */ ($('sync-search-submit')),
-    getRequiredElement('sync-search-status'),
-    getRequiredElement('sync-results-list'),
-    /** @type {!HTMLPreElement} */ ($('sync-result-details')));
-
-// Add a way to override the data model for the sync results list for testing.
-window.setupSyncResultsListForTest = function(data) {
-  manager.setDataForTest(data);
-};
diff --git a/components/sync/driver/resources/search.ts b/components/sync/driver/resources/search.ts
new file mode 100644
index 0000000..6b3024d
--- /dev/null
+++ b/components/sync/driver/resources/search.ts
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/cr_splitter/cr_splitter.js';
+
+import {assert} from 'chrome://resources/js/assert_ts.js';
+
+import {SyncNodeList} from './chrome_sync.js';
+import {decorateQuickQueryControls, SyncSearchManager} from './sync_search.js';
+
+const submit = document.querySelector<HTMLButtonElement>('#sync-search-submit');
+const query = document.querySelector<HTMLInputElement>('#sync-search-query');
+const quickLinks =
+    document.querySelectorAll<HTMLElement>('.sync-search-quicklink');
+const status = document.querySelector<HTMLElement>('#sync-search-status');
+const results = document.querySelector<HTMLElement>('#sync-results-list');
+const detail = document.querySelector<HTMLElement>('#sync-result-details');
+assert(submit && query && status && results && detail);
+
+decorateQuickQueryControls(quickLinks, submit, query);
+const manager = new SyncSearchManager(query, submit, status, results, detail);
+
+// Add a way to override the data model for the sync results list for testing.
+function setupSyncResultsListForTest(data: SyncNodeList) {
+  manager.setDataForTest(data);
+}
+
+Object.assign(window, {setupSyncResultsListForTest});
diff --git a/components/sync/driver/resources/sync_search.js b/components/sync/driver/resources/sync_search.ts
similarity index 61%
rename from components/sync/driver/resources/sync_search.js
rename to components/sync/driver/resources/sync_search.ts
index a3124fc..55d792d2 100644
--- a/components/sync/driver/resources/sync_search.js
+++ b/components/sync/driver/resources/sync_search.ts
@@ -2,47 +2,47 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {getAllNodes, Timer} from './chrome_sync.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
 
-const ERROR_ATTR = 'error';
-const SELECTED_ATTR = 'selected';
+import {getAllNodes, SyncNodeList, SyncNodeMap, Timer} from './chrome_sync.js';
+
+const ERROR_ATTR: string = 'error';
+const SELECTED_ATTR: string = 'selected';
 
 export class SyncSearchManager {
+  private currSearchId_: number = 0;
+  private resultsData_: Array<object> = [];
+  private selected_: HTMLElement|null = null;
+  private selectedIndex_: number = -1;
+  private resultsControl_: HTMLElement;
+  private detailsControl_: HTMLElement;
+  private queryControl_: HTMLInputElement;
+  private statusControl_: HTMLElement;
+
   /**
-   * @param {!HTMLInputElement} queryControl The <input> object of
+   * @param queryControl The <input> object of
    *     type=search where the user's query is typed.
-   * @param {!HTMLButtonElement} submitControl The <button> object
+   * @param submitControl The <button> object
    *     where the user can click to submit the query.
-   * @param {!HTMLElement} statusControl The <span> object display the
+   * @param statusControl The <span> object display the
    *     search status.
-   * @param {!HTMLElement} resultsControl The <list> object which holds
+   * @param resultsControl The <list> object which holds
    *     the list of returned results.
-   * @param {!HTMLPreElement} detailsControl The <pre> object which
+   * @param detailsControl The <pre> object which
    *     holds the details of the selected result.
    */
   constructor(
-      queryControl, submitControl, statusControl, resultsControl,
-      detailsControl) {
-    /** @private {number} */
-    this.currSearchId_ = 0;
-    /** @private {Array} */
-    this.resultsData_ = [];
-    /** @private {?HTMLElement} */
-    this.selected_ = null;
-    /** @private {number} */
-    this.selectedIndex_ = -1;
-    /** @private {HTMLElement} */
+      queryControl: HTMLInputElement, submitControl: HTMLButtonElement,
+      statusControl: HTMLElement, resultsControl: HTMLElement,
+      detailsControl: HTMLElement) {
     this.resultsControl_ = resultsControl;
-    /** @private {HTMLElement} */
     this.detailsControl_ = detailsControl;
-    /** @private {HTMLElement} */
     this.queryControl_ = queryControl;
-    /** @private {HTMLElement} */
     this.statusControl_ = statusControl;
 
     submitControl.addEventListener('click', () => this.startSearch_());
     // Decorate search box.
-    this.queryControl_.onsearch = () => this.startSearch_();
+    this.queryControl_.addEventListener('search', () => this.startSearch_());
     this.queryControl_.value = '';
     this.resultsControl_.setAttribute('role', 'list');
     this.resultsControl_.tabIndex = 0;
@@ -50,8 +50,7 @@
         'keydown', e => this.handleKeydown_(e));
   }
 
-  /** @private */
-  startSearch_() {
+  private startSearch_() {
     const query = this.queryControl_.value;
     this.statusControl_.textContent = '';
     this.resultsData_ = [];
@@ -65,12 +64,7 @@
     this.doSearch_(query);
   }
 
-  /**
-   * @param {Element} newSelected
-   * @param {number} newIndex
-   * @private
-   */
-  setSelected_(newSelected, newIndex) {
+  private setSelected_(newSelected: HTMLElement, newIndex: number) {
     if (this.selected_) {
       this.selected_.toggleAttribute(SELECTED_ATTR, false);
     }
@@ -81,12 +75,8 @@
         JSON.stringify(this.resultsData_[this.selectedIndex_], null, 2);
   }
 
-  /**
-   * @param {!KeyboardEvent} e
-   * @private
-   */
-  handleKeydown_(e) {
-    let newIndex = -1;
+  private handleKeydown_(e: KeyboardEvent) {
+    let newIndex: number = -1;
     if (e.key === 'ArrowUp') {
       newIndex = this.selectedIndex_ === -1 ?
           this.resultsData_.length - 1 :
@@ -106,21 +96,22 @@
     }
 
     const items = this.resultsControl_.querySelectorAll('li');
-    this.setSelected_(items[newIndex], newIndex);
+    this.setSelected_(items[newIndex]!, newIndex);
+    assert(this.selected_);
     this.selected_.scrollIntoViewIfNeeded();
     e.preventDefault();
   }
 
-  /** @private */
-  drawResultsList_() {
+  private drawResultsList_() {
     this.selected_ = null;
     this.selectedIndex_ = -1;
-    this.resultsControl_.innerHTML =
-        window.trustedTypes ? window.trustedTypes.emptyHTML : '';
-    this.resultsData_.forEach((item, index) => {
+    this.resultsControl_.innerHTML = window.trustedTypes ?
+        window.trustedTypes.emptyHTML as unknown as string :
+        '';
+    this.resultsData_.forEach((item: object, index: number) => {
       const li = document.createElement('li');
       li.setAttribute('role', 'listitem');
-      li.textContent = item;
+      li.textContent = item.toString();
       this.resultsControl_.appendChild(li);
       li.addEventListener('click', () => {
         this.setSelected_(li, index);
@@ -130,18 +121,18 @@
 
   /**
    * Runs a search with the given query.
-   * @param {string} query The regex to do the search with.
-   * @private
+   * @param query The regex to do the search with.
    */
-  doSearch_(query) {
+  private doSearch_(query: string) {
     const timer = new Timer();
     this.currSearchId_++;
     const searchId = this.currSearchId_;
     try {
       const regex = new RegExp(query);
-      getAllNodes(nodeMap => {
+      getAllNodes((nodeMap: SyncNodeMap) => {
         // Put all nodes into one big list that ignores the type.
-        const nodes = nodeMap.map(x => x.nodes).reduce((a, b) => a.concat(b));
+        const nodes: SyncNodeList =
+            nodeMap.map(x => x.nodes).reduce((a, b) => a.concat(b));
         if (this.currSearchId_ !== searchId) {
           return;
         }
@@ -154,17 +145,13 @@
     } catch (err) {
       // Sometimes the provided regex is invalid.  This and other errors will
       // be caught and handled here.
-      this.displayResults_(timer, [], err);
+      this.displayResults_(timer, [], err as Error);
     }
   }
 
-  /**
-   * @param {Timer} timer Measuring time since search started.
-   * @param {Array} nodes Node results
-   * @param {?Error} error The error, if any.
-   * @private
-   */
-  displayResults_(timer, nodes, error) {
+  private displayResults_(
+      timer: Timer, nodes: Array<{NON_UNIQUE_NAME: string}>,
+      error: Error|null) {
     if (error) {
       this.statusControl_.textContent = 'Error: ' + error;
       this.queryControl_.toggleAttribute(ERROR_ATTR, true);
@@ -175,7 +162,7 @@
 
       // TODO(akalin): Write a nicer list display.
       for (let i = 0; i < nodes.length; ++i) {
-        nodes[i].toString = function() {
+        nodes[i]!.toString = function() {
           return this.NON_UNIQUE_NAME;
         };
       }
@@ -184,13 +171,15 @@
     }
   }
 
-  setDataForTest(data) {
+  setDataForTest(data: Array<object>) {
     this.resultsData_ = data;
     this.drawResultsList_();
   }
 }
 
-function createDoQueryFunction(queryControl, submitControl, query) {
+function createDoQueryFunction(
+    queryControl: HTMLInputElement, submitControl: HTMLButtonElement,
+    query: string): () => void {
   return function() {
     queryControl.value = query;
     submitControl.click();
@@ -200,18 +189,20 @@
 /**
  * Decorates the quick search controls
  *
- * @param {!NodeList<!Element>} quickLinkArray The <a> object which
+ * @param quickLinkArray The <a> object which
  *     will be given a link to a quick filter option.
- * @param {!HTMLButtonElement} submitControl
- * @param {!HTMLInputElement} queryControl The <input> object of
- *     type=search where user's query is typed.
+ * @param submitControl
+ * @param queryControl The <input> object of type=search where user's query is
+ *     typed.
  */
 export function decorateQuickQueryControls(
-    quickLinkArray, submitControl, queryControl) {
+    quickLinkArray: NodeListOf<HTMLElement>, submitControl: HTMLButtonElement,
+    queryControl: HTMLInputElement) {
   for (let index = 0; index < quickLinkArray.length; ++index) {
-    const quickQuery = quickLinkArray[index].getAttribute('data-query');
+    const quickQuery = quickLinkArray[index]!.getAttribute('data-query');
+    assert(quickQuery);
     const quickQueryFunction =
         createDoQueryFunction(queryControl, submitControl, quickQuery);
-    quickLinkArray[index].addEventListener('click', quickQueryFunction);
+    quickLinkArray[index]!.addEventListener('click', quickQueryFunction);
   }
 }
diff --git a/components/user_education/common/feature_promo_specification.cc b/components/user_education/common/feature_promo_specification.cc
index a6bb186..f5b18a5 100644
--- a/components/user_education/common/feature_promo_specification.cc
+++ b/components/user_education/common/feature_promo_specification.cc
@@ -163,6 +163,12 @@
   return *this;
 }
 
+FeaturePromoSpecification& FeaturePromoSpecification::SetInAnyContext(
+    bool in_any_context) {
+  in_any_context_ = in_any_context;
+  return *this;
+}
+
 FeaturePromoSpecification& FeaturePromoSpecification::SetDemoPageInfo(
     DemoPageInfo demo_page_info) {
   demo_page_info_ = std::move(demo_page_info);
@@ -172,11 +178,18 @@
 ui::TrackedElement* FeaturePromoSpecification::GetAnchorElement(
     ui::ElementContext context) const {
   auto* const element_tracker = ui::ElementTracker::GetElementTracker();
-  return anchor_element_filter_ ? anchor_element_filter_.Run(
-                                      element_tracker->GetAllMatchingElements(
-                                          anchor_element_id_, context))
-                                : element_tracker->GetFirstMatchingElement(
-                                      anchor_element_id_, context);
+  if (anchor_element_filter_) {
+    return anchor_element_filter_.Run(
+        in_any_context_ ? element_tracker->GetAllMatchingElementsInAnyContext(
+                              anchor_element_id_)
+                        : element_tracker->GetAllMatchingElements(
+                              anchor_element_id_, context));
+  } else {
+    return in_any_context_
+               ? element_tracker->GetElementInAnyContext(anchor_element_id_)
+               : element_tracker->GetFirstMatchingElement(anchor_element_id_,
+                                                          context);
+  }
 }
 
 }  // namespace user_education
diff --git a/components/user_education/common/feature_promo_specification.h b/components/user_education/common/feature_promo_specification.h
index 69792ce..4353435 100644
--- a/components/user_education/common/feature_promo_specification.h
+++ b/components/user_education/common/feature_promo_specification.h
@@ -152,6 +152,14 @@
   FeaturePromoSpecification& SetAnchorElementFilter(
       AnchorElementFilter anchor_element_filter);
 
+  // Set whether we should look for the anchor element in any context.
+  // Default is false. Since usually we only want to create the bubble in the
+  // currently active window, this is only really useful for cases where there
+  // is a floating window, WebContents, or tab-modal dialog that can become
+  // detached from the current active window and therefore requires its own
+  // unique context.
+  FeaturePromoSpecification& SetInAnyContext(bool in_any_context);
+
   // Get the anchor element based on `anchor_element_id`,
   // `anchor_element_filter`, and `context`.
   ui::TrackedElement* GetAnchorElement(ui::ElementContext context) const;
@@ -162,6 +170,7 @@
   const AnchorElementFilter& anchor_element_filter() const {
     return anchor_element_filter_;
   }
+  bool in_any_context() const { return in_any_context_; }
   int bubble_body_string_id() const { return bubble_body_string_id_; }
   const std::u16string& bubble_title_text() const { return bubble_title_text_; }
   const gfx::VectorIcon* bubble_icon() const { return bubble_icon_; }
@@ -191,6 +200,9 @@
   // The element identifier of the element to attach the promo to.
   ui::ElementIdentifier anchor_element_id_;
 
+  // Whether we are allowed to search for the anchor element in any context.
+  bool in_any_context_ = false;
+
   // The filter to use if there is more than one matching element, or
   // additional processing is needed (default is to always use the first
   // matching element).
diff --git a/components/user_notes/browser/user_note_instance.cc b/components/user_notes/browser/user_note_instance.cc
index c55eb61..373b8d1 100644
--- a/components/user_notes/browser/user_note_instance.cc
+++ b/components/user_notes/browser/user_note_instance.cc
@@ -43,6 +43,12 @@
   }
 }
 
+void UserNoteInstance::OnNoteSelected() {
+  if (!agent_)
+    return;
+  agent_->ScrollIntoView();
+}
+
 void UserNoteInstance::DidFinishAttachment(const gfx::Rect& rect) {
   is_initialized_ = true;
   rect_ = rect;
diff --git a/components/user_notes/browser/user_note_instance.h b/components/user_notes/browser/user_note_instance.h
index 0f8ac939..076a19c9 100644
--- a/components/user_notes/browser/user_note_instance.h
+++ b/components/user_notes/browser/user_note_instance.h
@@ -51,6 +51,8 @@
   // Marked virtual for tests to override.
   virtual void InitializeHighlightIfNeeded(base::OnceClosure callback);
 
+  void OnNoteSelected();
+
   // blink::mojom::AnnotationAgentHost implementation.
   void DidFinishAttachment(const gfx::Rect& rect) override;
 
diff --git a/components/user_notes/browser/user_note_service.cc b/components/user_notes/browser/user_note_service.cc
index c6a70fc..f1d8d7e 100644
--- a/components/user_notes/browser/user_note_service.cc
+++ b/components/user_notes/browser/user_note_service.cc
@@ -152,9 +152,15 @@
   ui->StartNoteCreation(instance_raw);
 }
 
-void UserNoteService::OnNoteFocused(const base::UnguessableToken& id) {
+void UserNoteService::OnNoteSelected(const base::UnguessableToken& id,
+                                     content::RenderFrameHost* rfh) {
   DCHECK(IsUserNotesEnabled());
-  NOTIMPLEMENTED();
+  DCHECK(rfh);
+  UserNoteManager* manager = UserNoteManager::GetForPage(rfh->GetPage());
+  DCHECK(manager);
+  UserNoteInstance* note_instance = manager->GetNoteInstance(id);
+  DCHECK(note_instance);
+  note_instance->OnNoteSelected();
 }
 
 void UserNoteService::OnNoteDeleted(const base::UnguessableToken& id) {
diff --git a/components/user_notes/browser/user_note_service.h b/components/user_notes/browser/user_note_service.h
index 277e0e5b..ef30ee77 100644
--- a/components/user_notes/browser/user_note_service.h
+++ b/components/user_notes/browser/user_note_service.h
@@ -83,7 +83,8 @@
                           gfx::Rect rect);
 
   // UserNotesUIDelegate implementation.
-  void OnNoteFocused(const base::UnguessableToken& id) override;
+  void OnNoteSelected(const base::UnguessableToken& id,
+                      content::RenderFrameHost* rfh) override;
   void OnNoteDeleted(const base::UnguessableToken& id) override;
   void OnNoteCreationDone(const base::UnguessableToken& id,
                           const std::string& note_content) override;
diff --git a/components/user_notes/interfaces/user_notes_ui_delegate.h b/components/user_notes/interfaces/user_notes_ui_delegate.h
index 6ce5d5a..3cd241a6 100644
--- a/components/user_notes/interfaces/user_notes_ui_delegate.h
+++ b/components/user_notes/interfaces/user_notes_ui_delegate.h
@@ -9,6 +9,10 @@
 
 #include "base/unguessable_token.h"
 
+namespace content {
+class RenderFrameHost;
+}  // namespace content
+
 namespace user_notes {
 
 // Interface used by the UI layer (e.g. Side Panel on desktop) to delegate
@@ -20,8 +24,9 @@
   UserNotesUIDelegate& operator=(const UserNotesUIDelegate&) = delete;
   virtual ~UserNotesUIDelegate() = default;
 
-  // Called when a note in the UI is focused.
-  virtual void OnNoteFocused(const base::UnguessableToken& id) = 0;
+  // Called when a note in the UI is selected (i.e. via mouse press).
+  virtual void OnNoteSelected(const base::UnguessableToken& id,
+                              content::RenderFrameHost* rfh) = 0;
 
   // Called when the user deletes a note in the UI.
   virtual void OnNoteDeleted(const base::UnguessableToken& id) = 0;
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index dbfd8f7..19f38c19 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -815,9 +815,7 @@
 
 void SkiaRenderer::FinishDrawingFrame() {
   TRACE_EVENT0("viz", "SkiaRenderer::FinishDrawingFrame");
-  root_canvas_ = nullptr;
   current_canvas_ = nullptr;
-  current_surface_ = nullptr;
 
   swap_buffer_rect_ = current_frame()->root_damage_rect;
 
@@ -980,9 +978,7 @@
 }
 
 void SkiaRenderer::BindFramebufferToOutputSurface() {
-  root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
-  current_canvas_ = root_canvas_;
-  current_surface_ = root_surface_.get();
+  current_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
 }
 
 void SkiaRenderer::BindFramebufferToTexture(
@@ -2615,15 +2611,16 @@
 
 sk_sp<SkColorFilter> SkiaRenderer::GetContentColorFilter() {
   sk_sp<SkColorFilter> color_transform = nullptr;
-  if (current_canvas_ == root_canvas_ &&
-      output_surface_->color_matrix() != SkM44()) {
+  bool is_root =
+      current_frame()->current_render_pass == current_frame()->root_render_pass;
+
+  if (is_root && output_surface_->color_matrix() != SkM44()) {
     color_transform =
         SkColorFilters::Matrix(ToColorMatrix(output_surface_->color_matrix()));
   }
 
   sk_sp<SkColorFilter> tint_transform = nullptr;
-  if (current_canvas_ == root_canvas_ &&
-      debug_settings_->tint_composited_content) {
+  if (is_root && debug_settings_->tint_composited_content) {
     if (debug_settings_->tint_composited_content_modulate) {
       // Integer counter causes modulation through rgb dimming variations.
       std::array<float, 3> rgb;
@@ -2926,6 +2923,7 @@
   if (is_root_render_pass && UsingSkiaForDelegatedInk())
     DrawDelegatedInkTrail();
 
+  current_canvas_ = nullptr;
   EndPaint(/*failed=*/false);
 
   // Defer flushing drawing task for root render pass, to avoid extra
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index cbf1116..ff8fae0 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -289,10 +289,7 @@
   }
 
   // Interface used for drawing. Common among different draw modes.
-  sk_sp<SkSurface> root_surface_;
-  raw_ptr<SkCanvas, DanglingUntriaged> root_canvas_ = nullptr;
   raw_ptr<SkCanvas, DanglingUntriaged> current_canvas_ = nullptr;
-  raw_ptr<SkSurface, DanglingUntriaged> current_surface_ = nullptr;
 
   class FrameResourceGpuCommandsCompletedFence;
   scoped_refptr<FrameResourceGpuCommandsCompletedFence>
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 87c464f..d7c4983 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2854,8 +2854,8 @@
       "android/content_view_statics.cc",
       "android/date_time_chooser_android.cc",
       "android/date_time_chooser_android.h",
-      "android/drop_data_android_helper.cc",
-      "android/drop_data_android_helper.h",
+      "android/drop_data_android.cc",
+      "android/drop_data_android.h",
       "android/gesture_listener_manager.cc",
       "android/gesture_listener_manager.h",
       "android/ime_adapter_android.cc",
diff --git a/content/browser/accessibility/accessibility_action_browsertest.cc b/content/browser/accessibility/accessibility_action_browsertest.cc
index 4027c5c..f621dbd 100644
--- a/content/browser/accessibility/accessibility_action_browsertest.cc
+++ b/content/browser/accessibility/accessibility_action_browsertest.cc
@@ -428,8 +428,14 @@
   EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(3, 1));
 }
 
+// Flaky on Mac https://crbug.com/1337760.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_CanvasGetImageScale DISABLED_CanvasGetImageScale
+#else
+#define MAYBE_CanvasGetImageScale CanvasGetImageScale
+#endif
 IN_PROC_BROWSER_TEST_F(AccessibilityCanvasActionBrowserTest,
-                       CanvasGetImageScale) {
+                       MAYBE_CanvasGetImageScale) {
   LoadInitialAccessibilityTreeFromHtml(R"HTML(
       <body>
       <canvas aria-label="canvas" id="c" width="40" height="20">
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index d34dcaf..936d0241 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -2624,16 +2624,9 @@
                           L"Before frame\nText in iframe\nAfter frame");
 }
 
-// TODO(https://crbug.com/1338169): This test is flaky on Win.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_AXPlatformNodeTextRangeProviderWinBrowserTest \
-  DISABLED_AXPlatformNodeTextRangeProviderWinBrowserTest
-#else
-#define MAYBE_AXPlatformNodeTextRangeProviderWinBrowserTest \
-  AXPlatformNodeTextRangeProviderWinBrowserTest
-#endif  // BUILDFLAG(IS_WIN)
+// TODO(https://crbug.com/1338169): This test is flaky.
 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
-                       MAYBE_AXPlatformNodeTextRangeProviderWinBrowserTest) {
+                       DISABLED_OutOfProcessIFrameTraversal) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/accessibility/html/iframe-cross-process.html"));
   LoadInitialAccessibilityTreeFromUrl(main_url);
diff --git a/content/browser/android/drop_data_android.cc b/content/browser/android/drop_data_android.cc
new file mode 100644
index 0000000..e2c0e99
--- /dev/null
+++ b/content/browser/android/drop_data_android.cc
@@ -0,0 +1,76 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/drop_data_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "url/android/gurl_android.h"
+#include "url/gurl.h"
+
+#include "ui/android/ui_android_jni_headers/DropDataAndroid_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+using base::android::ToJavaByteArray;
+
+namespace content {
+
+// This function refers to //content/browser/renderer_host/data_transfer_util.cc
+// on how data fields are populated. If data_transfer_util.cc ever changed, this
+// function will need updates to keep in sync.
+ScopedJavaLocalRef<jobject> ToJavaDropData(const DropData& drop_data) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> jtext;
+  if (drop_data.text) {
+    jtext = ConvertUTF16ToJavaString(env, *drop_data.text);
+  }
+
+  ScopedJavaLocalRef<jobject> jgurl;
+  if (!drop_data.url.is_empty()) {
+    jgurl = url::GURLAndroid::FromNativeGURL(env, drop_data.url);
+    jtext = ConvertUTF16ToJavaString(env, drop_data.url_title);
+  }
+
+  // If file_contents is not empty, user is trying to drag image out of the
+  // web contents. If the image contains a link, the link URL, represented by
+  // |jgurl|, will be added to the image clip data.
+  // drop_data.file_contents_source_url represents the image source URL;
+  // drop_data.url represents the URL that is linked to the image, which may not
+  // necessarily be the image source URL and is the desired URL to be added to
+  // the image clip data.
+  ScopedJavaLocalRef<jbyteArray> jimage_bytes;
+  ScopedJavaLocalRef<jstring> jimage_extension;
+  ScopedJavaLocalRef<jstring> jimage_filename;
+  if (!drop_data.file_contents.empty()) {
+    jimage_bytes = ToJavaByteArray(env, drop_data.file_contents);
+    jimage_extension = ConvertUTF8ToJavaString(
+        env, drop_data.file_contents_filename_extension);
+    absl::optional<base::FilePath> filename =
+        drop_data.GetSafeFilenameForImageFileContents();
+    if (filename) {
+      jimage_filename =
+          ConvertUTF16ToJavaString(env, filename->LossyDisplayName());
+    } else {
+      // Use the current timestamp as the image file name in case the file name
+      // is not retrieved from the source.
+      jimage_filename = ConvertUTF8ToJavaString(
+          env, base::NumberToString(
+                   base::Time::Now().since_origin().InMilliseconds()) +
+                   "." + drop_data.file_contents_filename_extension);
+    }
+  }
+
+  return ui::Java_DropDataAndroid_create(env, jtext, jgurl, jimage_bytes,
+                                         jimage_extension, jimage_filename);
+}  // ToJavaDropData
+
+}  // namespace content
diff --git a/content/browser/android/drop_data_android_helper.h b/content/browser/android/drop_data_android.h
similarity index 75%
rename from content/browser/android/drop_data_android_helper.h
rename to content/browser/android/drop_data_android.h
index 0c63518e..0f6c9b7 100644
--- a/content/browser/android/drop_data_android_helper.h
+++ b/content/browser/android/drop_data_android.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_HELPER_H_
-#define CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_HELPER_H_
+#ifndef CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_H_
+#define CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_H_
 
 #include <jni.h>
 
@@ -19,4 +19,4 @@
     const DropData& drop_data);
 
 }  // namespace content
-#endif  // CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_HELPER_H_
+#endif  // CONTENT_BROWSER_ANDROID_DROP_DATA_ANDROID_H_
diff --git a/content/browser/android/drop_data_android_helper.cc b/content/browser/android/drop_data_android_helper.cc
deleted file mode 100644
index e73db4a1..0000000
--- a/content/browser/android/drop_data_android_helper.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/android/drop_data_android_helper.h"
-
-#include "base/android/jni_android.h"
-#include "base/files/file_path.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "ui/events/android/drop_data_android.h"
-#include "url/gurl.h"
-
-using base::UTF8ToUTF16;
-
-namespace content {
-
-// This function refers to //content/browser/renderer_host/data_transfer_util.cc
-// on how data fields are populated. If data_transfer_util.cc ever changed, this
-// function will need updates to keep in sync.
-base::android::ScopedJavaLocalRef<jobject> ToJavaDropData(
-    const DropData& drop_data) {
-  std::u16string text;
-  if (drop_data.text) {
-    text = *drop_data.text;
-  }
-
-  GURL gurl = drop_data.url;
-  if (!gurl.is_empty()) {
-    text = drop_data.url_title;
-  }
-
-  // If file_contents is not empty, user is trying to drag image out of the
-  // web contents. If the image contains a link, the link URL, represented by
-  // |jgurl|, will be added to the image clip data.
-  // drop_data.file_contents_source_url represents the image source URL;
-  // drop_data.url represents the URL that is linked to the image, which may not
-  // necessarily be the image source URL and is the desired URL to be added to
-  // the image clip data.
-  std::string file_content;
-  std::string image_extension;
-  std::u16string image_filename;
-  if (!drop_data.file_contents.empty()) {
-    file_content = drop_data.file_contents;
-    image_extension = drop_data.file_contents_filename_extension;
-    absl::optional<base::FilePath> filename =
-        drop_data.GetSafeFilenameForImageFileContents();
-    if (filename) {
-      image_filename = filename->LossyDisplayName();
-    } else {
-      // Use the current timestamp as the image file name in case the file name
-      // is not retrieved from the source.
-      image_filename =
-          UTF8ToUTF16(base::NumberToString(
-                          base::Time::Now().since_origin().InMilliseconds()) +
-                      "." + image_extension);
-    }
-  }
-
-  ui::DropDataAndroid drop_data_android = ui::DropDataAndroid::Create(
-      text, gurl, file_content, image_extension, image_filename);
-
-  return drop_data_android.GetJavaObject();
-
-}  // ToJavaDropData
-
-}  // namespace content
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index fb42e5d..46d76b5 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -3764,6 +3764,58 @@
                                 site_a.GetURL("a.test", "/")));
 }
 
+// Tests that if `update_first_party_url_on_redirect` is set to false, download
+// will not behave like a top-level frame navigation and SameSite=Strict cookies
+// will not be set on a redirection.
+IN_PROC_BROWSER_TEST_F(
+    DownloadContentTest,
+    SiteForCookies_DownloadUrl_NotUpdateFirstPartyUrlOnRedirect) {
+  net::EmbeddedTestServer site_a;
+  net::EmbeddedTestServer site_b;
+
+  base::StringPairs cookie_headers;
+  cookie_headers.push_back(std::make_pair(
+      std::string("Set-Cookie"), std::string("A=strict; SameSite=Strict")));
+  cookie_headers.push_back(std::make_pair(std::string("Set-Cookie"),
+                                          std::string("B=lax; SameSite=Lax")));
+
+  // This will request a URL on b.test, which redirects to a url that sets the
+  // cookies on a.test.
+  site_a.RegisterRequestHandler(CreateBasicResponseHandler(
+      "/sets-samesite-cookies", net::HTTP_OK, cookie_headers,
+      "application/octet-stream", "abcd"));
+  ASSERT_TRUE(site_a.Start());
+  site_b.RegisterRequestHandler(
+      CreateRedirectHandler("/redirected-download",
+                            site_a.GetURL("a.test", "/sets-samesite-cookies")));
+  ASSERT_TRUE(site_b.Start());
+
+  // Download the file.
+  SetupEnsureNoPendingDownloads();
+  std::unique_ptr<download::DownloadUrlParameters> download_parameters(
+      DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
+          shell()->web_contents(),
+          site_b.GetURL("b.test", "/redirected-download"),
+          TRAFFIC_ANNOTATION_FOR_TESTS));
+  download_parameters->set_update_first_party_url_on_redirect(false);
+  std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
+  DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters));
+  observer->WaitForFinished();
+
+  // Get the important info from other threads and check it.
+  EXPECT_TRUE(EnsureNoPendingDownloads());
+
+  std::vector<download::DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(1u, downloads.size());
+  ASSERT_EQ(download::DownloadItem::COMPLETE, downloads[0]->GetState());
+
+  // Check that the cookies were not set on a.test.
+  EXPECT_EQ("",
+            content::GetCookies(shell()->web_contents()->GetBrowserContext(),
+                                site_a.GetURL("a.test", "/")));
+}
+
 // Verifies that isolation info set in DownloadUrlParameters can be populated.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
                        SiteForCookies_DownloadUrl_IsolationInfoPopulated) {
diff --git a/content/browser/media/capture/web_contents_frame_tracker.cc b/content/browser/media/capture/web_contents_frame_tracker.cc
index b2db5b20..f190fa2 100644
--- a/content/browser/media/capture/web_contents_frame_tracker.cc
+++ b/content/browser/media/capture/web_contents_frame_tracker.cc
@@ -76,7 +76,7 @@
   }
 
   float GetScaleOverrideForCapture() const override {
-    if (auto* view = GetCurrentView()) {
+    if (const auto* view = GetCurrentView()) {
       return view->GetScaleOverrideForCapture();
     }
     // Otherwise we can assume it's unset and return the default value.
@@ -155,6 +155,13 @@
 
   DVLOG(3) << __func__ << ": content_size=" << content_size.ToString();
   if (base::FeatureList::IsEnabled(media::kWebContentsCaptureHiDpi)) {
+    // The unscaled content size can be determined by removing the scale factor
+    // from the |content_size|.
+    const float scale_override = context_->GetScaleOverrideForCapture();
+    DCHECK_NE(0.0f, scale_override);
+    const gfx::Size unscaled_content_size =
+        gfx::ScaleToCeiledSize(content_size, 1.0f / scale_override);
+
     // Check if the capture scale needs to be modified. The content_size
     // provided here is the final pixel size, with all scale factors such as the
     // device scale factor and HiDPI capture scale already applied.
@@ -163,7 +170,8 @@
     // browser tab. If region capture is active, there will be an additional
     // call providing the region size. Lastly, if the scale was modified, there
     // will be another call with the upscaled size.
-    SetCaptureScaleOverride(CalculatePreferredScaleFactor(content_size));
+    SetCaptureScaleOverride(
+        CalculatePreferredScaleFactor(content_size, unscaled_content_size));
   }
 }
 
@@ -213,64 +221,83 @@
   return preferred_size;
 }
 
-// TODO(https://crbug.com/1329704): this should also include live updates
-// about system resource availability. Perhaps we can use FPS or the
-// lossyness of outputted frames?
 float WebContentsFrameTracker::CalculatePreferredScaleFactor(
-    const gfx::Size& content_size) {
+    const gfx::Size& current_content_size,
+    const gfx::Size& unscaled_current_content_size) {
   // A max factor above 2.0 would cause a quality degradation for local
   // rendering. The downscaling used by the compositor uses a linear filter
   // which only looks at 4 source pixels, so rendering more than 4 pixels per
   // destination pixel would result in information loss.
-  constexpr float kMaxFactor = 2.0f;
+  static constexpr float kMaxFactor = 2.0f;
 
-  // A minimum scale factor of less than 1.0 doesn't really make any sense: this
-  // would only occur if the "preferred size" is larger than the specified
-  // capture size, which should never happen.
-  constexpr float kMinFactor = 1.0f;
+  // A minimum factor of 1.0 means that no DPI scaling is applied.
+  static constexpr float kMinFactor = 1.0;
 
-  // The content rectangle is letterboxed within the capture size rectangle.
-  // Calculate the effective scaled size after this is applied, and use
-  // this size for ratio calculations.
+  // The content size does not include letterboxing, meaning that there may
+  // be an aspect ratio difference between the content size and the final
+  // capture size. For example, if the video frame consumer requests a 1080P
+  // video stream and the web contents has a size of 960x720 (ratio of 4:3), the
+  // letterboxed size here will be 1440x1080 (still 4:3). Graphically:
+  //
+  //    |capture_size_|
+  //    |----------------------------------------------------|
+  //    |    | |letterbox_size|                         | .  |
+  //    |    |     |-------------------------------|    |    |
+  //    |    |     | |content_size|                |    |    |
+  //    |    |     |-------------------------------|    |    |
+  //    |    |                                          |    |
+  //    |----------------------------------------------------|
+  //
+  // In order to preserve the aspect ratio of the web contents, we use this
+  // letterboxed size with the same aspect ratio instead of the requested
+  // capture size's aspect ratio.
   gfx::Size letterbox_size =
-      media::ComputeLetterboxRegion(gfx::Rect(capture_size_), content_size)
+      media::ComputeLetterboxRegion(gfx::Rect(capture_size_),
+                                    unscaled_current_content_size)
           .size();
 
-  // Ideally the |content_size| should be the same as |letterbox_size|, so if
-  // we are achieving that with current settings we can exit early. Also
-  // accept almost-equal sizes to avoid oscillations due to rounding errors.
-  if (std::abs(content_size.width() - letterbox_size.width()) < 4 &&
-      std::abs(content_size.height() - letterbox_size.height()) < 4) {
+  // Ideally the |current_content_size| should be the same as |letterbox_size|,
+  // so if we are achieving that with current settings we can exit early. Since
+  // we only scale by factors of 1/4, we accept a difference here of up to 1/8th
+  // of the letterboxed size, meaning that this scale factor would have been a
+  // more appropriate fit that a neighboring factor.
+  if (std::abs(current_content_size.width() - letterbox_size.width()) <=
+          (letterbox_size.width() / 8) &&
+      std::abs(current_content_size.height() - letterbox_size.height()) <=
+          (letterbox_size.height() / 8)) {
     return capture_scale_override_;
   }
 
-  // The content_size should already be scaled based on the currently set
-  // scale factor, so start by looking at what the content size would have been
-  // if scaling was not enabled.
-  const auto unscaled_content_size = gfx::ScaleToCeiledSize(
-      content_size, 1.0f / context_->GetScaleOverrideForCapture());
-
   // Next, determine what the ideal scale factors in each direction would have
-  // been for this frame. The factors should be nearly equal after letterboxing.
+  // been for this frame. Since we are using the letterboxed size here, the
+  // factors should be almost identical.
+  DCHECK_NE(0.0f, unscaled_current_content_size.width());
+  DCHECK_NE(0.0f, unscaled_current_content_size.height());
   const gfx::Vector2dF factors(static_cast<float>(letterbox_size.width()) /
-                                   unscaled_content_size.width(),
+                                   unscaled_current_content_size.width(),
                                static_cast<float>(letterbox_size.height()) /
-                                   unscaled_content_size.height());
+                                   unscaled_current_content_size.height());
 
   // We prefer to err on the side of having to downscale in one direction rather
   // than upscale in the other direction, so we use the largest scale factor.
   const float largest_factor = std::max(factors.x(), factors.y());
 
+  // Finally, we return a value bounded by [kMinFactor, kMaxFactor] rounded to
+  // the nearest quarter.
+  const float preferred_factor =
+      base::clamp(std::round(largest_factor * 4) / 4, kMinFactor, kMaxFactor);
   DVLOG(3) << __func__ << ":"
            << " capture_size_=" << capture_size_.ToString()
-           << " letterbox_size=" << letterbox_size.ToString()
-           << " content_size=" << content_size.ToString()
-           << " unscaled_content_size=" << unscaled_content_size.ToString()
-           << " context_->GetScaleOverrideForCapture()="
+           << ", letterbox_size=" << letterbox_size.ToString()
+           << ", current_content_size=" << current_content_size.ToString()
+           << ", unscaled_current_content_size="
+           << unscaled_current_content_size.ToString()
+           << ", context_->GetScaleOverrideForCapture()="
            << context_->GetScaleOverrideForCapture()
-           << " factors.x()=" << factors.x() << " factors.y()=" << factors.y()
-           << " largest_factor=" << largest_factor;
-  return std::clamp(largest_factor, kMinFactor, kMaxFactor);
+           << ", factors.x()=" << factors.x() << " factors.y()=" << factors.y()
+           << ", largest_factor=" << largest_factor
+           << ", preferred factor=" << preferred_factor;
+  return preferred_factor;
 }
 
 void WebContentsFrameTracker::RenderFrameCreated(
diff --git a/content/browser/media/capture/web_contents_frame_tracker.h b/content/browser/media/capture/web_contents_frame_tracker.h
index c58c83a..b884460f 100644
--- a/content/browser/media/capture/web_contents_frame_tracker.h
+++ b/content/browser/media/capture/web_contents_frame_tracker.h
@@ -86,16 +86,15 @@
   // the post" system is used and the first capturer's preferred size is set.
   gfx::Size CalculatePreferredSize(const gfx::Size& capture_size);
 
-  // Determines the preferred capture scale factor based on the content size and
-  // current conditions. This method requires the |content_size|, which is the
-  // resulting frame size from the first captured frame, and thus has an
-  // implicit relationship with |CalculatePreferredSize|, which is used to help
-  // size the backing WebContents before any frames are captured. Ideally, the
-  // result of calculating the preferred size results in a content size that
-  // does not need any scaling, however in practice this is not always true and
-  // we need to adjust the DPI of the WebContents to get an appropriately sized
-  // VideoFrame.
-  float CalculatePreferredScaleFactor(const gfx::Size& content_size);
+  // Determines the preferred DPI scaling factor based on the current content
+  // size of the video frame, meaning the populated pixels, and the unscaled
+  // current content size, meaning the original size of the frame before scaling
+  // was applied to fit the frame. These values are used to compare against
+  // the currently requested |capture_size_| set in
+  // |WillStartCapturingWebContents()|.
+  float CalculatePreferredScaleFactor(
+      const gfx::Size& current_content_size,
+      const gfx::Size& unscaled_current_content_size);
 
   // WebContentsObserver overrides.
   void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
@@ -188,7 +187,11 @@
   // changes.
   float capture_scale_override_ = 1.0f;
 
-  // The last set capture size.
+  // The consumer-requested capture size, set in |WillStartCapturingWebContents|
+  // to indicate the preferred frame size from the video frame consumer. Note
+  // that frames will not necessarily be this size due to a variety of reasons,
+  // so the |current_content_size| passed into |CalculatePreferredScaleFactor|
+  // may differ from this value.
   gfx::Size capture_size_;
 };
 
diff --git a/content/browser/media/capture/web_contents_frame_tracker_unittest.cc b/content/browser/media/capture/web_contents_frame_tracker_unittest.cc
index df9f4e1..0035784 100644
--- a/content/browser/media/capture/web_contents_frame_tracker_unittest.cc
+++ b/content/browser/media/capture/web_contents_frame_tracker_unittest.cc
@@ -441,5 +441,86 @@
   EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5);
 }
 
+TEST_F(WebContentsFrameTrackerTest, HighDpiIsRoundedIfBetweenBounds) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(media::kWebContentsCaptureHiDpi);
+
+  StartTrackerOnUIThread(kSize1080p);
+  RunAllTasksUntilIdle();
+
+  // Both factors should be 1.4f, which should be between bounds and rounded
+  // up.
+  tracker()->SetCapturedContentSize(gfx::Size{1370, 771});
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5);
+}
+
+TEST_F(WebContentsFrameTrackerTest, HighDpiIsRoundedIfBetweenDifferentBounds) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(media::kWebContentsCaptureHiDpi);
+
+  StartTrackerOnUIThread(kSize1080p);
+  RunAllTasksUntilIdle();
+
+  // Both factors should be 1.6f, which should be between bounds and rounded
+  // down.
+  tracker()->SetCapturedContentSize(gfx::Size{1200, 675});
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.5f);
+}
+
+TEST_F(WebContentsFrameTrackerTest, HighDpiIsRoundedToMinimum) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(media::kWebContentsCaptureHiDpi);
+
+  StartTrackerOnUIThread(kSize1080p);
+  RunAllTasksUntilIdle();
+
+  // Both factors should be 1.3f, which should be between bounds and rounded
+  // down.
+  tracker()->SetCapturedContentSize(gfx::Size{1477, 831});
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.25f);
+}
+
+TEST_F(WebContentsFrameTrackerTest, HighDpiIsRoundedToMaximum) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(media::kWebContentsCaptureHiDpi);
+
+  StartTrackerOnUIThread(kSize1080p);
+  RunAllTasksUntilIdle();
+
+  // Both factors should be well over the maximum of 2.0f.
+  tracker()->SetCapturedContentSize(gfx::Size{320, 240});
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 2.0f);
+}
+
+TEST_F(WebContentsFrameTrackerTest, HighDpiScalingIsStable) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(media::kWebContentsCaptureHiDpi);
+
+  StartTrackerOnUIThread(kSize1080p);
+  RunAllTasksUntilIdle();
+
+  // Both factors should be 1.25f, which should be exactly a scaling factor.
+  static constexpr gfx::Size kContentSize(1536, 864);
+  tracker()->SetCapturedContentSize(kContentSize);
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.25f);
+
+  // Now that its applied, it should stay the same.
+  static const gfx::Size kScaledContentSize =
+      gfx::ScaleToRoundedSize(kContentSize, 1.25f);
+  tracker()->SetCapturedContentSize(kScaledContentSize);
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.25f);
+
+  // If it varies slightly that shouldn't result in any changes.
+  static const gfx::Size kScaledLargerContentSize =
+      gfx::ScaleToRoundedSize(kContentSize, 1.27f);
+  tracker()->SetCapturedContentSize(kScaledLargerContentSize);
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.25f);
+
+  static const gfx::Size kScaledSmallerContentSize =
+      gfx::ScaleToRoundedSize(kContentSize, 1.23f);
+  tracker()->SetCapturedContentSize(kScaledSmallerContentSize);
+  EXPECT_DOUBLE_EQ(context()->scale_override(), 1.25f);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index dc58ae67..1ded872 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -16,7 +16,7 @@
 #include "cc/layers/layer.h"
 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
 #include "content/browser/android/content_ui_event_handler.h"
-#include "content/browser/android/drop_data_android_helper.h"
+#include "content/browser/android/drop_data_android.h"
 #include "content/browser/android/gesture_listener_manager.h"
 #include "content/browser/android/select_popup.h"
 #include "content/browser/android/selection/selection_popup_controller.h"
@@ -400,7 +400,9 @@
     case JNI_DragEvent::ACTION_DROP: {
       DropData drop_data;
       drop_data.did_originate_from_renderer = false;
-      std::u16string drop_content = event.drop_data_android().text();
+      JNIEnv* env = AttachCurrentThread();
+      std::u16string drop_content =
+          ConvertJavaStringToUTF16(env, event.GetJavaContent());
       for (const std::u16string& mime_type : event.mime_types()) {
         if (base::EqualsASCII(mime_type, ui::kMimeTypeURIList)) {
           drop_data.url = GURL(drop_content);
diff --git a/content/public/renderer/BUILD.gn b/content/public/renderer/BUILD.gn
index 1eab7f35..fecca011 100644
--- a/content/public/renderer/BUILD.gn
+++ b/content/public/renderer/BUILD.gn
@@ -58,6 +58,7 @@
   ]
 
   deps = [
+    "//components/cast_streaming/renderer:resource_provider",
     "//content/public/child:child_sources",
     "//content/public/common:common_sources",
     "//content/renderer",
diff --git a/content/public/renderer/DEPS b/content/public/renderer/DEPS
index 12f044c..9e762d3 100644
--- a/content/public/renderer/DEPS
+++ b/content/public/renderer/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/cast_streaming/renderer/public",
   "+content/common/media",
   "+content/public/child",
   "+gin",
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index de7f7113f..8eeeee017 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "build/build_config.h"
+#include "components/cast_streaming/renderer/public/resource_provider.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/demuxer.h"
 #include "media/base/renderer_factory.h"
diff --git a/content/test/fuzzer/media_stream_dispatcher_host_mojolpm_fuzzer.cc b/content/test/fuzzer/media_stream_dispatcher_host_mojolpm_fuzzer.cc
index c2aff0b..d670a177 100644
--- a/content/test/fuzzer/media_stream_dispatcher_host_mojolpm_fuzzer.cc
+++ b/content/test/fuzzer/media_stream_dispatcher_host_mojolpm_fuzzer.cc
@@ -184,6 +184,8 @@
     base::OnceClosure done_closure) {
   mojolpm::GetContext()->EndTestcase();
 
+  media_stream_manager_->WillDestroyCurrentMessageLoop();
+
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
       base::BindOnce(&MediaStreamDispatcherHostTestcase::TearDownOnUIThread,
@@ -194,8 +196,6 @@
     base::OnceClosure done_closure) {
   audio_manager_->Shutdown();
 
-  media_stream_manager_->WillDestroyCurrentMessageLoop();
-
   std::move(done_closure).Run();
 }
 
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 f8db36b0..7dad90a 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -295,6 +295,9 @@
 # Flakes on gpu-fyi-try-chromeos-kevin and Fuchsia x64, produces notably different image.
 crbug.com/1086687 [ chromeos chromeos-board-kevin ] Pixel_PrecisionRoundedCorner [ Failure ]
 
+# Flakes on gpu-fyi-try-chromeos-amd64-generic, times out.
+crbug.com/1338173 [ chromeos chromeos-board-amd64-generic ] Pixel_PrecisionRoundedCorner [ Failure ]
+
 # Flaky hang.
 crbug.com/1218288 [ fuchsia-board-astro ] Pixel_PrecisionRoundedCorner [ Failure ]
 crbug.com/1136875 [ fuchsia-board-qemu-x64 ] Pixel_PrecisionRoundedCorner [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 79539b4..ff196a22 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -105,6 +105,8 @@
 crbug.com/1337998 [ chromeos-board-kevin no-passthrough ] WebCodecs_Encode* [ Failure ]
 crbug.com/1337998 [ chromeos-board-kevin no-passthrough ] WebCodecs_TexImage2d_hw_decoder [ Failure ]
 
+crbug.com/1338182 [ mac asan ] WebCodecs_texture_expired_from_destroyed_device_capture [ Failure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/device/bluetooth/bluetooth_pairing_winrt.cc b/device/bluetooth/bluetooth_pairing_winrt.cc
index 190117e..77993b0 100644
--- a/device/bluetooth/bluetooth_pairing_winrt.cc
+++ b/device/bluetooth/bluetooth_pairing_winrt.cc
@@ -289,27 +289,26 @@
       pairing_requested_ = pairing_requested;
       expecting_pin_code_ = true;
       pairing_delegate_->RequestPinCode(device_);
-      break;
+      return;
     case DevicePairingKinds_ConfirmOnly:
       if (base::FeatureList::IsEnabled(
               features::kWebBluetoothConfirmPairingSupport)) {
         pairing_requested_ = pairing_requested;
         pairing_delegate_->AuthorizePairing(device_);
+        return;
       } else {
         DVLOG(2) << "DevicePairingKind = " << static_cast<int>(pairing_kind)
                  << " is not enabled by "
                     "enable-web-bluetooth-confirm-pairing-support";
-        std::move(callback_).Run(
-            BluetoothDevice::ConnectErrorCode::ERROR_FAILED);
-        return;
       }
       break;
     default:
       DVLOG(2) << "Unsupported DevicePairingKind = "
                << static_cast<int>(pairing_kind);
-      std::move(callback_).Run(BluetoothDevice::ConnectErrorCode::ERROR_FAILED);
-      return;
+      break;
   }
+  std::move(callback_).Run(
+      BluetoothDevice::ConnectErrorCode::ERROR_AUTH_FAILED);
 }
 
 void BluetoothPairingWinrt::OnPair(
diff --git a/gin/public/v8_platform.h b/gin/public/v8_platform.h
index c9b535e..2f2e0d6 100644
--- a/gin/public/v8_platform.h
+++ b/gin/public/v8_platform.h
@@ -43,7 +43,7 @@
       std::unique_ptr<v8::Task> task) override;
   void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
                                  double delay_in_seconds) override;
-  std::unique_ptr<v8::JobHandle> PostJob(
+  std::unique_ptr<v8::JobHandle> CreateJob(
       v8::TaskPriority priority,
       std::unique_ptr<v8::JobTask> job_task) override;
   bool IdleTasksEnabled(v8::Isolate* isolate) override;
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index 03cbb53..9e79f7e4 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -431,7 +431,7 @@
       base::Seconds(delay_in_seconds));
 }
 
-std::unique_ptr<v8::JobHandle> V8Platform::PostJob(
+std::unique_ptr<v8::JobHandle> V8Platform::CreateJob(
     v8::TaskPriority priority,
     std::unique_ptr<v8::JobTask> job_task) {
   base::TaskTraits task_traits;
@@ -450,19 +450,19 @@
   // |max_concurrency_callback| uses an unretained pointer.
   auto* job_task_ptr = job_task.get();
   auto handle =
-      base::PostJob(FROM_HERE, task_traits,
-                    base::BindRepeating(
-                        [](const std::unique_ptr<v8::JobTask>& job_task,
-                           base::JobDelegate* delegate) {
-                          JobDelegateImpl delegate_impl(delegate);
-                          job_task->Run(&delegate_impl);
-                        },
-                        std::move(job_task)),
-                    base::BindRepeating(
-                        [](v8::JobTask* job_task, size_t worker_count) {
-                          return job_task->GetMaxConcurrency(worker_count);
-                        },
-                        base::Unretained(job_task_ptr)));
+      base::CreateJob(FROM_HERE, task_traits,
+                      base::BindRepeating(
+                          [](const std::unique_ptr<v8::JobTask>& job_task,
+                             base::JobDelegate* delegate) {
+                            JobDelegateImpl delegate_impl(delegate);
+                            job_task->Run(&delegate_impl);
+                          },
+                          std::move(job_task)),
+                      base::BindRepeating(
+                          [](v8::JobTask* job_task, size_t worker_count) {
+                            return job_task->GetMaxConcurrency(worker_count);
+                          },
+                          base::Unretained(job_task_ptr)));
 
   return std::make_unique<JobHandleImpl>(std::move(handle));
 }
diff --git a/gpu/command_buffer/client/webgpu_implementation.cc b/gpu/command_buffer/client/webgpu_implementation.cc
index 7df29457..ac5697f 100644
--- a/gpu/command_buffer/client/webgpu_implementation.cc
+++ b/gpu/command_buffer/client/webgpu_implementation.cc
@@ -378,13 +378,22 @@
 #endif
 }
 
-ReservedTexture WebGPUImplementation::ReserveTexture(WGPUDevice device) {
+ReservedTexture WebGPUImplementation::ReserveTexture(
+    WGPUDevice device,
+    const WGPUTextureDescriptor* optionalDesc) {
 #if BUILDFLAG(USE_DAWN)
   // Commit because we need to make sure messages that free a previously used
   // texture are seen first. ReserveTexture may reuse an existing ID.
   dawn_wire_->serializer()->Commit();
 
-  auto reservation = dawn_wire_->wire_client()->ReserveTexture(device);
+  WGPUTextureDescriptor placeholderDesc;
+  if (optionalDesc == nullptr) {
+    placeholderDesc = {};  // Zero initialize.
+    optionalDesc = &placeholderDesc;
+  }
+
+  auto reservation =
+      dawn_wire_->wire_client()->ReserveTexture(device, optionalDesc);
   ReservedTexture result;
   result.texture = reservation.texture;
   result.id = reservation.id;
diff --git a/gpu/command_buffer/client/webgpu_implementation.h b/gpu/command_buffer/client/webgpu_implementation.h
index f80734ee..35a0bd09 100644
--- a/gpu/command_buffer/client/webgpu_implementation.h
+++ b/gpu/command_buffer/client/webgpu_implementation.h
@@ -92,7 +92,9 @@
   bool EnsureAwaitingFlush() override;
   void FlushAwaitingCommands() override;
   scoped_refptr<APIChannel> GetAPIChannel() const override;
-  ReservedTexture ReserveTexture(WGPUDevice device) override;
+  ReservedTexture ReserveTexture(
+      WGPUDevice device,
+      const WGPUTextureDescriptor* optionalDesc = nullptr) override;
   WGPUDevice DeprecatedEnsureDefaultDeviceSync() override;
 
  private:
diff --git a/gpu/command_buffer/client/webgpu_interface.h b/gpu/command_buffer/client/webgpu_interface.h
index 9712844..b8be9a64 100644
--- a/gpu/command_buffer/client/webgpu_interface.h
+++ b/gpu/command_buffer/client/webgpu_interface.h
@@ -65,7 +65,9 @@
   // Get a strong reference to the APIChannel backing the implementation.
   virtual scoped_refptr<APIChannel> GetAPIChannel() const = 0;
 
-  virtual ReservedTexture ReserveTexture(WGPUDevice device) = 0;
+  virtual ReservedTexture ReserveTexture(
+      WGPUDevice device,
+      const WGPUTextureDescriptor* optionalDesc = nullptr) = 0;
 
   // Gets or creates a usable WGPUDevice synchronously. It really should not
   // be used, and the async request adapter and request device APIs should be
diff --git a/gpu/command_buffer/client/webgpu_interface_stub.cc b/gpu/command_buffer/client/webgpu_interface_stub.cc
index da1ef631..92e2c15 100644
--- a/gpu/command_buffer/client/webgpu_interface_stub.cc
+++ b/gpu/command_buffer/client/webgpu_interface_stub.cc
@@ -53,7 +53,9 @@
   return false;
 }
 void WebGPUInterfaceStub::FlushAwaitingCommands() {}
-ReservedTexture WebGPUInterfaceStub::ReserveTexture(WGPUDevice) {
+ReservedTexture WebGPUInterfaceStub::ReserveTexture(
+    WGPUDevice,
+    const WGPUTextureDescriptor*) {
   return {nullptr, 0, 0, 0, 0};
 }
 
diff --git a/gpu/command_buffer/client/webgpu_interface_stub.h b/gpu/command_buffer/client/webgpu_interface_stub.h
index b6bdfe0..1fa14302 100644
--- a/gpu/command_buffer/client/webgpu_interface_stub.h
+++ b/gpu/command_buffer/client/webgpu_interface_stub.h
@@ -28,7 +28,9 @@
   void FlushCommands() override;
   bool EnsureAwaitingFlush() override;
   void FlushAwaitingCommands() override;
-  ReservedTexture ReserveTexture(WGPUDevice device) override;
+  ReservedTexture ReserveTexture(
+      WGPUDevice device,
+      const WGPUTextureDescriptor* optionalDesc) override;
 
   WGPUDevice DeprecatedEnsureDefaultDeviceSync() override;
 
diff --git a/gpu/command_buffer/service/native_image_buffer.cc b/gpu/command_buffer/service/native_image_buffer.cc
index 8a9ebc0f..4c2582a5 100644
--- a/gpu/command_buffer/service/native_image_buffer.cc
+++ b/gpu/command_buffer/service/native_image_buffer.cc
@@ -57,7 +57,7 @@
 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
     GLuint texture_id) {
   gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL();
-  EGLDisplay egl_display = display->GetHardwareDisplay();
+  EGLDisplay egl_display = display->GetDisplay();
   EGLContext egl_context = eglGetCurrentContext();
 
   DCHECK_NE(EGL_NO_CONTEXT, egl_context);
diff --git a/gpu/command_buffer/service/passthrough_program_cache.cc b/gpu/command_buffer/service/passthrough_program_cache.cc
index e9afda3..c4a9164 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.cc
+++ b/gpu/command_buffer/service/passthrough_program_cache.cc
@@ -44,7 +44,7 @@
       store_(ProgramLRUCache::NO_AUTO_EVICT) {
 #if defined(USE_EGL)
   gl::GLDisplayEGL* gl_display = gl::GLSurfaceEGL::GetGLDisplayEGL();
-  EGLDisplay egl_display = gl_display->GetHardwareDisplay();
+  EGLDisplay egl_display = gl_display->GetDisplay();
 
   DCHECK(!g_program_cache);
   g_program_cache = this;
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
index e459980..13968bf 100644
--- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -861,6 +861,62 @@
   webgpu()->FlushCommands();
 }
 
+// Test that passing a descriptor to ReserveTexture produces a client-side
+// WGPUTexture that correctly reflects said descriptor.
+TEST_P(WebGPUMailboxTest, ReflectionOfDescriptor) {
+  if (!WebGPUSupported()) {
+    LOG(ERROR) << "Test skipped because WebGPU isn't supported";
+    return;
+  }
+
+  wgpu::Device device = GetNewDevice();
+
+  // Check that reserving a texture with a full descriptor give the same data
+  // back through reflection.
+  wgpu::TextureDescriptor desc1 = {};
+  desc1.size = {1, 2, 3};
+  desc1.format = wgpu::TextureFormat::R32Float;
+  desc1.usage = wgpu::TextureUsage::CopyDst;
+  desc1.dimension = wgpu::TextureDimension::e2D;
+  desc1.sampleCount = 1;
+  desc1.mipLevelCount = 1;
+  gpu::webgpu::ReservedTexture reservation1 = webgpu()->ReserveTexture(
+      device.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc1));
+  wgpu::Texture texture1 = wgpu::Texture::Acquire(reservation1.texture);
+
+  ASSERT_EQ(desc1.size.width, texture1.GetWidth());
+  ASSERT_EQ(desc1.size.height, texture1.GetHeight());
+  ASSERT_EQ(desc1.size.depthOrArrayLayers, texture1.GetDepthOrArrayLayers());
+  ASSERT_EQ(desc1.format, texture1.GetFormat());
+  ASSERT_EQ(desc1.usage, texture1.GetUsage());
+  ASSERT_EQ(desc1.dimension, texture1.GetDimension());
+  ASSERT_EQ(desc1.sampleCount, texture1.GetSampleCount());
+  ASSERT_EQ(desc1.mipLevelCount, texture1.GetMipLevelCount());
+
+  // Test with a different descriptor to check data is not hardcoded. Not that
+  // this is actually not a valid descriptor (diimension == 1D with height !=
+  // 1), but that it should still be reflected exactly.
+  wgpu::TextureDescriptor desc2 = {};
+  desc2.size = {4, 5, 6};
+  desc2.format = wgpu::TextureFormat::RGBA8Unorm;
+  desc2.usage = wgpu::TextureUsage::CopySrc;
+  desc2.dimension = wgpu::TextureDimension::e1D;
+  desc2.sampleCount = 4;
+  desc2.mipLevelCount = 3;
+  gpu::webgpu::ReservedTexture reservation2 = webgpu()->ReserveTexture(
+      device.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc2));
+  wgpu::Texture texture2 = wgpu::Texture::Acquire(reservation2.texture);
+
+  ASSERT_EQ(desc2.size.width, texture2.GetWidth());
+  ASSERT_EQ(desc2.size.height, texture2.GetHeight());
+  ASSERT_EQ(desc2.size.depthOrArrayLayers, texture2.GetDepthOrArrayLayers());
+  ASSERT_EQ(desc2.format, texture2.GetFormat());
+  ASSERT_EQ(desc2.usage, texture2.GetUsage());
+  ASSERT_EQ(desc2.dimension, texture2.GetDimension());
+  ASSERT_EQ(desc2.sampleCount, texture2.GetSampleCount());
+  ASSERT_EQ(desc2.mipLevelCount, texture2.GetMipLevelCount());
+}
+
 INSTANTIATE_TEST_SUITE_P(,
                          WebGPUMailboxTest,
                          ::testing::ValuesIn(WebGPUMailboxTest::TestParams()),
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index d95ffa8..aebd98c 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -565,8 +565,7 @@
   // Populate the list of ANGLE features by querying the functions exposed by
   // EGL_ANGLE_feature_control if it's available.
   if (gl::g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) {
-    EGLDisplay display =
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+    EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
     EGLAttrib feature_count = 0;
     eglQueryDisplayAttribANGLE(display, EGL_FEATURE_COUNT_ANGLE,
                                &feature_count);
diff --git a/infra/config/generated/builders/try/linux-rel-compilator/properties.json b/infra/config/generated/builders/try/linux-rel-compilator/properties.json
index 09dfeb0..cde009ac 100644
--- a/infra/config/generated/builders/try/linux-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux-rel-compilator/properties.json
@@ -157,6 +157,9 @@
     ],
     "use_clang_coverage": true
   },
+  "$build/flakiness": {
+    "check_for_flakiness": true
+  },
   "$build/goma": {
     "enable_ats": true,
     "jobs": 150,
diff --git a/infra/config/generated/builders/try/linux-rel/properties.json b/infra/config/generated/builders/try/linux-rel/properties.json
index 534966c..ed2efae5 100644
--- a/infra/config/generated/builders/try/linux-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-rel/properties.json
@@ -161,6 +161,9 @@
     ],
     "use_clang_coverage": true
   },
+  "$build/flakiness": {
+    "check_for_flakiness": true
+  },
   "$recipe_engine/resultdb/test_presentation": {
     "column_keys": [],
     "grouping_keys": [
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index e7597bb..008fb99f 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -3438,6 +3438,88 @@
       }
     }
     builders {
+      name: "Comparison ios (reclient)"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cpu:x86-64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Mac-11|Mac-12"
+      dimensions: "pool:luci.chromium.ci"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/goma": {'
+        '    "jobs": 250,'
+        '    "rpc_extra_params": "?prod",'
+        '    "server_host": "goma.chromium.org",'
+        '    "use_luci_auth": true'
+        '  },'
+        '  "$build/reclient": {'
+        '    "cache_silo": "Comparison ios - cache siloed",'
+        '    "instance": "rbe-chromium-trusted",'
+        '    "jobs": 250,'
+        '    "metrics_project": "chromium-reclient-metrics"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "chromium.fyi",'
+        '  "recipe": "reclient_goma_comparison",'
+        '  "xcode_build_version": "13c100"'
+        '}'
+      execution_timeout_secs: 36000
+      caches {
+        name: "xcode_ios_13c100"
+        path: "xcode_ios_13c100.app"
+      }
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "CrWinAsan"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 6fb3847..6e2aa1a 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -8039,6 +8039,11 @@
     short_name: "lcr"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Comparison ios (reclient)"
+    category: "ios"
+    short_name: "cmp"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/lacros-amd64-generic-rel-fyi"
     category: "lacros"
     short_name: "lcr"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index cab9cd75..9c6f959 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -700,6 +700,16 @@
   }
 }
 job {
+  id: "Comparison ios (reclient)"
+  realm: "ci"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "Comparison ios (reclient)"
+  }
+}
+job {
   id: "CrWinAsan"
   realm: "ci"
   acl_sets: "ci"
@@ -6886,6 +6896,7 @@
   triggers: "Comparison Simple Chrome (reclient)"
   triggers: "Comparison Windows (8 cores) (reclient)"
   triggers: "Comparison Windows (reclient)"
+  triggers: "Comparison ios (reclient)"
   triggers: "CrWinAsan"
   triggers: "CrWinAsan(dll)"
   triggers: "Dawn Linux x64 Builder"
diff --git a/infra/config/scripts/tests/branch_day_unit_test.py b/infra/config/scripts/tests/branch_day_unit_test.py
index 9a206b03..f6867aa 100755
--- a/infra/config/scripts/tests/branch_day_unit_test.py
+++ b/infra/config/scripts/tests/branch_day_unit_test.py
@@ -6,6 +6,7 @@
 
 import json
 import os
+import shutil
 import subprocess
 import tempfile
 import unittest
@@ -29,7 +30,7 @@
                       self._dev_star)
 
     for path in self._binaries:
-      os.symlink(MOCK_PY, path)
+      shutil.copy2(MOCK_PY, path)
 
   def tearDown(self):
     self._temp_dir.cleanup()
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
index 8e63ae2..1dc28ee0 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -12,7 +12,8 @@
     cores = 8,
     executable = ci.DEFAULT_EXECUTABLE,
     execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT,
-    goma_backend = goma.backend.RBE_PROD,
+    reclient_instance = rbe_instance.DEFAULT,
+    reclient_jobs = rbe_jobs.DEFAULT,
     notifies = ["chromesec-lkgr-failures"],
     os = os.LINUX_DEFAULT,
     pool = ci.DEFAULT_POOL,
@@ -60,9 +61,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -74,9 +73,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -88,9 +84,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 5,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -102,9 +96,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -116,9 +107,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -131,9 +120,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -145,9 +131,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -158,9 +141,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 6,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -172,9 +153,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -186,9 +165,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -203,6 +180,8 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 2,
     ),
+    goma_backend = goma.backend.RBE_PROD,
+    reclient_instance = None,
 )
 
 ci.builder(
@@ -217,6 +196,8 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 2,
     ),
+    goma_backend = goma.backend.RBE_PROD,
+    reclient_instance = None,
 )
 
 ci.builder(
@@ -228,9 +209,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -242,9 +221,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 3,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -256,9 +233,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -270,9 +245,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 4,
     ),
-    goma_backend = None,
     reclient_jobs = 250,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -286,9 +259,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 7,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -302,9 +273,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 6,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -317,9 +286,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 3,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -333,6 +300,8 @@
     execution_timeout = 4 * time.hour,
     os = os.MAC_12,
     xcode = xcode.x13main,
+    goma_backend = goma.backend.RBE_PROD,
+    reclient_instance = None,
 )
 
 ci.builder(
@@ -345,9 +314,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 5,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -360,9 +327,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 5,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
     execution_timeout = 4 * time.hour,
 )
 
@@ -376,9 +341,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 5,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -394,9 +357,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 5,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -409,9 +370,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 1,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -424,9 +382,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 1,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -439,9 +394,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 3,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -454,9 +407,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 3,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -469,9 +420,7 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 1,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -484,9 +433,6 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 1,
     ),
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.DEFAULT,
-    reclient_instance = rbe_instance.DEFAULT,
 )
 
 ci.builder(
@@ -499,6 +445,8 @@
     executable = "recipe:chromium_libfuzzer",
     execution_timeout = 4 * time.hour,
     os = os.MAC_DEFAULT,
+    goma_backend = goma.backend.RBE_PROD,
+    reclient_instance = None,
 )
 
 ci.builder(
@@ -514,7 +462,5 @@
     triggering_policy = scheduler.greedy_batching(
         max_concurrent_invocations = 3,
     ),
-    goma_backend = None,
     reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
 )
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index c671ca2..b6d9362 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -881,6 +881,24 @@
 )
 
 ci.builder(
+    name = "Comparison ios (reclient)",
+    builderless = True,
+    console_view_entry = consoles.console_view_entry(
+        category = "ios",
+        short_name = "cmp",
+    ),
+    goma_jobs = 250,
+    executable = "recipe:reclient_goma_comparison",
+    execution_timeout = 10 * time.hour,
+    reclient_cache_silo = "Comparison ios - cache siloed",
+    reclient_instance = rbe_instance.DEFAULT,
+    reclient_jobs = 250,
+    os = os.MAC_DEFAULT,
+    cores = None,
+    xcode = xcode.x13main,
+)
+
+ci.builder(
     name = "Linux Builder (j-500) (reclient)",
     console_view_entry = consoles.console_view_entry(
         category = "linux",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index 856372f..0a03cc99 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -225,6 +225,7 @@
     name = "linux-rel",
     compilator = "linux-rel-compilator",
     branch_selector = branches.STANDARD_MILESTONE,
+    check_for_flakiness = True,
     mirrors = [
         "ci/Linux Builder",
         "ci/Linux Tests",
@@ -249,6 +250,7 @@
 try_.compilator_builder(
     name = "linux-rel-compilator",
     branch_selector = branches.STANDARD_MILESTONE,
+    check_for_flakiness = True,
     main_list_view = "try",
 )
 
diff --git a/ios/chrome/browser/translate/translate_infobar_metrics_recorder.h b/ios/chrome/browser/translate/translate_infobar_metrics_recorder.h
index 4e7dd2e..1a97f94 100644
--- a/ios/chrome/browser/translate/translate_infobar_metrics_recorder.h
+++ b/ios/chrome/browser/translate/translate_infobar_metrics_recorder.h
@@ -62,14 +62,9 @@
 + (void)recordModalEvent:(MobileMessagesTranslateModalEvent)event;
 // Records a histogram for |presentEvent|.
 + (void)recordModalPresent:(MobileMessagesTranslateModalPresent)presentEvent;
-// Records a histogram for the time an unused legacy infobar persists on screen.
-+ (void)recordUnusedLegacyInfobarScreenDuration:(NSTimeInterval)duration;
 // Records a histogram for an infobar (both legacy and Messages) that the user
 // did not interact with throughout its lifetime.
 + (void)recordUnusedInfobar;
-// Records a histogram for the time between tapping the target and source
-// language in a legacy infobar.
-+ (void)recordLegacyInfobarToggleDelay:(NSTimeInterval)delay;
 @end
 
 #endif  // IOS_CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_METRICS_RECORDER_H_
diff --git a/ios/chrome/browser/translate/translate_infobar_metrics_recorder.mm b/ios/chrome/browser/translate/translate_infobar_metrics_recorder.mm
index 714d8534..f7ead64 100644
--- a/ios/chrome/browser/translate/translate_infobar_metrics_recorder.mm
+++ b/ios/chrome/browser/translate/translate_infobar_metrics_recorder.mm
@@ -30,22 +30,9 @@
                             presentEvent);
 }
 
-+ (void)recordUnusedLegacyInfobarScreenDuration:(NSTimeInterval)duration {
-  base::TimeDelta timeDelta = base::Seconds(duration);
-  // TODO(crbug.com/1025440): Use function version of macros.
-  UMA_HISTOGRAM_MEDIUM_TIMES("Mobile.Legacy.Translate.Unused.Duration",
-                             timeDelta);
-}
-
 + (void)recordUnusedInfobar {
   // TODO(crbug.com/1025440): Use function version of macros.
   UMA_HISTOGRAM_COUNTS_10M("Mobile.Translate.Unused.Count", 1);
 }
 
-+ (void)recordLegacyInfobarToggleDelay:(NSTimeInterval)delay {
-  base::TimeDelta timeDelta = base::Seconds(delay);
-  // TODO(crbug.com/1025440): Use function version of macros.
-  UMA_HISTOGRAM_MEDIUM_TIMES("Mobile.Legacy.Translate.Toggle.Delay", timeDelta);
-}
-
 @end
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 08b7866..3ce0b392 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -1026,6 +1026,15 @@
   }
 }
 
+- (void)showHelpPage {
+  GURL helpUrl(l10n_util::GetStringUTF16(IDS_IOS_TOOLS_MENU_HELP_URL));
+  UrlLoadParams params = UrlLoadParams::InNewTab(helpUrl);
+  params.append_to = kCurrentTab;
+  params.user_initiated = NO;
+  params.in_incognito = self.browser->GetBrowserState()->IsOffTheRecord();
+  UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
+}
+
 - (void)showAddCreditCard {
   [self.addCreditCardCoordinator start];
 }
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 09f7810..0b615ae 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -3757,16 +3757,6 @@
   [_voiceSearchController prepareToAppear];
 }
 
-// TODO(crbug.com/1329106): Move `showHelpPage` out of the BVC.
-- (void)showHelpPage {
-  GURL helpUrl(l10n_util::GetStringUTF16(IDS_IOS_TOOLS_MENU_HELP_URL));
-  UrlLoadParams params = UrlLoadParams::InNewTab(helpUrl);
-  params.append_to = kCurrentTab;
-  params.user_initiated = NO;
-  params.in_incognito = self.isOffTheRecord;
-  UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
-}
-
 // TODO(crbug.com/1329107): Move `showBookmarksManager` out of the BVC.
 - (void)showBookmarksManager {
   [self initializeBookmarkInteractionController];
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 3b04357..611e5f7 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -55,9 +55,6 @@
 // Closes all tabs.
 - (void)closeAllTabs;
 
-// Shows the online help page in a tab.
-- (void)showHelpPage;
-
 // Shows the bookmarks manager.
 - (void)showBookmarksManager;
 
diff --git a/ios/chrome/browser/ui/commands/browser_coordinator_commands.h b/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
index 6eb9996e..0248b748 100644
--- a/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_coordinator_commands.h
@@ -56,6 +56,9 @@
 // devices.
 - (void)showSendTabToSelfUI:(const GURL&)url title:(NSString*)title;
 
+// Shows the online help page in a tab.
+- (void)showHelpPage;
+
 // Displays the Badge popup menu showing |badgeItems|.
 - (void)displayPopupMenuWithBadgeItems:(NSArray<id<BadgeItem>>*)badgeItems;
 
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm
index f5749112..e0edc71 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm
@@ -31,6 +31,7 @@
 #include "ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/policy/enterprise_policy_test_helper.h"
+#import "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_swift.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h"
@@ -139,13 +140,19 @@
     return mediator_;
   }
 
-  void CreatePrefs() {
-    prefs_ = std::make_unique<TestingPrefServiceSimple>();
-    prefs_->registry()->RegisterBooleanPref(
+  void CreateBrowserStatePrefs() {
+    browserStatePrefs_ = std::make_unique<TestingPrefServiceSimple>();
+    browserStatePrefs_->registry()->RegisterBooleanPref(
         bookmarks::prefs::kEditBookmarksEnabled,
         /*default_value=*/true);
   }
 
+  void CreateLocalStatePrefs() {
+    localStatePrefs_ = std::make_unique<TestingPrefServiceSimple>();
+    localStatePrefs_->registry()->RegisterDictionaryPref(
+        prefs::kOverflowMenuDestinationUsageHistory, PrefRegistry::LOSSY_PREF);
+  }
+
   void SetUpBookmarks() {
     bookmark_model_ =
         ios::BookmarkModelFactory::GetForBrowserState(browser_state_.get());
@@ -223,7 +230,8 @@
   FakeOverlayPresentationContext presentation_context_;
   OverflowMenuMediator* mediator_;
   BookmarkModel* bookmark_model_;
-  std::unique_ptr<TestingPrefServiceSimple> prefs_;
+  std::unique_ptr<TestingPrefServiceSimple> browserStatePrefs_;
+  std::unique_ptr<TestingPrefServiceSimple> localStatePrefs_;
   web::FakeWebState* web_state_;
   std::unique_ptr<web::NavigationItem> navigation_item_;
   UIViewController* baseViewController_;
@@ -249,7 +257,10 @@
 // Tests that the mediator is returning the right number of items and sections
 // for the Tools Menu type.
 TEST_F(OverflowMenuMediatorTest, TestMenuItemsCount) {
+  CreateLocalStatePrefs();
   CreateMediator(/*is_incognito=*/NO);
+  mediator_.localStatePrefs = localStatePrefs_.get();
+
   NSUInteger number_of_action_items = 5;
   if (ios::provider::IsTextZoomEnabled()) {
     number_of_action_items++;
@@ -287,9 +298,11 @@
 // Tests that the items returned by the mediator are correctly enabled on a
 // WebPage.
 TEST_F(OverflowMenuMediatorTest, TestItemsStatusOnWebPage) {
+  CreateLocalStatePrefs();
   CreateMediator(/*is_incognito=*/NO);
   SetUpActiveWebState();
   mediator_.webStateList = browser_->GetWebStateList();
+  mediator_.localStatePrefs = localStatePrefs_.get();
 
   // Force creation of the model.
   [mediator_ overflowMenuModel];
@@ -304,9 +317,11 @@
 // Tests that the items returned by the mediator are correctly enabled on the
 // NTP.
 TEST_F(OverflowMenuMediatorTest, TestItemsStatusOnNTP) {
+  CreateLocalStatePrefs();
   CreateMediator(/*is_incognito=*/NO);
   SetUpActiveWebState();
   mediator_.webStateList = browser_->GetWebStateList();
+  mediator_.localStatePrefs = localStatePrefs_.get();
 
   // Force creation of the model.
   [mediator_ overflowMenuModel];
@@ -324,13 +339,13 @@
 TEST_F(OverflowMenuMediatorTest, TestReadLaterDisabled) {
   const GURL kUrl("https://chromium.test");
   web_state_->SetCurrentURL(kUrl);
-  CreatePrefs();
+  CreateBrowserStatePrefs();
   CreateMediator(/*is_incognito=*/NO);
   SetUpActiveWebState();
   mediator_.webStateList = browser_->GetWebStateList();
   mediator_.webContentAreaOverlayPresenter = OverlayPresenter::FromBrowser(
       browser_.get(), OverlayModality::kWebContentArea);
-  mediator_.browserStatePrefs = prefs_.get();
+  mediator_.browserStatePrefs = browserStatePrefs_.get();
 
   // Force creation of the model.
   [mediator_ overflowMenuModel];
@@ -430,12 +445,12 @@
   SetUpActiveWebState();
 
   CreateMediator(/*is_incognito=*/NO);
-  CreatePrefs();
+  CreateBrowserStatePrefs();
   SetUpBookmarks();
   bookmarks::AddIfNotBookmarked(bookmark_model_, bookmarkedURL,
                                 base::SysNSStringToUTF16(@"Test bookmark"));
   mediator_.webStateList = browser_->GetWebStateList();
-  mediator_.browserStatePrefs = prefs_.get();
+  mediator_.browserStatePrefs = browserStatePrefs_.get();
 
   // Force creation of the model.
   [mediator_ overflowMenuModel];
@@ -463,15 +478,16 @@
   SetUpActiveWebState();
 
   CreateMediator(/*is_incognito=*/NO);
-  CreatePrefs();
+  CreateBrowserStatePrefs();
   mediator_.webStateList = browser_->GetWebStateList();
-  mediator_.browserStatePrefs = prefs_.get();
+  mediator_.browserStatePrefs = browserStatePrefs_.get();
 
   // Force creation of the model.
   [mediator_ overflowMenuModel];
 
   EXPECT_TRUE(HasItem(kToolsMenuAddToBookmarks, /*enabled=*/YES));
 
-  prefs_->SetBoolean(bookmarks::prefs::kEditBookmarksEnabled, false);
+  browserStatePrefs_->SetBoolean(bookmarks::prefs::kEditBookmarksEnabled,
+                                 false);
   EXPECT_TRUE(HasItem(kToolsMenuAddToBookmarks, /*enabled=*/NO));
 }
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index 70bce04..cc22379 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -195,7 +195,7 @@
   ]
 }
 
-optimize_js("chrome_bundle_main_frame") {
+optimize_js("language_detection_js") {
   primary_script =
       "//components/translate/ios/browser/resources/language_detection.js"
   sources =
@@ -209,7 +209,7 @@
     "chrome_web_client.mm",
   ]
   deps = [
-    ":chrome_bundle_main_frame",
+    ":language_detection_js",
     ":web",
     "//base",
     "//components/autofill/ios/browser",
diff --git a/ios/chrome/browser/web/resources/PRESUBMIT.py b/ios/chrome/browser/web/resources/PRESUBMIT.py
deleted file mode 100644
index f27aab5..0000000
--- a/ios/chrome/browser/web/resources/PRESUBMIT.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Makes sure that injected JavaScript is clang-format clean."""
-
-USE_PYTHON3 = True
-
-
-def CheckChangeOnUpload(input_api, output_api):
-  """Special Top level function called by git_cl."""
-  return input_api.canned_checks.CheckPatchFormatted(
-      input_api, output_api, check_js=True)
diff --git a/ios/chrome/browser/web/resources/chrome_bundle_main_frame.js b/ios/chrome/browser/web/resources/chrome_bundle_main_frame.js
deleted file mode 100644
index 22c94816..0000000
--- a/ios/chrome/browser/web/resources/chrome_bundle_main_frame.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The set of scripts to be injected into the web view as early as possible.
-goog.provide('__crWeb.chromeBundleMainFrame');
-
-// DEPRECATED
-// Do NOT add new features here, but rather add them using an instance of
-// JavaScriptFeature. Please see the documentation at
-// //ios/web/public/js_messaging/README.md
-goog.require('__crWeb.languageDetection');
diff --git a/ios/testing/earl_grey/base_earl_grey_test_case.mm b/ios/testing/earl_grey/base_earl_grey_test_case.mm
index 3a09405d..bc57b94 100644
--- a/ios/testing/earl_grey/base_earl_grey_test_case.mm
+++ b/ios/testing/earl_grey/base_earl_grey_test_case.mm
@@ -87,9 +87,11 @@
   // The same screen object is shared across multiple test runs on IOS build.
   // Make sure that all display observers are removed at the end of each
   // test.
-  display::ScreenBase* screen =
-      static_cast<display::ScreenBase*>(display::Screen::GetScreen());
-  DCHECK(!screen->HasDisplayObservers());
+  if (display::Screen::HasScreen()) {
+    display::ScreenBase* screen =
+        static_cast<display::ScreenBase*>(display::Screen::GetScreen());
+    DCHECK(!screen->HasDisplayObservers());
+  }
 #endif
   if ([[AppLaunchManager sharedManager] appIsLaunched]) {
     [CoverageUtils writeClangCoverageProfile];
diff --git a/media/formats/hls/media_playlist.cc b/media/formats/hls/media_playlist.cc
index 2dfa7d0..821f19f 100644
--- a/media/formats/hls/media_playlist.cc
+++ b/media/formats/hls/media_playlist.cc
@@ -339,11 +339,21 @@
     return ParseStatusCode::kMediaPlaylistMissingTargetDuration;
   }
   const auto target_duration = target_duration_tag->duration;
+  if (target_duration > kMaxTargetDuration) {
+    return ParseStatusCode::kTargetDurationExceedsMax;
+  }
 
   absl::optional<PartialSegmentInfo> partial_segment_info;
   if (part_inf_tag.has_value()) {
     partial_segment_info = MediaPlaylist::PartialSegmentInfo{
         .target_duration = part_inf_tag->target_duration};
+
+    // Since the combination of partial segments should be equivalent to their
+    // parent segment, the partial segment target duration should not exceed the
+    // parent segment target duration.
+    if (partial_segment_info->target_duration > target_duration) {
+      return ParseStatusCode::kPartTargetDurationExceedsTargetDuration;
+    }
   }
 
   bool can_skip_dateranges = false;
@@ -395,9 +405,17 @@
   // Ensure that no segment exceeds the target duration
   base::TimeDelta total_duration;
   for (const auto& segment : segments) {
+    // The spec says that the segment duration should not exceed the target
+    // duration after rounding to the nearest integer.
+    // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.1
     const auto rounded_duration =
         std::round(segment.GetDuration().InSecondsF());
-    if (rounded_duration > target_duration.InSecondsF()) {
+
+    // Compare the rounded segment duration to the target duration (as an
+    // integer). Target duration should always be an integer of seconds, so to
+    // avoid floating-point precision issues we use `InSeconds()` rather than
+    // `InSecondsF()`.
+    if (rounded_duration > target_duration.InSeconds()) {
       return ParseStatusCode::kMediaSegmentExceedsTargetDuration;
     }
 
diff --git a/media/formats/hls/media_playlist.h b/media/formats/hls/media_playlist.h
index c369f735..7152786 100644
--- a/media/formats/hls/media_playlist.h
+++ b/media/formats/hls/media_playlist.h
@@ -23,6 +23,11 @@
 
 class MEDIA_EXPORT MediaPlaylist final : public Playlist {
  public:
+  // Several values in HLS are based on the playlist's target duration, to avoid
+  // overflow issues we limit this to a large value.
+  static constexpr base::TimeDelta kMaxTargetDuration =
+      base::TimeDelta::FiniteMax() / 10;
+
   // This structure describes information about partial segments in the
   // playlist.
   struct PartialSegmentInfo {
diff --git a/media/formats/hls/media_playlist_unittest.cc b/media/formats/hls/media_playlist_unittest.cc
index 2bab439d..a5729a13 100644
--- a/media/formats/hls/media_playlist_unittest.cc
+++ b/media/formats/hls/media_playlist_unittest.cc
@@ -182,37 +182,41 @@
 }
 
 TEST(HlsMediaPlaylistTest, TotalDuration) {
-  constexpr types::DecimalInteger kLargeDuration =
-      (base::TimeDelta::FiniteMax() / 2.5).InSeconds();
+  constexpr types::DecimalInteger kSegmentDuration =
+      MediaPlaylist::kMaxTargetDuration.InSeconds();
+  constexpr size_t kMaxSegments =
+      base::TimeDelta::FiniteMax().InSeconds() / kSegmentDuration;
+
+  // Make sure this test won't take an unreasonable amount of time to run
+  static_assert(kMaxSegments < 1000);
 
   // Ensure that if we have a playlist large enough where the total duration
   // overflows `base::TimeDelta`, this is caught.
   MediaPlaylistTestBuilder builder;
   builder.AppendLine("#EXTM3U");
   builder.AppendLine("#EXT-X-TARGETDURATION:" +
-                     base::NumberToString(kLargeDuration));
-  builder.ExpectPlaylist(HasTargetDuration, base::Seconds(kLargeDuration));
+                     base::NumberToString(kSegmentDuration));
+  builder.ExpectPlaylist(HasTargetDuration, base::Seconds(kSegmentDuration));
 
-  builder.AppendLine("#EXTINF:" + base::NumberToString(kLargeDuration) + ",\t");
-  builder.AppendLine("segment0.ts");
-  builder.ExpectAdditionalSegment();
-  builder.ExpectSegment(HasDuration, base::Seconds(kLargeDuration));
-  builder.ExpectSegment(HasUri, GURL("http://localhost/segment0.ts"));
+  for (size_t i = 0; i < kMaxSegments; ++i) {
+    builder.AppendLine("#EXTINF:" + base::NumberToString(kSegmentDuration) +
+                       ",\t");
+    builder.AppendLine("segment" + base::NumberToString(i) + ".ts");
+    builder.ExpectAdditionalSegment();
+    builder.ExpectSegment(HasDuration, base::Seconds(kSegmentDuration));
+    builder.ExpectSegment(HasUri, GURL("http://localhost/segment" +
+                                       base::NumberToString(i) + ".ts"));
+  }
 
-  builder.AppendLine("#EXTINF:" + base::NumberToString(kLargeDuration) + ",\t");
-  builder.AppendLine("segment1.ts");
-  builder.ExpectAdditionalSegment();
-  builder.ExpectSegment(HasDuration, base::Seconds(kLargeDuration));
-  builder.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
-
-  // These two shouldn't overflow base::TimeDelta
+  // The segments above should not overflow the playlist duration
   builder.ExpectPlaylist(HasComputedDuration,
-                         base::Seconds(kLargeDuration * 2));
+                         base::Seconds(kSegmentDuration * kMaxSegments));
   builder.ExpectOk();
 
   // But an additional segment would
-  builder.AppendLine("#EXTINF:" + base::NumberToString(kLargeDuration) + ",\t");
-  builder.AppendLine("segment3.ts");
+  builder.AppendLine("#EXTINF:" + base::NumberToString(kSegmentDuration) +
+                     ",\t");
+  builder.AppendLine("segmentX.ts");
   builder.ExpectError(ParseStatusCode::kPlaylistOverflowsTimeDelta);
 }
 
@@ -486,6 +490,24 @@
     builder2.AppendLine("#EXT-X-TARGETDURATION:", x);
     builder2.ExpectError(ParseStatusCode::kMalformedTag);
   }
+
+  // The target duration value may not exceed this implementation's max
+  builder = MediaPlaylistTestBuilder();
+  builder.AppendLine("#EXTM3U");
+  builder.AppendLine(
+      "#EXT-X-TARGETDURATION:",
+      base::NumberToString(MediaPlaylist::kMaxTargetDuration.InSeconds()));
+  builder.ExpectPlaylist(
+      HasTargetDuration,
+      base::Seconds(MediaPlaylist::kMaxTargetDuration.InSeconds()));
+  builder.ExpectOk();
+
+  builder = MediaPlaylistTestBuilder();
+  builder.AppendLine("#EXTM3U");
+  builder.AppendLine(
+      "#EXT-X-TARGETDURATION:",
+      base::NumberToString(MediaPlaylist::kMaxTargetDuration.InSeconds() + 1));
+  builder.ExpectError(ParseStatusCode::kTargetDurationExceedsMax);
 }
 
 TEST(HlsMediaPlaylistTest, XEndListTag) {
@@ -1095,7 +1117,7 @@
 TEST(HlsMediaPlaylistTest, XPartInfTag) {
   MediaPlaylistTestBuilder builder;
   builder.AppendLine("#EXTM3U");
-  builder.AppendLine("#EXT-X-TARGETDURATION:10");
+  builder.AppendLine("#EXT-X-TARGETDURATION:100");
   builder.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=500");
 
   // EXT-X-PART-INF tag must be well-formed
@@ -1133,6 +1155,19 @@
                           .target_duration = base::Seconds(99.99)});
   fork.ExpectOk();
 
+  // PART-TARGET may not exceed the playlist's target duration
+  fork = builder;
+  fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=100");
+  fork.ExpectPlaylist(HasTargetDuration, base::Seconds(100));
+  fork.ExpectPlaylist(
+      HasPartialSegmentInfo,
+      MediaPlaylist::PartialSegmentInfo{.target_duration = base::Seconds(100)});
+  fork.ExpectOk();
+
+  fork = builder;
+  fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=101");
+  fork.ExpectError(ParseStatusCode::kPartTargetDurationExceedsTargetDuration);
+
   // The EXT-X-PART-INF tag may not appear twice
   fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=10");
   fork.ExpectError(ParseStatusCode::kPlaylistHasDuplicateTags);
diff --git a/media/formats/hls/parse_status.cc b/media/formats/hls/parse_status.cc
index b877fd1..e22fa66 100644
--- a/media/formats/hls/parse_status.cc
+++ b/media/formats/hls/parse_status.cc
@@ -32,6 +32,7 @@
     PARSE_STATUS_CODE_CASE(kInvalidUri);
     PARSE_STATUS_CODE_CASE(kPlaylistMissingM3uTag);
     PARSE_STATUS_CODE_CASE(kMediaPlaylistMissingTargetDuration);
+    PARSE_STATUS_CODE_CASE(kTargetDurationExceedsMax);
     PARSE_STATUS_CODE_CASE(kMediaSegmentMissingInfTag);
     PARSE_STATUS_CODE_CASE(kMediaSegmentExceedsTargetDuration);
     PARSE_STATUS_CODE_CASE(kPlaylistHasDuplicateTags);
@@ -53,6 +54,7 @@
     PARSE_STATUS_CODE_CASE(kPlaylistOverflowsTimeDelta);
     PARSE_STATUS_CODE_CASE(kSkipBoundaryTooLow);
     PARSE_STATUS_CODE_CASE(kHoldBackDistanceTooLow);
+    PARSE_STATUS_CODE_CASE(kPartTargetDurationExceedsTargetDuration);
     PARSE_STATUS_CODE_CASE(kPartHoldBackDistanceTooLow);
     PARSE_STATUS_CODE_CASE(kPartInfTagWithoutPartHoldBack);
   }
diff --git a/media/formats/hls/parse_status.h b/media/formats/hls/parse_status.h
index a0b0b63..01a9bc4 100644
--- a/media/formats/hls/parse_status.h
+++ b/media/formats/hls/parse_status.h
@@ -29,6 +29,7 @@
   kInvalidUri,
   kPlaylistMissingM3uTag,
   kMediaPlaylistMissingTargetDuration,
+  kTargetDurationExceedsMax,
   kMediaSegmentMissingInfTag,
   kMediaSegmentExceedsTargetDuration,
   kPlaylistHasDuplicateTags,
@@ -50,6 +51,7 @@
   kPlaylistOverflowsTimeDelta,
   kSkipBoundaryTooLow,
   kHoldBackDistanceTooLow,
+  kPartTargetDurationExceedsTargetDuration,
   kPartHoldBackDistanceTooLow,
   kPartInfTagWithoutPartHoldBack,
 };
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index 98f1e2e..4785d49e 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -201,7 +201,7 @@
   scoped_refptr<V4L2Device> device = V4L2Device::Create();
   if (device.get()) {
     decoder.reset(new V4L2VideoDecodeAccelerator(
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
+        gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
         gl_client_.get_context, gl_client_.make_context_current, device));
   }
   return decoder;
@@ -216,7 +216,7 @@
   scoped_refptr<V4L2Device> device = V4L2Device::Create();
   if (device.get()) {
     decoder.reset(new V4L2SliceVideoDecodeAccelerator(
-        device, gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
+        device, gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
         gl_client_.bind_image, gl_client_.make_context_current));
   }
   return decoder;
diff --git a/media/gpu/windows/dxva_picture_buffer_win.cc b/media/gpu/windows/dxva_picture_buffer_win.cc
index d2a422431..fa4837b 100644
--- a/media/gpu/windows/dxva_picture_buffer_win.cc
+++ b/media/gpu/windows/dxva_picture_buffer_win.cc
@@ -65,8 +65,7 @@
 
  private:
   ~GLImagePbuffer() override {
-    EGLDisplay egl_display =
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+    EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
     eglReleaseTexImage(egl_display, surface_, EGL_BACK_BUFFER);
 
@@ -172,8 +171,7 @@
   RETURN_ON_FAILURE(!picture_buffer_.service_texture_ids().empty(),
                     "No service texture ids provided", false);
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   EGLint use_rgb = 1;
   eglGetConfigAttrib(egl_display, egl_config, EGL_BIND_TO_TEXTURE_RGB,
                      &use_rgb);
@@ -370,8 +368,7 @@
     RETURN_ON_FAILURE(result == S_OK, "Could not acquire sync mutex", false);
   }
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   eglBindTexImage(egl_display, decoding_surface_, EGL_BACK_BUFFER);
 
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -401,8 +398,7 @@
 bool PbufferPictureBuffer::ReusePictureBuffer() {
   DCHECK_NE(UNUSED, state_);
   DCHECK(decoding_surface_);
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   eglReleaseTexImage(egl_display, decoding_surface_, EGL_BACK_BUFFER);
 
   decoder_surface_.Reset();
@@ -427,8 +423,7 @@
   RETURN_ON_FAILURE(picture_buffer_.service_texture_ids().size() >= 2,
                     "Not enough texture ids provided", false);
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   const EGLint stream_attributes[] = {
       EGL_CONSUMER_LATENCY_USEC_KHR,
       0,
@@ -473,8 +468,7 @@
 
 bool EGLStreamPictureBuffer::ReusePictureBuffer() {
   DCHECK_NE(UNUSED, state_);
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
   if (stream_) {
     EGLBoolean result = eglStreamConsumerReleaseKHR(egl_display, stream_);
@@ -497,8 +491,7 @@
   shared_images_.resize(picture_buffer_.service_texture_ids().size());
 
   current_d3d_sample_ = sample;
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
   Microsoft::WRL::ComPtr<IMFMediaBuffer> output_buffer;
   HRESULT hr = current_d3d_sample_->GetBufferByIndex(0, &output_buffer);
@@ -554,8 +547,7 @@
   RETURN_ON_FAILURE(picture_buffer_.service_texture_ids().size() >= 2,
                     "Not enough texture ids provided", false);
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   const EGLint stream_attributes[] = {
       EGL_CONSUMER_LATENCY_USEC_KHR,
       0,
@@ -670,8 +662,7 @@
   RETURN_ON_FAILURE(picture_buffer_.service_texture_ids().size() >= 2,
                     "Not enough texture ids provided", false);
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   const EGLint stream_attributes[] = {
       EGL_CONSUMER_LATENCY_USEC_KHR,
       0,
@@ -793,8 +784,7 @@
       EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE,
   };
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
   EGLBoolean result = eglStreamPostD3DTextureANGLE(
       egl_display, stream_, static_cast<void*>(angle_copy_texture_.Get()),
@@ -813,8 +803,7 @@
 
 bool EGLStreamCopyPictureBuffer::ReusePictureBuffer() {
   DCHECK_NE(UNUSED, state_);
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
   if (state_ == IN_CLIENT) {
     HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_);
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index 88c4996..39f3dafa4 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -1558,7 +1558,7 @@
   if (!display->ext->b_EGL_EXT_pixel_format_float)
     use_fp16_ = false;
 
-  EGLDisplay egl_display = display->GetHardwareDisplay();
+  EGLDisplay egl_display = display->GetDisplay();
 
   while (true) {
     std::vector<EGLint> config_attribs = {EGL_BUFFER_SIZE,  32,
diff --git a/mojo/docs/basics.md b/mojo/docs/basics.md
index d4e42f6..5a3bddc 100644
--- a/mojo/docs/basics.md
+++ b/mojo/docs/basics.md
@@ -117,7 +117,7 @@
 
 Used when the receiver/callee creates the endpoints. One endpoint is retained
 for itself to receive IPCs, and the other endpoint is returned as an unbound
-`mojo::PendingRemote<T>` for the sender/callee to bind to a `mojo::Remote<T>`.
+`mojo::PendingRemote<T>` for the sender/caller to bind to a `mojo::Remote<T>`.
 
 ```c++
 class MathImpl : public math::mojom::MathImpl {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 6e94dd60..c6a443d 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -26,6 +26,11 @@
       "all"
     ]
   },
+  "Comparison ios (reclient)": {
+    "additional_compile_targets": [
+      "all"
+    ]
+  },
   "Linux Builder (j-500) (reclient)": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index fb38b44..8308964 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -10317,10 +10317,231 @@
     ]
   },
   "Mac FYI Experimental Release (Apple M1)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "angle_unittests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_unittests",
+        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "browser_tests",
+        "test_id_prefix": "ninja://chrome/test:browser_tests/"
+      },
+      {
+        "args": [
+          "--use-cmd-decoder=passthrough",
+          "--use-gl=angle",
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "gl_tests",
+        "test_id_prefix": "ninja://gpu:gl_tests/"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gl_unittests",
+        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gles2_conform_test",
+        "test_id_prefix": "ninja://gpu/gles2_conform_support:gles2_conform_test/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gpu_unittests",
+        "test_id_prefix": "ninja://gpu:gpu_unittests/"
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "services_unittests",
+        "test_id_prefix": "ninja://services:services_unittests/"
+      }
+    ],
     "isolated_scripts": [
       {
         "args": [
-          "noop_sleep",
+          "context_lost",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "gpu_process",
           "--show-stdout",
           "--browser=release",
           "--passthrough",
@@ -10332,7 +10553,11 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "noop_sleep_tests",
+        "name": "gpu_process_launch_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
         "should_retry_with_patch": false,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -10342,7 +10567,518 @@
               "cpu": "arm64",
               "display_attached": "1",
               "mac_model": "Macmini9,1",
-              "os": "Mac-11",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
+          "--expected-vendor-id",
+          "106b",
+          "--expected-device-id",
+          "0"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
+          "--dont-restore-color-profile-after-test",
+          "--test-machine-name",
+          "${buildername}",
+          "--git-revision=${got_revision}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_passthrough_test",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "mediapipe",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_higher_performance_gpu --use-cmd-decoder=passthrough --use-gl=angle"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "mediapipe_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
+          "--dont-restore-color-profile-after-test",
+          "--test-machine-name",
+          "${buildername}",
+          "--git-revision=${got_revision}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_passthrough_test",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webcodecs",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webcodecs_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 20
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=metal --use-cmd-decoder=passthrough --force_high_performance_gpu",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_metal_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 20
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=metal --use-cmd-decoder=passthrough --force_high_performance_gpu",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_metal_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
+              "pool": "chromium.tests"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 3
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=swiftshader --use-cmd-decoder=passthrough --force_high_performance_gpu",
+          "--test-filter=conformance/rendering/gl-drawelements.html"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_swangle_passthrough_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "display_attached": "1",
+              "mac_model": "Macmini9,1",
+              "os": "Mac-12",
               "pool": "chromium.tests"
             }
           ],
diff --git a/testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter
index 159c6be..1334a1c 100644
--- a/testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter
@@ -71,6 +71,3 @@
 -org.chromium.chrome.browser.tabmodel.UndoTabModelTest.testOpenRecentlyClosedTabMultiWindow
 -org.chromium.chrome.browser.tabmodel.UndoTabModelTest.testOpenRecentlyClosedTabMultiWindowFallback
 -org.chromium.chrome.browser.tasks.tab_management.TabSwitcherMultiWindowTest.*
-
-# crbug.com/1297678
--org.chromium.ui.base.ClipboardAndroidTest.*
diff --git a/testing/buildbot/filters/android.emulator_12.chrome_public_unit_test_apk.filter b/testing/buildbot/filters/android.emulator_12.chrome_public_unit_test_apk.filter
index 53ba18b8..75375f8 100644
--- a/testing/buildbot/filters/android.emulator_12.chrome_public_unit_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_12.chrome_public_unit_test_apk.filter
@@ -1,2 +1,5 @@
 # crbug.com/1297682
 -org.chromium.chrome.browser.download.DownloadForegroundServiceManagerTest.*
+
+# crbug.com/1297678
+-org.chromium.ui.base.ClipboardAndroidTest.*
diff --git a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
index b0bb0b6..9cc4d72 100644
--- a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
+++ b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
@@ -1,7 +1,5 @@
 # These tests cannot work on Wayland because the platform does not allow clients
 # to position top level windows, activate them, and set focus.
--All/HostedOrWebAppTest.CtrlClickLink/HostedApp
--All/HostedOrWebAppTest.CtrlClickLink/WebApp
 -All/PopupBrowserTest.MoveClampedToCurrentDisplay/0
 -All/PopupBrowserTest.MoveClampedToCurrentDisplay/1
 -AutomationManagerAuraBrowserTest.EventFromAction
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index c12127e..4459138 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -844,7 +844,18 @@
       },
     },
   },
-  'mac_arm64_apple_m1_gpu': {
+  'mac_arm64_apple_m1_gpu_experimental': {
+    'swarming': {
+      'dimensions': {
+        'cpu': 'arm64',
+        'mac_model': 'Macmini9,1',
+        'os': 'Mac-12',
+        'pool': 'chromium.tests',
+        'display_attached': '1',
+      },
+    },
+  },
+  'mac_arm64_apple_m1_gpu_stable': {
     'swarming': {
       'dimensions': {
         'cpu': 'arm64',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d1afb14..4b6b4386 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2729,6 +2729,20 @@
           'all'
         ],
       },
+      'Comparison ios (reclient)': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'mixins': [
+          'has_native_resultdb_integration',
+          'isolate_profile_data',
+          'mac_11_or_12_x64',
+          'mac_toolchain',
+          'out_dir_arg',
+          'xcode_13_main',
+          'xctest',
+        ],
+      },
       'Linux Builder (j-500) (reclient)': {
         # Copied from
         # https://source.chromium.org/chromium/chromium/src/+/main:testing/buildbot/waterfalls.pyl;l=4844-4854;drc=75f767e92e86611728189739fb26f4e2cdf212d9
@@ -4489,13 +4503,14 @@
         'os_type': 'mac',
         'browser_config': 'release',
         'mixins': [
-          'mac_arm64_apple_m1_gpu',
+          'mac_arm64_apple_m1_gpu_experimental',
         ],
         # When the experimental OS version is identical to the stable version,
         # the gpu_noop_sleep_telemetry_test test should be used. Otherwise, this
         # should have the same test_suites as 'Mac FYI Release (Apple M1)'.
         'test_suites': {
-          'gpu_telemetry_tests': 'gpu_noop_sleep_telemetry_test',
+          'gtest_tests': 'gpu_fyi_mac_release_gtests',
+          'gpu_telemetry_tests': 'gpu_fyi_mac_release_telemetry_tests',
         },
       },
       'Mac FYI Experimental Release (Intel)': {
@@ -4545,7 +4560,7 @@
         'os_type': 'mac',
         'browser_config': 'release',
         'mixins': [
-          'mac_arm64_apple_m1_gpu',
+          'mac_arm64_apple_m1_gpu_stable',
         ],
         'test_suites': {
           'gtest_tests': 'gpu_fyi_mac_release_gtests',
diff --git a/third_party/android_lint/.gitignore b/third_party/android_lint/.gitignore
new file mode 100644
index 0000000..18c89ec
--- /dev/null
+++ b/third_party/android_lint/.gitignore
@@ -0,0 +1 @@
+lint.jar
diff --git a/third_party/android_lint/3pp/3pp.pb b/third_party/android_lint/3pp/3pp.pb
new file mode 100644
index 0000000..388f771
--- /dev/null
+++ b/third_party/android_lint/3pp/3pp.pb
@@ -0,0 +1,22 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+create {
+  source {
+    script {
+      name: "fetch.py"
+      use_fetch_checkout_workflow: true
+    }
+  }
+
+  build {
+    install: "install.py"
+    tool: "chromium/third_party/maven"
+    dep: "chromium/third_party/jdk"
+  }
+}
+
+upload {
+  pkg_prefix: "chromium/third_party"
+  universal: true
+}
diff --git a/third_party/android_lint/3pp/fetch.py b/third_party/android_lint/3pp/fetch.py
new file mode 100755
index 0000000..4677b89
--- /dev/null
+++ b/third_party/android_lint/3pp/fetch.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script is customized based on 3ppFetch.template.
+
+import argparse
+import re
+import urllib.request
+
+_REPO_URL = 'https://dl.google.com/android/maven2'
+_GROUP_NAME = 'com/android/tools/lint'
+_MODULE_NAME = 'lint'
+_OVERRIDE_LATEST = None
+_PATCH_VERSION = 'cr0'
+
+
+def do_latest():
+    if _OVERRIDE_LATEST is not None:
+        print(_OVERRIDE_LATEST + f'.{_PATCH_VERSION}')
+        return
+    maven_metadata_url = '{}/{}/{}/maven-metadata.xml'.format(
+        _REPO_URL, _GROUP_NAME, _MODULE_NAME)
+    metadata = urllib.request.urlopen(maven_metadata_url).read().decode(
+        'utf-8')
+    # Do not parse xml with the python included parser since it is susceptible
+    # to maliciously crafted xmls. Only use regular expression parsing to be
+    # safe. RE should be enough to handle what we need to extract.
+    match = re.search('<latest>([^<]+)</latest>', metadata)
+    if match:
+        latest = match.group(1)
+    else:
+        # if no latest info was found just hope the versions are sorted and the
+        # last one is the latest (as is commonly the case).
+        latest = re.findall('<version>([^<]+)</version>', metadata)[-1]
+    print(latest + f'.{_PATCH_VERSION}')
+
+
+def do_checkout():
+    # Everything is done in install.py. This method allows us to bypass having
+    # to download an unnecessary file.
+    pass
+
+
+def main():
+    argparser = argparse.ArgumentParser()
+    subparser = argparser.add_subparsers()
+
+    latest = subparser.add_parser('latest')
+    latest.set_defaults(func=do_latest)
+
+    checkout = subparser.add_parser('checkout')
+    checkout.add_argument("checkout_path")  # Needed only to avoid parse error.
+    checkout.set_defaults(func=do_checkout)
+
+    args = argparser.parse_args()
+    args.func()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/third_party/android_lint/3pp/install.py b/third_party/android_lint/3pp/install.py
new file mode 100755
index 0000000..e687641
--- /dev/null
+++ b/third_party/android_lint/3pp/install.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import subprocess
+import sys
+
+_GROUP_ID = 'com.android.tools.lint'
+_ARTIFACT_ID = 'lint'
+_FINAL_NAME = 'lint.jar'
+
+_POM_TEMPLATE = """\
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>group</groupId>
+  <artifactId>artifact</artifactId>
+  <version>1</version>
+  <dependencies>
+    <dependency>
+      <groupId>{group_id}</groupId>
+      <artifactId>{artifact_id}</artifactId>
+      <version>{version}</version>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>3.3.0</version>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <repositories>
+    <repository>
+      <id>google</id>
+      <name>google</name>
+      <url>https://maven.google.com/</url>
+    </repository>
+  </repositories>
+</project>
+"""
+
+
+def main(output_prefix: str, deps_prefix: str):
+    # Remove the patch version at the end: 30.4.0-alpha05.cr0 => 30.4.0-alpha05
+    version = os.environ['_3PP_VERSION'].rsplit('.', 1)[0]
+    with open('pom.xml', 'w') as f:
+        f.write(
+            _POM_TEMPLATE.format(version=version,
+                                 group_id=_GROUP_ID,
+                                 artifact_id=_ARTIFACT_ID))
+
+    # Set up JAVA_HOME for the mvn command to find the JDK.
+    env = os.environ.copy()
+    env['JAVA_HOME'] = os.path.join(deps_prefix, 'current')
+
+    # Ensure that mvn works and the environment is set up correctly.
+    subprocess.run(['mvn', '-v'], check=True, env=env)
+
+    # Build the jar file, explicitly specify -f to reduce sources of error.
+    subprocess.run(['mvn', 'clean', 'assembly:single', '-f', 'pom.xml'],
+                   check=True,
+                   env=env)
+
+    # Move and rename output to the upload directory. Moving only the jar avoids
+    # polluting the output directory with maven intermediate outputs.
+    os.makedirs(output_prefix, exist_ok=True)
+    shutil.move('target/artifact-1-jar-with-dependencies.jar',
+                os.path.join(output_prefix, _FINAL_NAME))
+
+
+if __name__ == '__main__':
+    main(sys.argv[1], sys.argv[2])
diff --git a/third_party/android_lint/LICENSE b/third_party/android_lint/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/android_lint/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/android_lint/OWNERS b/third_party/android_lint/OWNERS
new file mode 100644
index 0000000..7200601
--- /dev/null
+++ b/third_party/android_lint/OWNERS
@@ -0,0 +1,3 @@
+file://build/android/OWNERS
+
+wnwen@chromium.org
diff --git a/third_party/android_lint/README.chromium b/third_party/android_lint/README.chromium
new file mode 100644
index 0000000..40c0ad2
--- /dev/null
+++ b/third_party/android_lint/README.chromium
@@ -0,0 +1,20 @@
+Name: Android SDK lint
+Short Name: lint
+Version: unknown
+License: Apache Version 2.0
+License File: NOT_SHIPPED
+Security Critical: No
+URL: http://tools.android.com/tips/lint
+
+Description:
+Android lint is used to scan Android source code for potential bugs.
+
+Local Modifications:
+None
+
+What version is this:
+  * New instances are uploaded by the packager bot:
+    https://ci.chromium.org/p/chromium/builders/ci/3pp-linux-amd64-packager
+  * The bot autoruns every 6 hours. Ping a trooper or a clank-build-core@ dev to
+    trigger it if you need it sooner:
+    https://luci-scheduler.appspot.com/jobs/chromium/3pp-linux-amd64-packager
diff --git a/third_party/blink/public/web/web_element.h b/third_party/blink/public/web/web_element.h
index f795f64..af80bdb8 100644
--- a/third_party/blink/public/web/web_element.h
+++ b/third_party/blink/public/web/web_element.h
@@ -116,6 +116,12 @@
   // Returns the original image size.
   gfx::Size GetImageSize();
 
+  // Returns {clientWidth, clientHeight}.
+  gfx::Size GetClientSize();
+
+  // Returns {scrollWidth, scrollHeight}.
+  gfx::Size GetScrollSize();
+
   // ComputedStyle property values. The following exposure is of CSS property
   // values are part of the ComputedStyle set which is usually exposed through
   // the Window object in WebIDL as window.getComputedStyle(element). Exposing
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc
index 3c83396..e7eeef2 100644
--- a/third_party/blink/renderer/core/css/css_selector.cc
+++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/pseudo_element.h"
+#include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
@@ -71,9 +72,10 @@
   DCHECK_NE(Match(), kTag);
   if (has_rare_data_)
     return;
-  // This transitions the DataUnion from |value_| to |rare_data_| and thus needs to be careful to
-  // correctly manage explicitly destruction of |value_| followed by placement new of |rare_data_|.
-  // A straight-assignment will compile and may kinda work, but will be undefined behavior.
+  // This transitions the DataUnion from |value_| to |rare_data_| and thus needs
+  // to be careful to correctly manage explicitly destruction of |value_|
+  // followed by placement new of |rare_data_|. A straight-assignment will
+  // compile and may kinda work, but will be undefined behavior.
   auto rare_data = RareData::Create(data_.value_);
   data_.value_.~AtomicString();
   new (&data_.rare_data_) scoped_refptr<RareData>(std::move(rare_data));
@@ -1059,7 +1061,9 @@
                                AttributeMatchType match_type) {
   CreateRareData();
   data_.rare_data_->attribute_ = value;
-  data_.rare_data_->bits_.attribute_match_ = match_type;
+  data_.rare_data_->bits_.attr_.attribute_match_ = match_type;
+  data_.rare_data_->bits_.attr_.is_case_sensitive_attribute_ =
+      HTMLDocument::IsCaseSensitiveAttribute(value);
 }
 
 void CSSSelector::SetArgument(const AtomicString& value) {
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h
index 646bf8a..ccfa832 100644
--- a/third_party/blink/renderer/core/css/css_selector.h
+++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -305,7 +305,7 @@
     kPseudoPageTransitionIncomingImage,
   };
 
-  enum class AttributeMatchType {
+  enum class AttributeMatchType : int {
     kCaseSensitive,
     kCaseInsensitive,
     kCaseSensitiveAlways,
@@ -341,6 +341,7 @@
   // http://www.w3.org/TR/css3-selectors/#attrnmsp
   const QualifiedName& Attribute() const;
   AttributeMatchType AttributeMatch() const;
+  bool IsCaseSensitiveAttribute() const;
   // Returns the argument of a parameterized selector. For example, :lang(en-US)
   // would have an argument of en-US.
   // Note that :nth-* selectors don't store an argument and just store the
@@ -487,8 +488,12 @@
         int a_;  // Used for :nth-*
         int b_;  // Used for :nth-*
       } nth_;
-      AttributeMatchType
-          attribute_match_;  // used for attribute selector (with value)
+
+      struct {
+        AttributeMatchType
+            attribute_match_;  // used for attribute selector (with value)
+        bool is_case_sensitive_attribute_;
+      } attr_;
 
       struct {
         // Used for :has() with pseudos in its argument. e.g. :has(:hover)
@@ -511,8 +516,8 @@
   };
   void CreateRareData();
 
-  // The type tag for DataUnion is actually inferred from multiple state variables in the
-  // containing CSSSelector using the following rules.
+  // The type tag for DataUnion is actually inferred from multiple state
+  // variables in the containing CSSSelector using the following rules.
   //
   //  if (match_ == kTag) {
   //     /* data_.tag_q_name_ is valid */
@@ -522,10 +527,10 @@
   //     /* data_.value_ is valid */
   //  }
   //
-  // Note that it is important to placement-new and explicitly destruct the fields when
-  // shifting between types tags for a DataUnion! Otherwise there will be undefined
-  // behavior! This luckily only happens when transitioning from a normal |value_| to
-  // a |rare_data_|.
+  // Note that it is important to placement-new and explicitly destruct the
+  // fields when shifting between types tags for a DataUnion! Otherwise there
+  // will be undefined behavior! This luckily only happens when transitioning
+  // from a normal |value_| to a |rare_data_|.
   union DataUnion {
     enum ConstructUninitializedTag { kConstructUninitialized };
     explicit DataUnion(ConstructUninitializedTag) {}
@@ -553,7 +558,13 @@
 inline CSSSelector::AttributeMatchType CSSSelector::AttributeMatch() const {
   DCHECK(IsAttributeSelector());
   DCHECK(has_rare_data_);
-  return data_.rare_data_->bits_.attribute_match_;
+  return data_.rare_data_->bits_.attr_.attribute_match_;
+}
+
+inline bool CSSSelector::IsCaseSensitiveAttribute() const {
+  DCHECK(IsAttributeSelector());
+  DCHECK(has_rare_data_);
+  return data_.rare_data_->bits_.attr_.is_case_sensitive_attribute_;
 }
 
 inline bool CSSSelector::IsASCIILower(const AtomicString& value) {
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index d744c1310..06f365d 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -566,9 +566,8 @@
     // Legacy dictates that values of some attributes should be compared in
     // a case-insensitive manner regardless of whether the case insensitive
     // flag is set or not.
-    bool legacy_case_insensitive =
-        IsA<HTMLDocument>(element.GetDocument()) &&
-        !HTMLDocument::IsCaseSensitiveAttribute(selector_attr);
+    bool legacy_case_insensitive = IsA<HTMLDocument>(element.GetDocument()) &&
+                                   !selector.IsCaseSensitiveAttribute();
 
     // If case-insensitive, re-check, and count if result differs.
     // See http://code.google.com/p/chromium/issues/detail?id=327060
diff --git a/third_party/blink/renderer/core/exported/web_element.cc b/third_party/blink/renderer/core/exported/web_element.cc
index 3fbf2ef..5e11ef9 100644
--- a/third_party/blink/renderer/core/exported/web_element.cc
+++ b/third_party/blink/renderer/core/exported/web_element.cc
@@ -196,6 +196,16 @@
   return gfx::Size(image->width(), image->height());
 }
 
+gfx::Size WebElement::GetClientSize() {
+  Element* element = Unwrap<Element>();
+  return gfx::Size(element->clientWidth(), element->clientHeight());
+}
+
+gfx::Size WebElement::GetScrollSize() {
+  Element* element = Unwrap<Element>();
+  return gfx::Size(element->scrollWidth(), element->scrollHeight());
+}
+
 WebString WebElement::GetComputedValue(const WebString& property_name) {
   if (IsNull())
     return WebString();
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc
index d3423dd..b765f6b 100644
--- a/third_party/blink/renderer/core/page/focus_controller.cc
+++ b/third_party/blink/renderer/core/page/focus_controller.cc
@@ -1020,8 +1020,9 @@
 
   document->UpdateStyleAndLayout(DocumentUpdateReason::kFocus);
   ScopedFocusNavigation scope =
-      current ? ScopedFocusNavigation::CreateFor(*current, owner_map)
-              : ScopedFocusNavigation::CreateForDocument(*document, owner_map);
+      (current && current->IsInTreeScope())
+          ? ScopedFocusNavigation::CreateFor(*current, owner_map)
+          : ScopedFocusNavigation::CreateForDocument(*document, owner_map);
   Element* element =
       FindFocusableElementAcrossFocusScopes(type, scope, owner_map);
   if (!element) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 848153b6..196618c 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -610,11 +610,8 @@
     }
   }
 
-  if (RuntimeEnabledFeatures::FixedElementsDontOverscrollEnabled()) {
-    property_tree_manager.SetOverscrollTransformNodeId(
-        ids.overscroll_elasticity_transform);
-    property_tree_manager.SetFixedElementsDontOverscroll(true);
-  }
+  property_tree_manager.SetFixedElementsDontOverscroll(
+      RuntimeEnabledFeatures::FixedElementsDontOverscrollEnabled());
   layer_tree_host->RegisterViewportPropertyIds(ids);
 }
 
@@ -690,10 +687,6 @@
     int effect_id = property_tree_manager.SwitchToEffectNodeWithSynthesizedClip(
         effect, clip, layer.draws_content());
 
-    if (RuntimeEnabledFeatures::FixedElementsDontOverscrollEnabled() &&
-        transform.RequiresCompositingForFixedToViewport())
-      property_tree_manager.SetOverscrollClipNodeId(clip_id);
-
     // We need additional bookkeeping for backdrop-filter mask.
     if (effect.RequiresCompositingForBackdropFilterMask() &&
         effect.CcNodeId(g_s_property_tree_sequence_number) == effect_id) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 9926830..30158e9 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -382,14 +382,6 @@
   }
 }
 
-void PropertyTreeManager::SetOverscrollTransformNodeId(const int id) {
-  transform_tree_.set_overscroll_node_id(id);
-}
-
-void PropertyTreeManager::SetOverscrollClipNodeId(const int id) {
-  clip_tree_.set_overscroll_node_id(id);
-}
-
 void PropertyTreeManager::SetFixedElementsDontOverscroll(const bool value) {
   transform_tree_.set_fixed_elements_dont_overscroll(value);
 }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index 1efabd8c..37ff59e5 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -113,9 +113,6 @@
 
   int EnsureCompositorPageScaleTransformNode(const TransformPaintPropertyNode&);
 
-  // Used to offset the scroll translation during overscroll.
-  void SetOverscrollTransformNodeId(const int id);
-  void SetOverscrollClipNodeId(const int id);
   void SetFixedElementsDontOverscroll(const bool value);
 
   // This function is expected to be invoked right before emitting each layer.
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
index cfc41475..39239fb4 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -39,6 +39,7 @@
       client_(client),
       device_(device),
       usage_(usage),
+      wgpu_format_(format),
       format_(WGPUFormatToViz(format)) {
   // Create a layer that will be used by the canvas and will ask for a
   // SharedImage each frame.
@@ -185,8 +186,20 @@
   webgpu->WaitSyncTokenCHROMIUM(
       current_swap_buffer_->access_finished_token.GetConstData());
 
-  // Associate the mailbox to a dawn_wire client DawnTexture object
-  gpu::webgpu::ReservedTexture reservation = webgpu->ReserveTexture(device_);
+  // Associate the mailbox to a dawn_wire client DawnTexture object. Pass in a
+  // complete descriptor of the texture so that reflection on GPUTexture from
+  // canvases gives the correct result.
+  WGPUTextureDescriptor texDesc = {};
+  texDesc.size = {static_cast<uint32_t>(size.width()),
+                  static_cast<uint32_t>(size.height()), 1};
+  texDesc.format = wgpu_format_;
+  texDesc.usage = usage_;
+  texDesc.dimension = WGPUTextureDimension_2D;
+  texDesc.mipLevelCount = 1;
+  texDesc.sampleCount = 1;
+
+  gpu::webgpu::ReservedTexture reservation =
+      webgpu->ReserveTexture(device_, &texDesc);
   DCHECK(reservation.texture);
   wire_device_id_ = reservation.deviceId;
   wire_device_generation_ = reservation.deviceGeneration;
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
index f7053726..7dd9bf8 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -112,6 +112,7 @@
   bool neutered_ = false;
 
   WGPUTextureUsage usage_;
+  WGPUTextureFormat wgpu_format_;
 
   // The maximum number of in-flight swap-buffers waiting to be used for
   // recycling.
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
index 1375a9c..7bc31021 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
 
 using testing::_;
+using testing::Invoke;
 using testing::Return;
 
 namespace blink {
@@ -27,7 +28,9 @@
     procs()->deviceRelease = [](WGPUDevice) {};
   }
 
-  MOCK_METHOD1(ReserveTexture, gpu::webgpu::ReservedTexture(WGPUDevice device));
+  MOCK_METHOD(gpu::webgpu::ReservedTexture,
+              ReserveTexture,
+              (WGPUDevice device, const WGPUTextureDescriptor* optionalDesc));
 
   // Could have used mock, but we only care about number of associated
   // mailboxes, so use override for now
@@ -118,6 +121,9 @@
 
 class WebGPUSwapBufferProviderTest : public testing::Test {
  protected:
+  static constexpr WGPUTextureFormat kFormat = WGPUTextureFormat_RGBA8Unorm;
+  static constexpr WGPUTextureUsage kUsage = WGPUTextureUsage_RenderAttachment;
+
   void SetUp() override {
     auto webgpu = std::make_unique<MockWebGPUInterface>();
     webgpu_ = webgpu.get();
@@ -132,8 +138,8 @@
         std::move(provider), base::ThreadTaskRunnerHandle::Get());
 
     provider_ = base::MakeRefCounted<WebGPUSwapBufferProviderForTests>(
-        &provider_alive_, &client_, fake_device_, dawn_control_client_,
-        WGPUTextureUsage_RenderAttachment, WGPUTextureFormat_RGBA8Unorm);
+        &provider_alive_, &client_, fake_device_, dawn_control_client_, kUsage,
+        kFormat);
   }
 
   void TearDown() override { Platform::UnsetMainThreadTaskRunnerForTesting(); }
@@ -168,19 +174,19 @@
   viz::ReleaseCallback release_callback3;
 
   // Produce resources.
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation1));
   provider_->GetNewTexture(kSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource1,
                                                      &release_callback1));
 
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation2));
   provider_->GetNewTexture(kSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource2,
                                                      &release_callback2));
 
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation3));
   provider_->GetNewTexture(kSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource3,
@@ -209,7 +215,7 @@
   viz::ReleaseCallback release_callback;
 
   // Produce one resource of size kSize.
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
@@ -218,7 +224,7 @@
   std::move(release_callback).Run(gpu::SyncToken(), false /* lostResource */);
 
   // Produce one resource of size kOtherSize.
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kOtherSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
@@ -227,7 +233,7 @@
   std::move(release_callback).Run(gpu::SyncToken(), false /* lostResource */);
 
   // Produce one resource of size kSize again.
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
@@ -246,7 +252,7 @@
 
   // Produce the first resource, check that WebGPU will wait for the creation of
   // the shared image
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
   EXPECT_EQ(sii_->MostRecentGeneratedToken(),
@@ -284,7 +290,7 @@
 
   // Produce some swap buffers
   viz::ReleaseCallback release_callback_0;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -295,7 +301,7 @@
                                                      &release_callback_0));
 
   viz::ReleaseCallback release_callback_1;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -306,7 +312,7 @@
                                                      &release_callback_1));
 
   viz::ReleaseCallback release_callback_2;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -322,7 +328,7 @@
   std::move(release_callback_2).Run(gpu::SyncToken(), false /* lostResource */);
 
   // Produce two swap buffers
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -332,7 +338,7 @@
   EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
                                                      &release_callback_1));
 
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -357,7 +363,7 @@
   const gfx::Size kSize(10, 10);
 
   viz::ReleaseCallback release_callback_1;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -368,7 +374,7 @@
                                                      &release_callback_1));
 
   viz::ReleaseCallback release_callback_2;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kSize);
 
@@ -386,7 +392,7 @@
   const gfx::Size kOtherSize(20, 20);
 
   viz::ReleaseCallback release_callback_3;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kOtherSize);
 
@@ -397,7 +403,7 @@
                                                      &release_callback_3));
 
   viz::ReleaseCallback release_callback_4;
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(kOtherSize);
 
@@ -417,7 +423,7 @@
   gpu::webgpu::ReservedTexture reservation = {
       reinterpret_cast<WGPUTexture>(&resource), 1, 1, 1, 1};
 
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation));
   provider_->GetNewTexture(gfx::Size(10, 10));
 
@@ -447,7 +453,7 @@
   viz::ReleaseCallback release_callback2;
 
   // Produce and prepare transferable resource
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation1));
   provider_->GetNewTexture(kSize);
   EXPECT_EQ(webgpu_->num_associated_mailboxes, 1);
@@ -458,7 +464,7 @@
 
   // Produce 2nd resource but this time neuters the provider. Mailbox must also
   // be dissociated.
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation2));
   provider_->GetNewTexture(kSize);
   EXPECT_EQ(webgpu_->num_associated_mailboxes, 1);
@@ -478,7 +484,7 @@
   viz::ReleaseCallback release_callback1;
 
   // Produce and prepare transferable resource
-  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_))
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
       .WillOnce(Return(reservation1));
   provider_->GetNewTexture(kSize);
   EXPECT_EQ(webgpu_->num_associated_mailboxes, 1);
@@ -492,4 +498,52 @@
   EXPECT_EQ(webgpu_->num_associated_mailboxes, 0);
 }
 
+TEST_F(WebGPUSwapBufferProviderTest, ReserveTextureDescriptorForReflection) {
+  const gfx::Size kSize(10, 10);
+  const gfx::Size kOtherSize(20, 20);
+
+  viz::TransferableResource resource;
+  gpu::webgpu::ReservedTexture reservation = {
+      reinterpret_cast<WGPUTexture>(&resource), 1, 1, 1, 1};
+  viz::ReleaseCallback release_callback;
+
+  // Produce one resource of size kSize and check that the descriptor passed to
+  // ReserveTexture is correct..
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
+      .WillOnce(Invoke([&](WGPUDevice device,
+                           const WGPUTextureDescriptor* desc) -> auto{
+        EXPECT_NE(desc, nullptr);
+        EXPECT_EQ(desc->size.width, static_cast<uint32_t>(kSize.width()));
+        EXPECT_EQ(desc->size.height, static_cast<uint32_t>(kSize.height()));
+        EXPECT_EQ(desc->size.depthOrArrayLayers, 1u);
+        EXPECT_EQ(desc->format, kFormat);
+        EXPECT_EQ(desc->usage, kUsage);
+        EXPECT_EQ(desc->dimension, WGPUTextureDimension_2D);
+        EXPECT_EQ(desc->mipLevelCount, 1u);
+        EXPECT_EQ(desc->sampleCount, 1u);
+        return reservation;
+      }));
+  provider_->GetNewTexture(kSize);
+  EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
+                                                     &release_callback));
+  EXPECT_EQ(kSize, resource.size);
+  std::move(release_callback).Run(gpu::SyncToken(), false /* lostResource */);
+
+  // Produce one resource of size kOtherSize. The descriptor passed to
+  // ReserveTexture is updated accordingly.
+  EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_, _))
+      .WillOnce(Invoke([&](WGPUDevice device,
+                           const WGPUTextureDescriptor* desc) -> auto{
+        EXPECT_EQ(desc->size.width, static_cast<uint32_t>(kOtherSize.width()));
+        EXPECT_EQ(desc->size.height,
+                  static_cast<uint32_t>(kOtherSize.height()));
+        return reservation;
+      }));
+  provider_->GetNewTexture(kOtherSize);
+  EXPECT_TRUE(provider_->PrepareTransferableResource(nullptr, &resource,
+                                                     &release_callback));
+  EXPECT_EQ(kOtherSize, resource.size);
+  std::move(release_callback).Run(gpu::SyncToken(), false /* lostResource */);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/tools/blinkpy/common/checkout/git.py b/third_party/blink/tools/blinkpy/common/checkout/git.py
index d1b388f2..94e7618a 100644
--- a/third_party/blink/tools/blinkpy/common/checkout/git.py
+++ b/third_party/blink/tools/blinkpy/common/checkout/git.py
@@ -87,7 +87,7 @@
         if not platform or not platform.is_win():
             return 'git'
         try:
-            executive.run_command(['git', 'help'])
+            executive.run_command(['git', 'help'], debug_logging=False)
             return 'git'
         except OSError:
             _log.debug('Using "git.bat" as git executable.')
@@ -106,7 +106,8 @@
                                            cwd=cwd,
                                            input=stdin,
                                            return_exit_code=return_exit_code,
-                                           decode_output=decode_output)
+                                           decode_output=decode_output,
+                                           debug_logging=False)
 
     def absolute_path(self, repository_relative_path):
         """Converts repository-relative paths to absolute paths."""
@@ -117,7 +118,8 @@
         return self._executive.run_command(
             [self._executable_name, 'rev-parse', '--is-inside-work-tree'],
             cwd=path,
-            error_handler=Executive.ignore_error).rstrip() == 'true'
+            error_handler=Executive.ignore_error,
+            debug_logging=False).rstrip() == 'true'
 
     def find_checkout_root(self, path):
         """Returns the absolute path to the root of the repository."""
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 633d6de..64ffe9c 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -641,12 +641,8 @@
         # rebaselined and has an actual result but no baseline. We can't
         # add a Missing expectation (this is not allowed), but no other
         # expectation is correct.
-        # We also want to skip any new manual tests that are not automated;
-        # see crbug.com/708241 for context.
         if 'MISSING' in actual_results:
             return {'Skip'}
-        if '-manual.' in test_name and 'TIMEOUT' in actual_results:
-            return {'Skip'}
         expectations = set()
         failure_types = {'TEXT', 'IMAGE+TEXT', 'IMAGE', 'AUDIO', 'FAIL'}
         other_types = {'TIMEOUT', 'CRASH', 'PASS'}
@@ -950,9 +946,7 @@
         webdriver_list = []
         for lines in line_dict.values():
             for line in lines:
-                if 'Skip' in line and '-manual.' in line:
-                    wont_fix_list.append(line)
-                elif self.finder.webdriver_prefix() in line:
+                if self.finder.webdriver_prefix() in line:
                     webdriver_list.append(line)
                 else:
                     line_list.append(line)
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
index c48deedd..1588c67 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -440,10 +440,6 @@
                 SimpleTestResult('PASS', 'MISSING MISSING', 'bug')), {'Skip'})
         self.assertEqual(
             updater.get_expectations(
-                SimpleTestResult('PASS', 'TIMEOUT', 'bug'),
-                test_name='foo/bar-manual.html'), {'Skip'})
-        self.assertEqual(
-            updater.get_expectations(
                 SimpleTestResult('PASS', 'FAIL', 'bug'),
                 test_name='external/wpt/webdriver/foo/a'), {'Failure'})
 
@@ -584,28 +580,6 @@
                 'virtual/foo/external/wpt/test/zzzz.html': set(['Trusty', 'Mac10.11'])
             })
 
-    def test_create_line_dict_with_manual_tests(self):
-        # In this example, there are two manual tests that should be skipped.
-        updater = WPTExpectationsUpdater(self.mock_host())
-        results = {
-            'virtual/foo/external/wpt/test/aa-manual.html': {
-                tuple([DesktopConfig(port_name='test-linux-trusty')]):
-                SimpleTestResult(
-                    expected='PASS', actual='TIMEOUT', bug='crbug.com/test'),
-                tuple([DesktopConfig(port_name='test-mac-mac10.11')]):
-                SimpleTestResult(
-                    expected='FAIL', actual='TIMEOUT', bug='crbug.com/test'),
-            },
-        }
-        line_dict, _ = updater.create_line_dict(results)
-        self.assertEqual(
-            line_dict, {
-                'virtual/foo/external/wpt/test/aa-manual.html': [
-                    '[ Trusty ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
-                    '[ Mac10.11 ] virtual/foo/external/wpt/test/aa-manual.html [ Skip ]',
-                ],
-            })
-
     def test_create_line_dict_with_asterisks(self):
         # Literal asterisks in test names need to be escaped in expectations.
         updater = WPTExpectationsUpdater(self.mock_host())
@@ -1127,61 +1101,6 @@
         skip_value = host.filesystem.read_text_file(skip_path)
         self.assertMultiLineEqual(skip_value, skip_value_origin)
 
-    def test_write_to_test_expectations_with_manual_tests_and_newline(self):
-        host = self.mock_host()
-        expectations_path = \
-            host.port_factory.get().path_to_generic_test_expectations_file()
-        skip_path = host.port_factory.get().path_to_never_fix_tests_file()
-        raw_exps = '# tags: [ Trusty ]\n# results: [ Skip ]\n'
-        test_expectations = {'external/wpt/fake/file/path-manual.html': {
-            tuple([DesktopConfig(port_name='test-linux-trusty')]):
-            SimpleTestResult(actual='TIMEOUT', expected={}, bug='')}}
-        host.filesystem.write_text_file(expectations_path,
-                                        WPTExpectationsUpdater.MARKER_COMMENT + '\n')
-        host.filesystem.write_text_file(
-            skip_path,
-            raw_exps +
-            '\n[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]\n')
-        updater = WPTExpectationsUpdater(host)
-
-        updater.write_to_test_expectations(test_expectations)
-
-        expectations_value = host.filesystem.read_text_file(expectations_path)
-        skip_value = host.filesystem.read_text_file(skip_path)
-        self.assertMultiLineEqual(expectations_value, WPTExpectationsUpdater.MARKER_COMMENT + '\n')
-        self.assertMultiLineEqual(
-            skip_value,
-            raw_exps + '\n'
-            '[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]\n'
-            '[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]\n')
-
-    def test_write_to_test_expectations_without_newline(self):
-        host = self.mock_host()
-        expectations_path = \
-            host.port_factory.get().path_to_generic_test_expectations_file()
-        skip_path = host.port_factory.get().path_to_never_fix_tests_file()
-        test_expectations = {'external/wpt/fake/file/path-manual.html': {
-            tuple([DesktopConfig(port_name='test-linux-trusty')]):
-            SimpleTestResult(actual='TIMEOUT', expected={}, bug='')}}
-        raw_exps = '# tags: [ Trusty ]\n# results: [ Skip ]\n'
-        host.filesystem.write_text_file(
-            expectations_path,
-            WPTExpectationsUpdater.MARKER_COMMENT + '\n')
-        host.filesystem.write_text_file(
-            skip_path,
-            raw_exps + '\n[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]')
-        updater = WPTExpectationsUpdater(host)
-
-        updater.write_to_test_expectations(test_expectations)
-
-        expectations_value = host.filesystem.read_text_file(expectations_path)
-        skip_value = host.filesystem.read_text_file(skip_path)
-        self.assertMultiLineEqual(expectations_value, WPTExpectationsUpdater.MARKER_COMMENT + '\n')
-        self.assertMultiLineEqual(
-            skip_value,
-            raw_exps + '\n[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]\n'
-            '[ Trusty ] external/wpt/fake/file/path-manual.html [ Skip ]\n')
-
     def test_is_reference_test_given_testharness_test(self):
         updater = WPTExpectationsUpdater(self.mock_host())
         self.assertFalse(updater.is_reference_test('test/path.html'))
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
index 66fcb0cd..f56d62c 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
@@ -233,7 +233,15 @@
         all_tests = set(all_tests_list)
         tests_to_skip = set()
         idlharness_skips = set()
+        tests_always_skipped = set()
         for test in all_tests:
+            # Manual tests and virtual tests skipped by platform config are
+            # always skipped and not affected by the --skip parameter
+            if (self._port.is_manual_test(test) or
+                    self._port.virtual_test_skipped_due_to_platform_config(test)):
+                tests_always_skipped.update({test})
+                continue
+
             # We always skip idlharness tests for MSAN/ASAN, even when running
             # with --no-expectations (https://crbug.com/856601). Note we will
             # run the test anyway if it is explicitly specified on the command
@@ -275,6 +283,8 @@
             # make sure we're explicitly running any tests passed on the command line; equivalent to 'default'.
             tests_to_skip -= set(paths)
 
+        tests_to_skip.update(tests_always_skipped)
+
         return tests_to_skip
 
     def split_into_chunks(self, test_names):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index 4e7ce118..5d143bf 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -1276,14 +1276,16 @@
     def skips_test(self, test):
         """Checks whether the given test is skipped for this port.
 
-        Returns True if the test is skipped because the port runs smoke tests
-        only or because the test is marked as Skip in NeverFixTest or because
-        it is a virtual test not intended to run on this platform (otherwise
-        the test is only marked as Skip indicating a temporary skip).
+        Returns True if:
+          - the test is a manual test
+          - the port runs smoke tests only and the test is not in the list
+          - the test is marked as Skip in NeverFixTest
+          - the test is a virtual test not intended to run on this platform.
         """
-        return self.skipped_due_to_smoke_tests(
-            test) or self.skipped_in_never_fix_tests(
-            test) or self.virtual_test_skipped_due_to_platform_config(test)
+        return (self.is_manual_test(test)
+                or self.skipped_due_to_smoke_tests(test)
+                or self.skipped_in_never_fix_tests(test)
+                or self.virtual_test_skipped_due_to_platform_config(test))
 
     @memoized
     def _tests_from_file(self, filename):
@@ -1296,6 +1298,10 @@
             tests.add(line)
         return tests
 
+    def is_manual_test(self, test):
+        """Skip the test if it is a WPT manual test"""
+        return self.is_wpt_test(test) and '-manual.' in test
+
     def skipped_due_to_smoke_tests(self, test):
         """Checks if the test is skipped based on the set of Smoke tests.
 
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/linux.py b/third_party/blink/tools/blinkpy/web_tests/port/linux.py
index 114aa5f..abae8930 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/linux.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/linux.py
@@ -75,7 +75,8 @@
 
         # See //testing/xvfb.py for an explanation of parsing -help output.
         try:
-            output = self.host.executive.run_command(['Xvfb', '-help'])
+            output = self.host.executive.run_command(['Xvfb', '-help'],
+                                                     debug_logging=False)
             self._xvfb_supports_maxclients = (type(output) is str
                                               and '-maxclients' in output)
         except Exception:
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 5b7af635..ae762a5 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -156,10 +156,6 @@
 fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html [ Skip ]
 virtual/threaded-prefer-compositing/fast/scrolling/scrollbars/mouse-scrolling-on-div-scrollbar-thumb-scaled.html [ Pass ]
 
-# Only run fake-Android tests on Linux
-[ Mac ] virtual/android/* [ Skip ]
-[ Win ] virtual/android/* [ Skip ]
-
 # Android doesn't support plugins
 virtual/android/fullscreen/rendering/backdrop-object.html [ Skip ]
 
@@ -1720,9 +1716,6 @@
 virtual/trust-tokens/external/wpt/trust-tokens/end-to-end/* [ Pass ]
 virtual/trust-tokens/wpt_internal/trust-tokens/* [ Pass ]
 
-# Mac does not ever have fractional device scale factor.
-[ Mac ] virtual/scalefactor150/* [ Skip ]
-
 # Run these tests with under virtual/scalefactor... only.
 crbug.com/567837 fast/hidpi/static/* [ Skip ]
 [ Linux ] virtual/scalefactor150/fast/hidpi/static/* [ Pass ]
@@ -1964,14 +1957,6 @@
 crbug.com/626703 [ Mac10.15 ] external/wpt/appmanifest/start_url-member/start_url-member-pass-manual.html [ Skip ]
 crbug.com/626703 [ Mac11 ] virtual/fsa-incognito/external/wpt/file-system-access/local_FileSystemBaseHandle-postMessage-windows-manual.https.html [ Skip ]
 
-# Virtual test suite shared_array_buffer_on_desktop is platform agnostic
-[ Mac ] virtual/shared_array_buffer_on_desktop/* [ Skip ]
-[ Win ] virtual/shared_array_buffer_on_desktop/* [ Skip ]
-
-# Virtual test suite plz-dedicated-worker is platform agnostic
-[ Mac ] virtual/plz-dedicated-worker/* [ Skip ]
-[ Win ] virtual/plz-dedicated-worker/* [ Skip ]
-
 # The following tests never pass in the default Blink test runner due to forced
 # frame updates, but still pass in the full browser. They are only run in the
 # no-forced-frame-updates virtual test suite.
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 9eb3ed433..2e02ce8 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -173,7 +173,7 @@
   },
   {
     "prefix": "android",
-    "platforms": ["Linux", "Mac", "Win"],
+    "platforms": ["Linux"],
     "bases": ["fullscreen"],
     "args": ["--enable-features=OverlayScrollbar",
              "--enable-threaded-compositing",
@@ -192,7 +192,7 @@
   },
   {
     "prefix": "shared_array_buffer_on_desktop",
-    "platforms": ["Linux", "Mac", "Win"],
+    "platforms": ["Linux"],
     "bases": ["external/wpt/html/browsers/origin/origin-keyed-agent-clusters",
               "external/wpt/wasm/jsapi/memory",
               "fast/workers/worker-atomics-wait.html",
@@ -258,7 +258,7 @@
   },
   {
     "prefix": "scalefactor150",
-    "platforms": ["Linux", "Mac", "Win"],
+    "platforms": ["Linux", "Win"],
     "bases": ["fast/events/synthetic-events",
               "fast/hidpi/static"],
     "args": ["--force-device-scale-factor=1.5"]
@@ -416,7 +416,7 @@
   },
   {
     "prefix": "plz-dedicated-worker",
-    "platforms": ["Linux", "Mac", "Win"],
+    "platforms": ["Linux"],
     "bases": ["external/wpt/content-security-policy/inside-worker",
               "external/wpt/content-security-policy/worker-src",
               "external/wpt/content-security-policy/gen",
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-iframe-load-and-delete.js b/third_party/blink/web_tests/http/tests/devtools/network/network-iframe-load-and-delete.js
index e0bea0ec..9bb8797e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/network/network-iframe-load-and-delete.js
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-iframe-load-and-delete.js
@@ -43,6 +43,7 @@
       }
   `);
 
+  ProtocolClient.test.suppressRequestErrors = true;
   NetworkTestRunner.recordNetwork();
   ConsoleTestRunner.addConsoleSniffer(step2);
   TestRunner.evaluateInPage('loadIframe()');
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/document-exit-fullscreen-timing-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/document-exit-fullscreen-timing-manual-expected.txt
deleted file mode 100644
index c4f1bd6e4..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/document-exit-fullscreen-timing-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Timing of fullscreenchange and resize events assert_array_equals: event order lengths differ, expected array ["resize", "fullscreenchange"] length 2, got ["fullscreenchange"] length 1
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-ready-check-not-allowed-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-ready-check-not-allowed-manual-expected.txt
deleted file mode 100644
index fec32b8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-ready-check-not-allowed-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Element ready check with enabled flag not set assert_false: fullscreen enabled flag expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt
deleted file mode 100644
index e754f2e..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/api/element-request-fullscreen-timing-manual-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Timing of fullscreenchange and resize events assert_array_equals: event order lengths differ, expected array ["resize", "fullscreenchange"] length 2, got ["fullscreenchange"] length 1
-PASS Timing of fullscreenerror event
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/rendering/fullscreen-pseudo-class-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/rendering/fullscreen-pseudo-class-manual-expected.txt
deleted file mode 100644
index ff07788..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/fullscreen/rendering/fullscreen-pseudo-class-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL :fullscreen pseudo-class assert_true: outer:fullscreen in nested fullscreen expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_html_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_html_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_html_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_svg_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_svg_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-document_on_svg_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_html_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_html_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_html_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_svg_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_svg_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-object_on_svg_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_html_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_html_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_html_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_svg_element-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_svg_element-manual-expected.txt
deleted file mode 100644
index 2d33166..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/graphics-aam/graphics-symbol_on_svg_element-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught ReferenceError: ATTAcomm is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual-expected.txt
deleted file mode 100644
index de8aaf9..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Traversing the history, prompt in before unload, navigation denied assert_array_equals: Pages opened during history navigation lengths differ, expected array [2] length 1, got [2, 1] length 2
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual-expected.txt
deleted file mode 100644
index 41569f6..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Traversing the history, unload event is fired on doucment assert_array_equals: Pages opened during history navigation lengths differ, expected array [2] length 1, got [2, 1] length 2
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/get-navigatorlanguage-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/get-navigatorlanguage-manual-expected.txt
deleted file mode 100644
index 0fe4d380..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/get-navigatorlanguage-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL NavigatorLanguage: navigator.language returns the user's preferred language assert_equals: expected "en" but got "en-US"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-false-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-false-manual-expected.txt
deleted file mode 100644
index a959723..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-false-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL navigator.cookieEnabled is false when cookies are disabled assert_false: expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/mediacapture-depth/dictionary-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/mediacapture-depth/dictionary-manual.https-expected.txt
deleted file mode 100644
index f99d27a7..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/mediacapture-depth/dictionary-manual.https-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-FAIL MediaTrackSupportedConstraints dictionary include attributes are correct assert_equals: Expect dictionary.videoKind to be boolean expected "boolean" but got "undefined"
-FAIL MediaTrackCapabilities dictionary of depth include attributes are correct assert_equals: Expect dictionary.videoKind to be string expected "string" but got "undefined"
-FAIL MediaTrackConstraintSet dictionary of depth include attributes are correct promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading '0')"
-FAIL MediaTrackSettings dictionary of depth include attributes are correct assert_equals: Expect dictionary.videoKind to be string expected "string" but got "undefined"
-FAIL MediaTrackCapabilities dictionary of color include attributes are correct assert_equals: Expect dictionary.videoKind to be string expected "string" but got "undefined"
-FAIL MediaTrackConstraintSet dictionary of color include attributes are correct promise_test: Unhandled rejection with value: object "TypeError: Cannot read properties of undefined (reading '0')"
-FAIL MediaTrackSettings dictionary of color include attributes are correct assert_equals: Expect dictionary.videoKind to be string expected "string" but got "undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/notifications/shownotification-resolve-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/notifications/shownotification-resolve-manual.https-expected.txt
deleted file mode 100644
index 701230f..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/notifications/shownotification-resolve-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL showNotification resolves after icon fetch promise_test: Unhandled rejection with value: object "Error: You must allow notifications for this origin before running this test."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/orientation-event/orientation/horizontal-surface-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/orientation-event/orientation/horizontal-surface-manual.https-expected.txt
deleted file mode 100644
index 55c8f99..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/orientation-event/orientation/horizontal-surface-manual.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL X angle assert_approx_equals: expected a number but got a "undefined"
-FAIL Y angle assert_approx_equals: expected a number but got a "undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
deleted file mode 100644
index 01611e8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-payment-method-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-address-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-address-manual.https-expected.txt
deleted file mode 100644
index 01611e8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-address-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-option-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-option-manual.https-expected.txt
deleted file mode 100644
index 01611e8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/change-shipping-option-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt
deleted file mode 100644
index 01611e8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/payment-request-event-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt
deleted file mode 100644
index 01611e8..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/payment-handler/supports-shipping-contact-delegation-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: Not allowed to install this payment handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https-expected.txt
deleted file mode 100644
index fc4c6ea..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL FetchEvent#request.isReloadNavigation is true for manual reload. assert_equals: expected "method = GET, isReloadNavigation = false" but got "method = GET, isReloadNavigation = undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-within-sw-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-within-sw-manual.https-expected.txt
deleted file mode 100644
index e774a74..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/service-workers/service-worker/fetch-event-within-sw-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Notification requests intercepted both from window and SW promise_test: Unhandled rejection with value: object "Error: You must allow notifications for this origin before running this test."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/storage/persist-permission-manual.https-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/storage/persist-permission-manual.https-expected.txt
deleted file mode 100644
index 3a7b644..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/storage/persist-permission-manual.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Expect permission state is granted after calling persist() assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/xhr/send-authentication-prompt-manual-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/xhr/send-authentication-prompt-manual-expected.txt
deleted file mode 100644
index 433cb5b..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/xhr/send-authentication-prompt-manual-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL XMLHttpRequest: send() - "Basic" authentication gets 401 response assert_equals: expected "usr\nsecret" but got "User name/password wrong or not given: usr\nwrongpassword"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
deleted file mode 100644
index d04620da..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
deleted file mode 100644
index 8ce64b4..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
deleted file mode 100644
index fb91623..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
deleted file mode 100644
index 0e16bbf..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
deleted file mode 100644
index 6d97a135..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index 3675622..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
deleted file mode 100644
index 2a977c25..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index bd836a4b..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
deleted file mode 100644
index 436a0c89..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
deleted file mode 100644
index 4c5d82a5..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
deleted file mode 100644
index 40f7d22e..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
deleted file mode 100644
index 4c5d82a5..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index 80e9d2e..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/name-member/name-member-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/name-member/name-member-manual-expected.png
deleted file mode 100644
index 9d4eac7..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/name-member/name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
deleted file mode 100644
index 81774db1..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
deleted file mode 100644
index 213b1f1..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
deleted file mode 100644
index 9c3fdfd0..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index cf692bfa..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
deleted file mode 100644
index 987bbab..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index 28e9d99..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
deleted file mode 100644
index 29bd0f03..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
deleted file mode 100644
index 59cb730..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
deleted file mode 100644
index d8d66ca..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
deleted file mode 100644
index 4fa2230..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
deleted file mode 100644
index 1092eb2..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-cascade/important-transition-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-cascade/important-transition-manual-expected.png
deleted file mode 100644
index d065f26..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-cascade/important-transition-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
deleted file mode 100644
index b2a7c08..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
deleted file mode 100644
index 4d809303..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
deleted file mode 100644
index 96ef612..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
deleted file mode 100644
index 64a38e07..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
deleted file mode 100644
index 60e7c4b..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
deleted file mode 100644
index 188ecc6..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
deleted file mode 100644
index c44322c..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
deleted file mode 100644
index bbe9430..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
deleted file mode 100644
index 9cb73a6..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
deleted file mode 100644
index 51b601a..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
deleted file mode 100644
index dc3fbfd..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/entries-api/idlharness-manual.window-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/entries-api/idlharness-manual.window-expected.png
deleted file mode 100644
index 257dfc4..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/entries-api/idlharness-manual.window-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
deleted file mode 100644
index d087fd0..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
deleted file mode 100644
index 0c6639d..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
deleted file mode 100644
index ebf3a3b..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
deleted file mode 100644
index c900a63..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
deleted file mode 100644
index c900a63..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
deleted file mode 100644
index c900a63..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
deleted file mode 100644
index 6d36693..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
deleted file mode 100644
index 32713c9f..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
deleted file mode 100644
index c900a63..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
deleted file mode 100644
index 4e151ed..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
deleted file mode 100644
index 3cb1ad24..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
deleted file mode 100644
index 73bb420..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
deleted file mode 100644
index 337d9be..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/document-not-attached-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
deleted file mode 100644
index 743b65a..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index 80e9d2e..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
deleted file mode 100644
index 74761258..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
deleted file mode 100644
index e778ad8e..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
deleted file mode 100644
index ed6fbc13..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-none-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
deleted file mode 100644
index 49d8af4..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
deleted file mode 100644
index 465e0ca..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
deleted file mode 100644
index b62fe28..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
deleted file mode 100644
index 3b24c01..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
deleted file mode 100644
index 65b2e569..0000000
--- a/third_party/blink/web_tests/platform/mac-mac11-arm64/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
deleted file mode 100644
index cb4d7d1..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
deleted file mode 100644
index 199a6b49..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
deleted file mode 100644
index cc9958b..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
deleted file mode 100644
index 29d2612..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
deleted file mode 100644
index 464a86b..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index 5b46a6791..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
deleted file mode 100644
index dd841151..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index dfd83ec..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
deleted file mode 100644
index 3b03bb45..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
deleted file mode 100644
index fe7769d..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
deleted file mode 100644
index bbada96..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
deleted file mode 100644
index fe7769d..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index cc0737c..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/name-member/name-member-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/name-member/name-member-manual-expected.png
deleted file mode 100644
index 0332224..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/name-member/name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
deleted file mode 100644
index 2fca9e6..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
deleted file mode 100644
index a2b17e4f..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
deleted file mode 100644
index 2b803bc..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index 510c2c0..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
deleted file mode 100644
index 296e73f..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index 639167e..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
deleted file mode 100644
index 3962e77..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
deleted file mode 100644
index ad81053..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
deleted file mode 100644
index 3b3f79cd..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
deleted file mode 100644
index a202de3..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
deleted file mode 100644
index 2e593dd..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-cascade/important-transition-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-cascade/important-transition-manual-expected.png
deleted file mode 100644
index a62ef39..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-cascade/important-transition-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
deleted file mode 100644
index 16c8cb27..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
deleted file mode 100644
index 7ba1cbd..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
deleted file mode 100644
index aed3c8d..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
deleted file mode 100644
index 69872b8..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
deleted file mode 100644
index 338ed8d..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
deleted file mode 100644
index a9e6f1f..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
deleted file mode 100644
index f1b777d..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
deleted file mode 100644
index 804abbc..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
deleted file mode 100644
index e0b7a4c..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
deleted file mode 100644
index 8ac6d59..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
deleted file mode 100644
index 7059013..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/entries-api/idlharness-manual.window-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/entries-api/idlharness-manual.window-expected.png
deleted file mode 100644
index edf0ec9..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/entries-api/idlharness-manual.window-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
deleted file mode 100644
index 4d276b2a..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
deleted file mode 100644
index 08780ea..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
deleted file mode 100644
index 04651bd..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
deleted file mode 100644
index 4174df15..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
deleted file mode 100644
index 4174df15..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
deleted file mode 100644
index 4174df15..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
deleted file mode 100644
index b319c3a..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
deleted file mode 100644
index b14fbd9..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
deleted file mode 100644
index 4174df15..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
deleted file mode 100644
index fea425e..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
deleted file mode 100644
index 15ab8f97..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
deleted file mode 100644
index 52e29fa..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
deleted file mode 100644
index b8369d44..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/document-not-attached-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
deleted file mode 100644
index 916ab7a1..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index cc0737c..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
deleted file mode 100644
index bc81194..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
deleted file mode 100644
index ae971e1b..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
deleted file mode 100644
index acfb6a2..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-none-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
deleted file mode 100644
index b4a8e24..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
deleted file mode 100644
index 9ebfe594f..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
deleted file mode 100644
index a769dc3..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
deleted file mode 100644
index 06488ea..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/speech-api/SpeechSynthesisUtterance-volume-manual-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/speech-api/SpeechSynthesisUtterance-volume-manual-expected.png
deleted file mode 100644
index adc2f8b0..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/speech-api/SpeechSynthesisUtterance-volume-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
deleted file mode 100644
index f1d30c3b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-browser-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
deleted file mode 100644
index 9afe3f42..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-fullscreen-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
deleted file mode 100644
index e78c601a..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
deleted file mode 100644
index 3857bce..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-minimal-ui-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
deleted file mode 100644
index 676e418e..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/display-member/display-member-media-feature-standalone-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index 5915b60..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
deleted file mode 100644
index 4e86616..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index a4c1be9a..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
deleted file mode 100644
index 0350f20..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
deleted file mode 100644
index 04f41b25..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-last-matching-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
deleted file mode 100644
index c069720..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
deleted file mode 100644
index 04f41b25..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/icons-member/icons-member-next-appropriate-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index ad9e95c..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/name-member/name-member-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/name-member/name-member-manual-expected.png
deleted file mode 100644
index 673b85e..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/name-member/name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
deleted file mode 100644
index aacaa039..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-landscape-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
deleted file mode 100644
index 12e4d42f..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/orientation-member/orientation-member-portrait-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
deleted file mode 100644
index d9418a6..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/short_name-member/short_name-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
deleted file mode 100644
index 087f21e..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
deleted file mode 100644
index eb2f316..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
deleted file mode 100644
index bf969573..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
deleted file mode 100644
index dac4345..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
deleted file mode 100644
index bebba1e5..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-fail-manual.sub-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
deleted file mode 100644
index f59a2879..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/start_url-member/start_url-member-pass-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
deleted file mode 100644
index 687a8318..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/theme_color-member/theme_color-member-red-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
deleted file mode 100644
index 310e7f3..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/appmanifest/unrecognized-member/unrecognized-member-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-cascade/important-transition-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-cascade/important-transition-manual-expected.png
deleted file mode 100644
index ceee3ea6..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-cascade/important-transition-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
deleted file mode 100644
index 606d66a3..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
deleted file mode 100644
index 265e584d..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
deleted file mode 100644
index 1cb2a9dd..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
deleted file mode 100644
index 3719ea1..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/active-selection-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
deleted file mode 100644
index d2279fe2..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-pseudo/selection-text-shadow-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
deleted file mode 100644
index 99cb29f..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-decoration-thickness-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
deleted file mode 100644
index 7f265cf..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text-decor/text-underline-offset-nesting-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
deleted file mode 100644
index d333ad03..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-text/word-boundary/word-boundary-015-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
deleted file mode 100644
index 0c730c8..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-transforms/css-transform-scale-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
deleted file mode 100644
index 4f174f2..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/alt-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
deleted file mode 100644
index 290c91c..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-writing-modes/tooltip-display-vertical-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/entries-api/idlharness-manual.window-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/entries-api/idlharness-manual.window-expected.png
deleted file mode 100644
index 12d5238..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/entries-api/idlharness-manual.window-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
deleted file mode 100644
index 7c45faac..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-sticky-activation-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
deleted file mode 100644
index f50b821fa..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
deleted file mode 100644
index a46793b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/events/events-non-draggable-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
deleted file mode 100644
index fa2fc7b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-001-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
deleted file mode 100644
index fa2fc7b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-002-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
deleted file mode 100644
index fa2fc7b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-003-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
deleted file mode 100644
index 98814b5..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-004-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
deleted file mode 100644
index 8c4431c..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-005-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
deleted file mode 100644
index fa2fc7b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/close-drag-006-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
deleted file mode 100644
index 81cae48c..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-keypress-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
deleted file mode 100644
index c7acb94..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-link-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
deleted file mode 100644
index 9cbbd8dc..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/drag-to-title-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
deleted file mode 100644
index 8c5cae8a..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/editing/dnd/platform/modifiers/releasemodifiersdrag-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/document-not-attached-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
deleted file mode 100644
index ad09865..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/document-not-attached-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
deleted file mode 100644
index ad9e95c..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/link-relationship/link-tree-order-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
deleted file mode 100644
index 84eade8..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
deleted file mode 100644
index 8d86f32..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-application-manifest+json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
deleted file mode 100644
index 9a246b0a..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-invalid-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-none-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
deleted file mode 100644
index e205d4d..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-none-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
deleted file mode 100644
index 82f11e3..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/mime-type-text-json-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
deleted file mode 100644
index 873f5bd..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/no-manifest-from-iframe-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
deleted file mode 100644
index 06221d2..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/links/manifest/wrong-mime-type-text-plain-manual-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index f047d65..d5d8a99 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-12-1-30-g4b6f92e6b
-Revision: 4b6f92e6b3d0d99a839448bc897673b849981997
+Version: VER-2-12-1-32-g2848378be
+Revision: 2848378be56ea26376e3aff68b1b4b8aa8f8611b
 CPEPrefix: cpe:/a:freetype:freetype:2.11.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/r8/playground/playground.pgcfg b/third_party/r8/playground/playground.pgcfg
index b1575bf..f828d13 100644
--- a/third_party/r8/playground/playground.pgcfg
+++ b/third_party/r8/playground/playground.pgcfg
@@ -9,3 +9,8 @@
 -keep,allowoptimization class Playground {
   *** main(...);
 }
+
+# Don't allow optimization of native methods or else R8 might remove parameters.
+-keepclassmembernames,allowshrinking class ** {
+  native <methods>;
+}
diff --git a/third_party/updater/chromium_mac_amd64/3pp/fetch.py b/third_party/updater/chromium_mac_amd64/3pp/fetch.py
index 3e3a39516..e903a17b 100755
--- a/third_party/updater/chromium_mac_amd64/3pp/fetch.py
+++ b/third_party/updater/chromium_mac_amd64/3pp/fetch.py
@@ -73,7 +73,7 @@
     latest = int(
         urllib.request.urlopen(
             'https://storage.googleapis.com/storage/v1/b/'
-            'chromium-browser-snapshots/o/Mac%2FLAST_CHANGE?alt=media').read())
+            'chromium-browser-snapshots/o/%s%%2FLAST_CHANGE?alt=media' % platform).read())
     min_datum = latest - 3000
     min_datum -= min_datum % 10000
     return max(MIN_VERSION, find(platform, min_datum, latest))
diff --git a/third_party/updater/chromium_mac_arm64/3pp/fetch.py b/third_party/updater/chromium_mac_arm64/3pp/fetch.py
index 2abc76e..44bf6a6 100755
--- a/third_party/updater/chromium_mac_arm64/3pp/fetch.py
+++ b/third_party/updater/chromium_mac_arm64/3pp/fetch.py
@@ -73,7 +73,7 @@
     latest = int(
         urllib.request.urlopen(
             'https://storage.googleapis.com/storage/v1/b/'
-            'chromium-browser-snapshots/o/Mac%2FLAST_CHANGE?alt=media').read())
+            'chromium-browser-snapshots/o/%s%%2FLAST_CHANGE?alt=media' % platform).read())
     min_datum = latest - 3000
     min_datum -= min_datum % 10000
     return max(MIN_VERSION, find(platform, min_datum, latest))
diff --git a/third_party/updater/chromium_win_x86/3pp/fetch.py b/third_party/updater/chromium_win_x86/3pp/fetch.py
index 9ae41d44..e1023f9 100755
--- a/third_party/updater/chromium_win_x86/3pp/fetch.py
+++ b/third_party/updater/chromium_win_x86/3pp/fetch.py
@@ -73,7 +73,7 @@
     latest = int(
         urllib.request.urlopen(
             'https://storage.googleapis.com/storage/v1/b/'
-            'chromium-browser-snapshots/o/Mac%2FLAST_CHANGE?alt=media').read())
+            'chromium-browser-snapshots/o/%s%%2FLAST_CHANGE?alt=media' % platform).read())
     min_datum = latest - 3000
     min_datum -= min_datum % 10000
     return max(MIN_VERSION, find(platform, min_datum, latest))
diff --git a/third_party/updater/chromium_win_x86_64/3pp/fetch.py b/third_party/updater/chromium_win_x86_64/3pp/fetch.py
index 7750ade..42bad8cb 100755
--- a/third_party/updater/chromium_win_x86_64/3pp/fetch.py
+++ b/third_party/updater/chromium_win_x86_64/3pp/fetch.py
@@ -73,7 +73,7 @@
     latest = int(
         urllib.request.urlopen(
             'https://storage.googleapis.com/storage/v1/b/'
-            'chromium-browser-snapshots/o/Mac%2FLAST_CHANGE?alt=media').read())
+            'chromium-browser-snapshots/o/%s%%2FLAST_CHANGE?alt=media' % platform).read())
     min_datum = latest - 3000
     min_datum -= min_datum % 10000
     return max(MIN_VERSION, find(platform, min_datum, latest))
diff --git a/tools/android/kerberos/README.md b/tools/android/kerberos/README.md
index 286b49e..015e463 100644
--- a/tools/android/kerberos/README.md
+++ b/tools/android/kerberos/README.md
@@ -26,7 +26,7 @@
 
     ```sh
     $CHROMIUM_SRC/build/android/adb_chrome_public_command_line \
-    '--auth-server-whitelist="*" \
+    '--auth-server-allowlist="*" \
     --auth-spnego-account-type="org.chromium.tools.SpnegoAuthenticator"'
     ```
 
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index feff3f7..46fc466 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -1221,10 +1221,6 @@
     RunCommand(['ninja', '-C', LLVM_BUILD_DIR, 'cr-check-all'], msvc_arch='x64')
 
   if not args.build_mac_arm and args.run_tests:
-    test_targets = [ 'check-all' ]
-    if sys.platform == 'darwin':
-      # TODO(thakis): Run check-all on Darwin too, https://crbug.com/959361
-      test_targets = [ 'check-llvm', 'check-clang', 'check-lld' ]
     env = None
     if sys.platform.startswith('linux'):
       env = os.environ.copy()
@@ -1232,7 +1228,7 @@
       # interception, so its tests can't pass.
       env['LIT_FILTER_OUT'] = ('^SanitizerCommon-(a|l|m|ub|t)san-x86_64-Linux' +
                                ' :: Linux/crypt_r.cpp$')
-    RunCommand(['ninja', '-C', LLVM_BUILD_DIR] + test_targets,
+    RunCommand(['ninja', '-C', LLVM_BUILD_DIR, 'check-all'],
                env=env,
                msvc_arch='x64')
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 56e87e5e..95ad7ee 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -331,6 +331,10 @@
         'goma': 'gpu_tests_release_bot_minimal_symbols',
         'reclient': 'gpu_tests_release_bot_minimal_symbols_reclient',
       },
+      'Comparison ios (reclient)': {
+        'goma': 'ios_simulator_code_coverage_partial_instrumentation_xctest',
+        'reclient': 'ios_simulator_code_coverage_partial_instrumentation_xctest_reclient',
+      },
       'Libfuzzer Upload Chrome OS ASan': 'libfuzzer_chromeos_asan_release_bot',
       'Libfuzzer Upload Linux ASan': 'libfuzzer_asan_release_bot',
       'Libfuzzer Upload Linux ASan (reclient)': 'libfuzzer_asan_release_bot_reclient',
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 80f02365..aafcbf4 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -149,6 +149,37 @@
       }
     }
   },
+  "Comparison ios (reclient)": {
+    "goma": {
+      "gn_args": {
+        "coverage_instrumentation_input_file": "//.code-coverage/files_to_instrument.txt",
+        "enable_run_ios_unittests_with_xctest": true,
+        "ios_set_attributes_for_xcode_project_generation": false,
+        "is_component_build": false,
+        "is_debug": true,
+        "symbol_level": 1,
+        "target_cpu": "x64",
+        "target_environment": "simulator",
+        "target_os": "ios",
+        "use_clang_coverage": true,
+        "use_goma": true
+      }
+    },
+    "reclient": {
+      "gn_args": {
+        "dcheck_always_on": false,
+        "enable_run_ios_unittests_with_xctest": true,
+        "ios_set_attributes_for_xcode_project_generation": false,
+        "is_component_build": false,
+        "is_debug": false,
+        "target_cpu": "x64",
+        "target_environment": "simulator",
+        "target_os": "ios",
+        "use_clang_coverage": true,
+        "use_remoteexec": true
+      }
+    }
+  },
   "Libfuzzer Upload Chrome OS ASan": {
     "gn_args": {
       "archive_seed_corpus": false,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 219cfabf..4381d81 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -7566,6 +7566,7 @@
 </action>
 
 <action name="DownloadNotification.Button_AlwaysOpenType">
+  <obsolete>It was discovered in June 2022 that this was dead code.</obsolete>
   <owner>yoshiki@chromium.org</owner>
   <description>
     User pushes &quot;Always open type&quot; button on download notification.
@@ -7582,6 +7583,7 @@
 </action>
 
 <action name="DownloadNotification.Button_BypassDeepScanning">
+  <obsolete>It was discovered in June 2022 that this was dead code.</obsolete>
   <owner>drubery@chromium.org</owner>
   <description>
     User pushes &quot;Open now&quot; on the prompt for download deep scanning
@@ -7624,6 +7626,7 @@
 </action>
 
 <action name="DownloadNotification.Button_LearnInterrupted">
+  <obsolete>It was discovered in June 2022 that this was dead code.</obsolete>
   <owner>yoshiki@chromium.org</owner>
   <description>
     User pushes &quot;Learn More about Interrupted&quot; button on download
@@ -7662,6 +7665,7 @@
 </action>
 
 <action name="DownloadNotification.Button_PlatformOpen">
+  <obsolete>It was discovered in June 2022 that this was dead code.</obsolete>
   <owner>yoshiki@chromium.org</owner>
   <description>
     User pushes &quot;Open&quot; button on download notification.
@@ -7676,6 +7680,7 @@
 </action>
 
 <action name="DownloadNotification.Button_Review">
+  <obsolete>It was discovered in June 2022 that this was dead code.</obsolete>
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <description>
diff --git a/tools/metrics/histograms/README.md b/tools/metrics/histograms/README.md
index f97a541a..b650fed 100644
--- a/tools/metrics/histograms/README.md
+++ b/tools/metrics/histograms/README.md
@@ -722,6 +722,11 @@
 [histograms.xml](https://source.chromium.org/search?q=file:histograms.xml%20%3Cvariants)
 for examples.
 
+*** promo
+Warning: The `name` attribute of the `<variants>` tag is globally scoped, so
+use detailed names to avoid collisions.
+***
+
 By default, a `<variant>` inherits the owners declared for the patterned
 histogram. Each variant can optionally override the inherited list with custom
 owners:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 78f911d..662be0a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -14822,8 +14822,8 @@
   <int value="10" label="Ignored Configuration Changed"/>
   <int value="11" label="Ignored SHA-1 Signature Present"/>
   <int value="12" label="Ignored Windows Rev Checking Enabled"/>
-  <int value="13" label="Ignored Authority Invalid"/>
-  <int value="14" label="Ignored Known Root"/>
+  <int value="13" label="Ignored Both Authority Invalid"/>
+  <int value="14" label="Ignored Both Known Root, Different Chains"/>
   <int value="15" label="Ignored Both Errors Platform Symantec"/>
   <int value="16" label="Ignored Lets Encrypt Expired Root"/>
 </enum>
@@ -27977,14 +27977,15 @@
   <int value="25" label="Learn more mixed content clicked"/>
   <int value="26" label="Copy to clipboard enabled"/>
   <int value="27" label="Copy to clipboard clicked"/>
-  <int value="28" label="Annotate enabled"/>
-  <int value="29" label="Annotate clicked"/>
+  <int value="28" label="Annotate enabled (obsolete)"/>
+  <int value="29" label="Annotate clicked (obsolete)"/>
   <int value="30" label="Deep scan enabled"/>
   <int value="31" label="Deep scan clicked"/>
   <int value="32" label="Bypass deep scanning enabled"/>
   <int value="33" label="Bypass deep scanning clicked"/>
-  <int value="34" label="Review enabled"/>
-  <int value="35" label="Review clicked"/>
+  <int value="34" label="Review enabled (obsolete)"/>
+  <int value="35" label="Review clicked (obsolete)"/>
+  <int value="36" label="Should never be logged"/>
 </enum>
 
 <enum name="DownloadSource">
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index e468e4d..87d90f0d 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -206,31 +206,38 @@
   <variant name=".Reshows" summary="Bubble was reopened after being closed"/>
 </variants>
 
-<variants name="AutofillMeasurementTime">
-  <variant name="Fillable.AtFillTimeAfterSecurityPolicy"
-      summary="Recorded at filling time after applying restrictions due to
-               the cross-frame security policy under the assumption of a
-               complete profile (i.e., the profile holds data for all present
-               fields)."/>
-  <variant name="Fillable.AtFillTimeBeforeSecurityPolicy"
-      summary="Recorded at filling time before applying restrictions due to
-               the cross-frame security policy under the assumption of a
-               complete profile (i.e., the profile holds data for all present
-               fields)."/>
-  <variant name="Fills.AtFillTimeAfterSecurityPolicy"
-      summary="Recorded at filling time after applying restrictions due to
-               the cross-frame security policy."/>
-  <variant name="Fills.AtFillTimeBeforeSecurityPolicy"
-      summary="Recorded at filling time before applying restrictions due to
-               the cross-frame security policy."/>
-  <variant name="Fills.AtSubmissionTime"
+<variants name="AutofillSaveCreditCardPromptDestination">
+  <variant name=".Local" summary="to local storage"/>
+  <variant name=".Upload" summary="to upload"/>
+</variants>
+
+<variants name="AutofillSeamlessnessFillability">
+  <variant name="Fillable"
+      summary="Recorded under the assumption of a complete profile (i.e., the
+               profile holds data for all present fields)."/>
+  <variant name="Fills"
+      summary="Recorded taking only the actually filled fields into account."/>
+</variants>
+
+<variants name="AutofillSeamlessnessMeasurementTime">
+  <variant name=".AtFillTimeAfterSecurityPolicy"
+      summary="Recorded after applying restrictions due to the cross-frame
+               security policy."/>
+  <variant name=".AtFillTimeBeforeSecurityPolicy"
+      summary="Recorded before applying restrictions due to the cross-frame
+               security policy."/>
+  <variant name=".AtSubmissionTime"
       summary="Recorded at submission time. May be missed due to submission
                detection problems."/>
 </variants>
 
-<variants name="AutofillSaveCreditCardPromptDestination">
-  <variant name=".Local" summary="to local storage"/>
-  <variant name=".Upload" summary="to upload"/>
+<variants name="AutofillSeamlessnessVisibility">
+  <variant name=""
+      summary="Recorded for all detected fields, including those that may be
+               invisible to the user."/>
+  <variant name=".Visible"
+      summary="Recorded only for fields that are visible to the user as per
+               Autofill's visibility detection (IsWebElementVisible())."/>
 </variants>
 
 <variants name="AutofillStrikeDatabaseProjectType">
@@ -797,30 +804,15 @@
   </summary>
 </histogram>
 
-<histogram name="Autofill.CreditCard.Number{AutofillMeasurementTime}"
-    units="Filled" expires_after="2022-10-31">
-  <obsolete>
-    Deprecated as of M101. Subsumed by
-    Autofill.CreditCard.Seamless{AutofillMeasurementTime}.Bitmask.
-  </obsolete>
-  <owner>schwering@google.com</owner>
-  <owner>chrome-autofill-alerts@google.com</owner>
-  <summary>
-    Records for each credit card form submission whether a credit card number
-    has been autofilled. {AutofillMeasurementTime}
-
-    That is, emits 1 if a form contains an autofilled credit card number.
-  </summary>
-  <token key="AutofillMeasurementTime" variants="AutofillMeasurementTime"/>
-</histogram>
-
-<histogram name="Autofill.CreditCard.Seamless{AutofillMeasurementTime}"
+<histogram
+    name="Autofill.CreditCard.Seamless{AutofillSeamlessnessFillability}{AutofillSeamlessnessMeasurementTime}{AutofillSeamlessnessVisibility}"
     enum="CreditCardSeamlessFill" expires_after="2022-10-31">
   <owner>schwering@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
     Records for each credit card form the quality of the fill.
-    {AutofillMeasurementTime}
+    {AutofillSeamlessnessFillability} {AutofillSeamlessnessMeasurementTime}
+    {AutofillSeamlessnessVisibility}
 
     The fields in question are: cardholder name (full, or first and last),
     credit card number, expiration date (MM/YY, MM/YYYY, MM and YY, or MM and
@@ -844,16 +836,23 @@
     Any form that contains at least one credit card field counts as credit card
     form.
   </summary>
-  <token key="AutofillMeasurementTime" variants="AutofillMeasurementTime"/>
+  <token key="AutofillSeamlessnessFillability"
+      variants="AutofillSeamlessnessFillability"/>
+  <token key="AutofillSeamlessnessMeasurementTime"
+      variants="AutofillSeamlessnessMeasurementTime"/>
+  <token key="AutofillSeamlessnessVisibility"
+      variants="AutofillSeamlessnessVisibility"/>
 </histogram>
 
-<histogram name="Autofill.CreditCard.Seamless{AutofillMeasurementTime}.Bitmask"
+<histogram
+    name="Autofill.CreditCard.Seamless{AutofillSeamlessnessFillability}{AutofillSeamlessnessMeasurementTime}{AutofillSeamlessnessVisibility}.Bitmask"
     enum="AutofillCreditCardSeamlessnessBitmask" expires_after="2022-10-31">
   <owner>schwering@google.com</owner>
   <owner>chrome-autofill-alerts@google.com</owner>
   <summary>
     Records for each credit card form the quality of the fill.
-    {AutofillMeasurementTime}
+    {AutofillSeamlessnessFillability} {AutofillSeamlessnessMeasurementTime}
+    {AutofillSeamlessnessVisibility}
 
     The emitted value is a non-zero bitmask whose bits have the following
     meaning, from highest to lowest bit:
@@ -866,7 +865,12 @@
 
     Bit #1 is true iff a CVC name was filled.
   </summary>
-  <token key="AutofillMeasurementTime" variants="AutofillMeasurementTime"/>
+  <token key="AutofillSeamlessnessFillability"
+      variants="AutofillSeamlessnessFillability"/>
+  <token key="AutofillSeamlessnessMeasurementTime"
+      variants="AutofillSeamlessnessMeasurementTime"/>
+  <token key="AutofillSeamlessnessVisibility"
+      variants="AutofillSeamlessnessVisibility"/>
 </histogram>
 
 <histogram name="Autofill.CreditCardFillingInfoBar"
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index 64d5c22..ac60465 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -250,6 +250,42 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.PostMessage.OnMessage" enum="Boolean"
+    expires_after="M108">
+  <owner>sinansahin@google.com</owner>
+  <owner>jinsukkim@chromium.org</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    Android only. Recorded when the tab controlled by the CustomTabsSession
+    sends a postMessage. Always emits true.
+  </summary>
+</histogram>
+
+<histogram name="CustomTabs.PostMessage.PostMessageFromClientApp"
+    enum="Boolean" expires_after="M108">
+  <owner>sinansahin@google.com</owner>
+  <owner>jinsukkim@chromium.org</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    Android only. Recorded when the CCT client sends a postMessage request to
+    the tab. Always emits true.
+  </summary>
+</histogram>
+
+<histogram name="CustomTabs.PostMessage.RequestPostMessageChannel"
+    enum="Boolean" expires_after="M108">
+  <owner>sinansahin@google.com</owner>
+  <owner>jinsukkim@chromium.org</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    Android only. Recorded when the CCT client calls requestPostMessageChannel
+    to establish a two way postMessage channel. Emits true if the request is
+    successful and false otherwise. A true value emitted here doesn't mean the
+    request cannot fail later; and a false value may be the result of multiple
+    things, e.g. the warmup hasn't been called.
+  </summary>
+</histogram>
+
 <histogram name="CustomTabs.PredictionStatus" enum="PredictionStatus"
     expires_after="2020-03-01">
   <owner>lizeb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml
index a122a3b..b71d342 100644
--- a/tools/metrics/histograms/metadata/mobile/histograms.xml
+++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -184,28 +184,8 @@
   </summary>
 </histogram>
 
-<histogram name="Mobile.Legacy.Translate.Toggle.Delay" units="ms"
-    expires_after="2020-12-13">
-  <owner>sczs@chromium.org</owner>
-  <owner>thegreenfrog@chromium.org</owner>
-  <summary>
-    Records the time between tapping the target and source language in a legacy
-    infobar. If only one of either is tapped, nothing is logged.
-  </summary>
-</histogram>
-
-<histogram name="Mobile.Legacy.Translate.Unused.Duration" units="ms"
-    expires_after="2020-10-11">
-  <owner>sczs@chromium.org</owner>
-  <owner>thegreenfrog@chromium.org</owner>
-  <summary>
-    Records the time an unused legacy infobar persists on screen. This is logged
-    when the infobar is closed.
-  </summary>
-</histogram>
-
 <histogram name="Mobile.Messages.Badge.Tapped.{MobileInfobarType}"
-    enum="MobileMessagesBadgeState" expires_after="2022-07-24">
+    enum="MobileMessagesBadgeState" expires_after="2023-07-24">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
@@ -214,7 +194,7 @@
 </histogram>
 
 <histogram name="Mobile.Messages.Banner.Dismiss.{MobileInfobarType}"
-    enum="MobileMessagesBannerDismissType" expires_after="2022-07-24">
+    enum="MobileMessagesBannerDismissType" expires_after="2023-07-24">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
@@ -223,7 +203,7 @@
 </histogram>
 
 <histogram name="Mobile.Messages.Banner.Event.{MobileInfobarType}"
-    enum="MobileMessagesBannerEvent" expires_after="2022-07-31">
+    enum="MobileMessagesBannerEvent" expires_after="2023-07-31">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>Records infobar banner events. {MobileInfobarType}</summary>
@@ -275,14 +255,14 @@
 </histogram>
 
 <histogram name="Mobile.Messages.Modal.Event.{MobileInfobarType}"
-    enum="MobileMessagesModalEvent" expires_after="2022-07-24">
+    enum="MobileMessagesModalEvent" expires_after="2023-07-24">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>Records generic infobar modal events. {MobileInfobarType}</summary>
 </histogram>
 
 <histogram base="true" name="Mobile.Messages.OverflowRow.Tapped"
-    enum="MobileMessagesInfobarType" expires_after="2022-07-20">
+    enum="MobileMessagesInfobarType" expires_after="2023-07-20">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>Records a tap on an Infobar overflow menu row.</summary>
@@ -307,7 +287,7 @@
 </histogram>
 
 <histogram base="true" name="Mobile.Messages.Passwords.Modal.Present"
-    enum="MobileMessagesPasswordsModalPresent" expires_after="2022-07-20">
+    enum="MobileMessagesPasswordsModalPresent" expires_after="2023-07-20">
 <!-- Name completed by histogram_suffixes name="Mobile.Messages.Password.Type" -->
 
   <owner>sczs@chromium.org</owner>
@@ -316,14 +296,14 @@
 </histogram>
 
 <histogram name="Mobile.Messages.Save.Card.Modal.Event"
-    enum="MobileMessagesSaveCardModalEvent" expires_after="2022-10-16">
+    enum="MobileMessagesSaveCardModalEvent" expires_after="2023-10-16">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>Records Save Card specific Infobar Modal events.</summary>
 </histogram>
 
 <histogram name="Mobile.Messages.Translate.Banner.Event"
-    enum="MobileMessagesTranslateBannerEvent" expires_after="2022-07-20">
+    enum="MobileMessagesTranslateBannerEvent" expires_after="2023-07-20">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
@@ -343,7 +323,7 @@
 </histogram>
 
 <histogram name="Mobile.Messages.Translate.Modal.Present"
-    enum="MobileMessagesTranslateModalPresent" expires_after="2022-07-20">
+    enum="MobileMessagesTranslateModalPresent" expires_after="2023-07-20">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
@@ -579,7 +559,7 @@
 </histogram>
 
 <histogram name="Mobile.Translate.Unused.Count" units="units"
-    expires_after="2022-07-31">
+    expires_after="2023-07-31">
   <owner>sczs@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 0deb258..bcf0ee7 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -1601,7 +1601,11 @@
 </histogram>
 
 <histogram name="Network.Shill.PortalDetectionMultiProbeResult"
-    enum="PortalDetectionMultiProbeResult" expires_after="2022-12-31">
+    enum="PortalDetectionMultiProbeResult" expires_after="2022-06-17">
+  <obsolete>
+    Removed 6/2022 because it is unmonitored and not technology specific.
+    TODO(b/236386653): Remove entirely once removed from Shill.
+  </obsolete>
   <owner>matthewmwang@chromium.org</owner>
   <owner>cros-network-metrics@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/notifications/OWNERS b/tools/metrics/histograms/metadata/notifications/OWNERS
index 2a1833a..b93feb14 100644
--- a/tools/metrics/histograms/metadata/notifications/OWNERS
+++ b/tools/metrics/histograms/metadata/notifications/OWNERS
@@ -2,4 +2,5 @@
 
 # Prefer sending CLs to the owners listed below.
 # Use chromium-metrics-reviews@google.com as a backup.
-knollr@chromium.org
+peter@chromium.org
+rayankans@chromium.org
diff --git a/tools/metrics/histograms/metadata/notifications/histograms.xml b/tools/metrics/histograms/metadata/notifications/histograms.xml
index d975c30..ed42c17 100644
--- a/tools/metrics/histograms/metadata/notifications/histograms.xml
+++ b/tools/metrics/histograms/metadata/notifications/histograms.xml
@@ -613,7 +613,7 @@
 
 <histogram
     name="Notifications.Permissions.UNNotification.{Style}.PermissionRequest"
-    enum="UNNotificationPermissionRequestResult" expires_after="M98">
+    enum="UNNotificationPermissionRequestResult" expires_after="M110">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -627,7 +627,7 @@
 
 <histogram
     name="Notifications.Permissions.UNNotification.{Style}.PermissionStatus"
-    enum="UNNotificationPermissionStatus" expires_after="M98">
+    enum="UNNotificationPermissionStatus" expires_after="M110">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -640,7 +640,7 @@
 </histogram>
 
 <histogram name="Notifications.Permissions.UNNotification.{Style}.Style"
-    enum="UNNotificationStyle" expires_after="M98">
+    enum="UNNotificationStyle" expires_after="M110">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 14e665f..3928c70 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -8792,6 +8792,50 @@
   </summary>
 </histogram>
 
+<histogram name="OSCrypt.Win.Decrypt.Result" enum="BooleanSuccess"
+    expires_after="M106">
+  <owner>wfh@chromium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    Whether or not the DPAPI Decrypt call to decrypt the OSCrypt key succeeeded.
+    This is logged once during browser startup on Windows.
+  </summary>
+</histogram>
+
+<histogram name="OSCrypt.Win.Decrypt.Time" units="ms" expires_after="M106">
+  <owner>wfh@chromium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The amount of time, in ms, that it takes to perform a DPAPI Decrypt call.
+    This is logged once during browser startup on Windows.
+  </summary>
+</histogram>
+
+<histogram name="OSCrypt.Win.Encrypt.Result" enum="BooleanSuccess"
+    expires_after="M106">
+  <owner>wfh@chromium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    Whether or not the DPAPI Encrypt call to encrypt the OSCrypt key succeeeded.
+    This is logged once during browser startup on Windows, if there is no stored
+    key and a new one has to be generated. This data will therefore be biased
+    towards newer clients. See OSCrypt.Win.Decrypt.Result which contains
+    unbiased data.
+  </summary>
+</histogram>
+
+<histogram name="OSCrypt.Win.Encrypt.Time" units="ms" expires_after="M106">
+  <owner>wfh@chromium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The amount of time, in ms, that it takes to perform a DPAPI Encrypt call.
+    This is logged once during browser startup on Windows, if there is no stored
+    key and a new one has to be generated. This data will therefore be biased
+    towards newer clients. See OSCrypt.Win.Decrypt.Time which contains unbiased
+    data.
+  </summary>
+</histogram>
+
 <histogram name="OSCrypt.Win.KeyDecryptionError" enum="WinGetLastError"
     expires_after="2021-08-01">
   <owner>wfh@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml
index 524de10..1b76150 100644
--- a/tools/metrics/histograms/metadata/search/histograms.xml
+++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -778,8 +778,8 @@
 </histogram>
 
 <histogram name="Search.ContextualSearchPromoOpenCount2" units="opens"
-    expires_after="2022-06-26">
-  <owner>donnd@chromium.org</owner>
+    expires_after="2023-06-26">
+  <owner>gangwu@chromium.org</owner>
   <owner>contextual-search-eng@chromium.org</owner>
   <summary>
     The total count of times that the revised promo has been shown. Once the
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 8b42bd1..6286d1a 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -1612,6 +1612,20 @@
       filled if the credit card on file was complete.
     </summary>
   </metric>
+  <metric name="Fillable.AfterSecurity.Visible.Bitmask"
+      enum="AutofillCreditCardSeamlessnessBitmask">
+    <summary>
+      Logs the field types which Autofill would have filled into visible fields
+      if the credit card on file was complete.
+    </summary>
+  </metric>
+  <metric name="Fillable.AfterSecurity.Visible.Qualitative"
+      enum="CreditCardSeamlessFill">
+    <summary>
+      Logs a qualitative summary of the field types which Autofill would have
+      filled into visible fields if the credit card on file was complete.
+    </summary>
+  </metric>
   <metric name="Fillable.BeforeSecurity.Bitmask"
       enum="AutofillCreditCardSeamlessnessBitmask">
     <summary>
@@ -1627,6 +1641,21 @@
       policy.
     </summary>
   </metric>
+  <metric name="Fillable.BeforeSecurity.Visible.Bitmask"
+      enum="AutofillCreditCardSeamlessnessBitmask">
+    <summary>
+      Logs the field types which Autofill would have filled into visible fields
+      if the credit card on file was complete and there was no security policy.
+    </summary>
+  </metric>
+  <metric name="Fillable.BeforeSecurity.Visible.Qualitative"
+      enum="CreditCardSeamlessFill">
+    <summary>
+      Logs a qualitative summary of the field types which Autofill would have
+      filled into visible fields if the credit card on file was complete and
+      there was no security policy.
+    </summary>
+  </metric>
   <metric name="Filled.AfterSecurity.Bitmask"
       enum="AutofillCreditCardSeamlessnessBitmask">
     <summary>
@@ -1639,6 +1668,19 @@
       filled.
     </summary>
   </metric>
+  <metric name="Filled.AfterSecurity.Visible.Bitmask"
+      enum="AutofillCreditCardSeamlessnessBitmask">
+    <summary>
+      Logs the field types which Autofill actually filled into visible fields.
+    </summary>
+  </metric>
+  <metric name="Filled.AfterSecurity.Visible.Qualitative"
+      enum="CreditCardSeamlessFill">
+    <summary>
+      Logs a qualitative summary of the field types which Autofill actually
+      filled into visible fields.
+    </summary>
+  </metric>
   <metric name="Filled.BeforeSecurity.Bitmask"
       enum="AutofillCreditCardSeamlessnessBitmask">
     <summary>
@@ -1653,6 +1695,20 @@
       filled if there was no security policy.
     </summary>
   </metric>
+  <metric name="Filled.BeforeSecurity.Visible.Bitmask"
+      enum="AutofillCreditCardSeamlessnessBitmask">
+    <summary>
+      Logs the field types which Autofill would have filled into visible fields
+      if there was no security policy.
+    </summary>
+  </metric>
+  <metric name="Filled.BeforeSecurity.Visible.Qualitative"
+      enum="CreditCardSeamlessFill">
+    <summary>
+      Logs a qualitative summary of the field types which Autofill would have
+      filled into visible fields if there was no security policy.
+    </summary>
+  </metric>
   <metric name="FormSignature">
     <summary>
       An approximately 10-bit hash of the form's actual signature.
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index bf01e3e..b503ac19 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": "53fc881fbd90c7b86c93038753e5a58e8dc280df",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/8f3eeefc3742dbdec0c6c76f17d3d9ca7cc8e6c4/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/a15b969a82947fe647e30f9aea938a6bf11d3d68/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
@@ -14,15 +14,15 @@
         },
         "mac": {
             "hash": "0222c03249c2ac97990c17ff2bf951c16d63c3b8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/a15b969a82947fe647e30f9aea938a6bf11d3d68/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/5c85522e6e4c1670e58b341f05b68892df56a3c7/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "85fffaf6acd440eb732648f602ff261b5d755b5c",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/a15b969a82947fe647e30f9aea938a6bf11d3d68/trace_processor_shell"
+            "hash": "695c35c4dc544a9359c100ffafa58d7322eb7633",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/ae42e46f238d58c259af6366aba90e18e975cfa5/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/rust/.style.yapf b/tools/rust/.style.yapf
new file mode 100644
index 0000000..557fa7b
--- /dev/null
+++ b/tools/rust/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = pep8
diff --git a/tools/rust/build_crubit.py b/tools/rust/build_crubit.py
new file mode 100755
index 0000000..2074486
--- /dev/null
+++ b/tools/rust/build_crubit.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+# Copyright 2022 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+'''Builds the Crubit tool.
+
+!!! DO NOT USE IN PRODUCTION
+Builds the Crubit tool (an experiment for Rust/C++ FFI bindings generation).
+
+This script clones the Crubit repository, checks it out to a defined revision,
+and then uses Bazel to build Crubit.
+'''
+
+import argparse
+import collections
+import hashlib
+import os
+import pipes
+import shutil
+import string
+import subprocess
+import sys
+
+from pathlib import Path
+
+# Get variables and helpers from Clang update script
+sys.path.append(
+    os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'clang',
+                 'scripts'))
+
+from update import (CLANG_REVISION, CLANG_SUB_REVISION, LLVM_BUILD_DIR)
+from build import LLVM_BOOTSTRAP_INSTALL_DIR
+
+from update_rust import (CHROMIUM_DIR, RUST_REVISION, RUST_SUB_REVISION,
+                         STAGE0_JSON_SHA256, THIRD_PARTY_DIR,
+                         GetPackageVersion)
+
+# Trunk on 2022-06-13.
+CRUBIT_REVISION = '0a25665ed0df6d4f067bfd5855be1c24d2df3f6c'
+CRUBIT_SUB_REVISION = 1
+
+THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party')
+CRUBIT_SRC_DIR = os.path.join(THIRD_PARTY_DIR, 'crubit')
+
+
+def RunCommand(command, env=None, cwd=None, fail_hard=True):
+    print('Running', command)
+    if subprocess.run(command, env=env, cwd=cwd,
+                      shell=sys.platform == 'win32').returncode == 0:
+        return True
+    print('Failed.')
+    if fail_hard:
+        raise RuntimeError(f"Failed to run {command}")
+    return False
+
+
+def CheckoutCrubit(commit, dir):
+    """Checkout the Crubit repo at a certain git commit in dir. Any local
+  modifications in dir will be lost."""
+
+    print('Checking out crubit repo %s into %s' % (commit, dir))
+
+    # Try updating the current repo if it exists and has no local diff.
+    if os.path.isdir(dir):
+        os.chdir(dir)
+        # git diff-index --quiet returns success when there is no diff.
+        # Also check that the first commit is reachable.
+        if (RunCommand(['git', 'diff-index', '--quiet', 'HEAD'],
+                       fail_hard=False)
+                and RunCommand(['git', 'fetch'], fail_hard=False)
+                and RunCommand(['git', 'checkout', commit], fail_hard=False)):
+            return
+
+        # If we can't use the current repo, delete it.
+        os.chdir(CHROMIUM_DIR)  # Can't remove dir if we're in it.
+        print('Removing %s.' % dir)
+        RmTree(dir)
+
+    clone_cmd = ['git', 'clone', 'https://github.com/google/crubit.git', dir]
+
+    if RunCommand(clone_cmd, fail_hard=False):
+        os.chdir(dir)
+        if RunCommand(['git', 'checkout', commit], fail_hard=False):
+            return
+
+    print('CheckoutCrubit failed.')
+    sys.exit(1)
+
+
+def BuildCrubit():
+    # TODO(https://crbug.com/1337346): Use locally built Rust instead of having
+    # Bazel always download the whole Rust toolchain from the internet.
+    # TODO(https://crbug.com/1337348): Use crates from chromium/src/third_party/rust.
+    # TODO(https://crbug.com/1338217): Don't use system-wide C++ stdlib.
+    env = {"LLVM_INSTALL_PATH": LLVM_BOOTSTRAP_INSTALL_DIR}
+    args = ["bazel", "build", "rs_bindings_from_cc:rs_bindings_from_cc_impl"]
+
+    # CC is set via `--repo_env` rather than via `env` to ensure that we
+    # override the defaults from `crubit/.bazelrc`.
+    #
+    # Note that we use `bin/clang` from `LLVM_BUILD_DIR`, but depend on headers
+    # and libraries from `LLVM_BOOTSTRAP_INSTALL_DIR`.  The former helps ensure
+    # that we use the same compiler as the final one used elsewhere in Chromium.
+    # The latter is needed, because the headers+libraries are not available
+    # anywhere else.
+    clang_path = os.path.join(LLVM_BUILD_DIR, "bin", "clang")
+    args += [
+        "--repo_env=CC=",  # Unset/ignore old values from the environment.
+        "--repo_env=CXX=",
+        "--repo_env=LD=",
+        f"--repo_env=CC={clang_path}",
+        f"--repo_env=CXX={clang_path}++",
+        f"--repo_env=LD={clang_path}",
+    ]
+
+    RunCommand(args, env=env, cwd=CRUBIT_SRC_DIR)
+
+
+def ShutdownBazel():
+    # This needs to use the same arguments as BuildCrubit, because otherwise
+    # we get: WARNING: Running Bazel server needs to be killed, because the
+    # startup options are different.
+    RunCommand(["bazel", "shutdown"], cwd=CRUBIT_SRC_DIR)
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='Build and package Crubit tools')
+    parser.add_argument('-v',
+                        '--verbose',
+                        action='count',
+                        help='run subcommands with verbosity')
+    parser.add_argument(
+        '--skip-checkout',
+        action='store_true',
+        help='skip Crubit git checkout. Useful for trying local changes')
+    args, rest = parser.parse_known_args()
+
+    if not args.skip_checkout:
+        CheckoutCrubit(CRUBIT_REVISION, CRUBIT_SRC_DIR)
+
+    try:
+        BuildCrubit()
+    finally:
+        ShutdownBazel()
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/tools/visual_debugger/app.html b/tools/visual_debugger/app.html
index 5196a89..d4638bb2 100644
--- a/tools/visual_debugger/app.html
+++ b/tools/visual_debugger/app.html
@@ -371,7 +371,7 @@
     });
 
     setUpPlayer();
-    FilterUIDefault.initialize();
+    restoreFilters();
   }
 
   function setUpPlayer() {
diff --git a/tools/visual_debugger/filter-ui.js b/tools/visual_debugger/filter-ui.js
index 4ab18070..10929f1 100644
--- a/tools/visual_debugger/filter-ui.js
+++ b/tools/visual_debugger/filter-ui.js
@@ -235,6 +235,9 @@
   showModal(filterUi);
 }
 
+// Traverses through all the filter chips and enables/disables
+// "move next/prev" button clickability depending on if
+// the chip is at the beginning/middle/end of list
 function refreshFilterSet() {
   const list = document.querySelector('#filters');
   for (var chip = list.firstElementChild;
@@ -256,6 +259,7 @@
         .classList.remove("mdc-list-item--disabled");
     }
   }
+  locallyStoreFilters();
 
   Player.instance.refresh();
 
@@ -350,13 +354,80 @@
   refreshFilterSet();
 }
 
+// Stores filter instances in local storage
+function locallyStoreFilters() {
+  var filterInstances = Filter.instances;
+  // Store string representation of filterInstances list in local storage.
+  localStorage.setItem('filterInstances', JSON.stringify(filterInstances));
+}
+
+// Restores filter instances from local storage.
+function restoreFilters() {
+  const retrievedFilterString = localStorage.getItem('filterInstances');
+  // Add default filters to the instances list.
+  FilterUIDefault.initialize();
+
+  if (!retrievedFilterString) {
+    return;
+  }
+
+  var retrievedFilterInstances = JSON.parse(retrievedFilterString);
+  // Remove any default filter duplicates from restored filters.
+  for (const defaultFilter of defaultFilters) {
+    retrievedFilterInstances = retrievedFilterInstances.filter
+        (instance => !isDuplicate(instance, defaultFilter));
+  }
+  // Re-create non-default filter chips from local storage.
+  // Pre-existing filters are appended behind the default ones.
+  retrievedFilterInstances.forEach((instance) =>
+    createFilterComplete(instance.selector_, instance.action_));
+}
+
+// Checks if one filter is a duplicate of another.
+// NOTE: Custom equality check needed to avoid marking same style
+// of filters with different enabled states and indices as
+// non-duplicates.
+function isDuplicate(filter1, filter2) {
+  if (!filter1 || !filter2) {
+    return false;
+  }
+  if (filter1.selector_.filename !== filter2.selector_.filename) {
+    return false;
+  }
+  if (filter1.selector_.func !== filter2.selector_.func) {
+    return false;
+  }
+  if (filter1.selector_.anno !== filter2.selector_.anno) {
+    return false;
+  }
+  if (filter1.action_.skipDraw !== filter2.action_.skipDraw) {
+    return false;
+  }
+  if (filter1.action_.color !== filter2.action_.color) {
+    return false;
+  }
+  if (filter1.action_.alpha !== filter2.action_.alpha) {
+    return false;
+  }
+  return true;
+}
+
+const defaultFilters = [
+    {
+      selector_: { filename: "", func: "", anno: "frame.root.quad" },
+      action_: { skipDraw: false, color: '#000000', alpha: "10" }
+    },
+    {
+      selector_: { filename: "", func: "", anno: "frame.root.damage" },
+      action_: { skipDraw: false, color: '#FF0000', alpha: "20" }
+    }
+];
+
 // Default filters should probably load off disk.
 const FilterUIDefault = {
   initialize() {
-    createFilterComplete({ filename: "", func: "", anno: "frame.root.quad" },
-      { skipDraw: false, color: '#000000', alpha: "10" });
-    createFilterComplete({ filename: "", func: "", anno: "frame.root.damage" },
-      { skipDraw: false, color: '#FF0000', alpha: "20" });
+    defaultFilters.forEach((instance) =>
+      createFilterComplete(instance.selector_, instance.action_))
   }
 };
 
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index 457757a..f4f835dd 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -8,11 +8,12 @@
 #include <IOSurface/IOSurface.h>
 #include <QuartzCore/QuartzCore.h>
 
+#include <list>
 #include <memory>
-#include <vector>
 
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_nsobject.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
 #include "ui/gfx/geometry/rect.h"
@@ -82,10 +83,17 @@
   class ContentLayer;
   friend class ContentLayer;
 
+  // Populate the `old_layer_` entries for all layers in `this`, pointing them
+  // to values in `old_tree`. This is a very naive algorithm and often creates
+  // large diffs.
+  // TODO(https://crbug.com/1313999): Find a better V2 matching algorithm.
+  void MatchLayersToOldTreeV1(CARendererLayerTree* old_tree);
+
   class RootLayer {
    public:
-    RootLayer();
+    RootLayer(CARendererLayerTree* tree);
 
+    RootLayer(RootLayer&&) = delete;
     RootLayer(const RootLayer&) = delete;
     RootLayer& operator=(const RootLayer&) = delete;
 
@@ -107,27 +115,33 @@
     // properties appropriately. Re-use the CALayers from |old_layer| if
     // possible. If re-using a CALayer from |old_layer|, reset its |ca_layer|
     // to nil, so that its destructor will not remove an active CALayer.
-    void CommitToCA(CALayer* superlayer,
-                    RootLayer* old_layer,
-                    const gfx::Size& pixel_size,
-                    float scale_factor);
+    void CommitToCA(CALayer* superlayer, const gfx::Size& pixel_size);
 
     // Return true if the CALayer tree is just a video layer on a black or
     // transparent background, false otherwise.
     bool WantsFullcreenLowPowerBackdrop() const;
 
-    std::vector<ClipAndSortingLayer> clip_and_sorting_layers_;
+    // Tree that owns `this`.
+    const raw_ptr<CARendererLayerTree> tree_;
+
+    std::list<ClipAndSortingLayer> clip_and_sorting_layers_;
     base::scoped_nsobject<CALayer> ca_layer_;
+
+    // Weak pointer to the layer in the old CARendererLayerTree that will be
+    // reused by this layer, and the weak factory used to make that pointer.
+    base::WeakPtr<RootLayer> old_layer_;
+    base::WeakPtrFactory<RootLayer> weak_factory_for_new_layer_{this};
   };
   class ClipAndSortingLayer {
    public:
-    ClipAndSortingLayer(bool is_clipped,
+    ClipAndSortingLayer(RootLayer* root_layer,
+                        bool is_clipped,
                         gfx::Rect clip_rect,
                         gfx::RRectF rounded_corner_bounds,
                         unsigned sorting_context_id,
                         bool is_singleton_sorting_context);
-    ClipAndSortingLayer(ClipAndSortingLayer&& layer);
 
+    ClipAndSortingLayer(ClipAndSortingLayer&& layer) = delete;
     ClipAndSortingLayer(const ClipAndSortingLayer&) = delete;
     ClipAndSortingLayer& operator=(const ClipAndSortingLayer&) = delete;
 
@@ -136,11 +150,13 @@
     ~ClipAndSortingLayer();
     void AddContentLayer(CARendererLayerTree* tree,
                          const CARendererLayerParams& params);
-    void CommitToCA(CALayer* superlayer,
-                    ClipAndSortingLayer* old_layer,
-                    float scale_factor);
+    void CommitToCA();
+    CARendererLayerTree* tree() { return parent_layer_->tree_; }
 
-    std::vector<TransformLayer> transform_layers_;
+    // Parent layer that owns `this`, and child layers that `this` owns.
+    const raw_ptr<RootLayer> parent_layer_;
+    std::list<TransformLayer> transform_layers_;
+
     bool is_clipped_ = false;
     gfx::Rect clip_rect_;
     gfx::RRectF rounded_corner_bounds_;
@@ -148,12 +164,18 @@
     bool is_singleton_sorting_context_ = false;
     base::scoped_nsobject<CALayer> clipping_ca_layer_;
     base::scoped_nsobject<CALayer> rounded_corner_ca_layer_;
+
+    // Weak pointer to the layer in the old CARendererLayerTree that will be
+    // reused by this layer, and the weak factory used to make that pointer.
+    base::WeakPtr<ClipAndSortingLayer> old_layer_;
+    base::WeakPtrFactory<ClipAndSortingLayer> weak_factory_for_new_layer_{this};
   };
   class TransformLayer {
    public:
-    TransformLayer(const gfx::Transform& transform);
-    TransformLayer(TransformLayer&& layer);
+    TransformLayer(ClipAndSortingLayer* parent_layer,
+                   const gfx::Transform& transform);
 
+    TransformLayer(TransformLayer&& layer) = delete;
     TransformLayer(const TransformLayer&) = delete;
     TransformLayer& operator=(const TransformLayer&) = delete;
 
@@ -162,17 +184,24 @@
     ~TransformLayer();
     void AddContentLayer(CARendererLayerTree* tree,
                          const CARendererLayerParams& params);
-    void CommitToCA(CALayer* superlayer,
-                    TransformLayer* old_layer,
-                    float scale_factor);
+    void CommitToCA();
+    CARendererLayerTree* tree() { return parent_layer_->tree(); }
+
+    // Parent layer that owns `this`, and child layers that `this` owns.
+    const raw_ptr<ClipAndSortingLayer> parent_layer_;
+    std::list<ContentLayer> content_layers_;
 
     gfx::Transform transform_;
-    std::vector<ContentLayer> content_layers_;
     base::scoped_nsobject<CALayer> ca_layer_;
+
+    // Weak pointer to the layer in the old CARendererLayerTree that will be
+    // reused by this layer, and the weak factory used to make that pointer.
+    base::WeakPtr<TransformLayer> old_layer_;
+    base::WeakPtrFactory<TransformLayer> weak_factory_for_new_layer_{this};
   };
   class ContentLayer {
    public:
-    ContentLayer(CARendererLayerTree* tree,
+    ContentLayer(TransformLayer* parent_layer,
                  base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
                  base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
                  const gfx::RectF& contents_rect,
@@ -183,17 +212,18 @@
                  float opacity,
                  unsigned filter,
                  gfx::ProtectedVideoType protected_video_type);
-    ContentLayer(ContentLayer&& layer);
 
+    ContentLayer(ContentLayer&& layer) = delete;
     ContentLayer(const ContentLayer&) = delete;
     ContentLayer& operator=(const ContentLayer&) = delete;
 
-    // See the behavior of RootLayer for the effects of these functions on the
-    // |ca_layer| member and |old_layer| argument.
+    // See the behavior of RootLayer for the effects of these functions.
     ~ContentLayer();
-    void CommitToCA(CALayer* parent,
-                    ContentLayer* old_layer,
-                    float scale_factor);
+    void CommitToCA();
+    CARendererLayerTree* tree() { return parent_layer_->tree(); }
+
+    // Parent layer that owns `this`.
+    const raw_ptr<TransformLayer> parent_layer_;
 
     // Ensure that the IOSurface be marked as in-use as soon as it is received.
     // When they are committed to the window server, that will also increment
@@ -232,9 +262,14 @@
     // Layer used to colorize content when it updates, if borders are
     // enabled.
     base::scoped_nsobject<CALayer> update_indicator_layer_;
+
+    // Weak pointer to the layer in the old CARendererLayerTree that will be
+    // reused by this layer, and the weak factory used to make that pointer.
+    base::WeakPtr<ContentLayer> old_layer_;
+    base::WeakPtrFactory<ContentLayer> weak_factory_for_new_layer_{this};
   };
 
-  RootLayer root_layer_;
+  RootLayer root_layer_{this};
   float scale_factor_ = 1;
   bool has_committed_ = false;
   const bool allow_av_sample_buffer_display_layer_ = true;
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 523f6bd8..1e69e87 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -272,19 +272,74 @@
     const gfx::Size& pixel_size,
     float scale_factor) {
   TRACE_EVENT0("gpu", "CARendererLayerTree::CommitScheduledCALayers");
-  RootLayer* old_root_layer = nullptr;
-  if (old_tree) {
-    DCHECK(old_tree->has_committed_);
-    if (old_tree->scale_factor_ == scale_factor)
-      old_root_layer = &old_tree->root_layer_;
-  }
+  scale_factor_ = scale_factor;
 
-  root_layer_.CommitToCA(superlayer, old_root_layer, pixel_size, scale_factor);
+  MatchLayersToOldTreeV1(old_tree.get());
+
+  root_layer_.CommitToCA(superlayer, pixel_size);
   // If there are any extra CALayers in |old_tree| that were not stolen by this
   // tree, they will be removed from the CALayer tree in this deallocation.
   old_tree.reset();
   has_committed_ = true;
-  scale_factor_ = scale_factor;
+}
+
+void CARendererLayerTree::MatchLayersToOldTreeV1(
+    CARendererLayerTree* old_tree) {
+  if (!old_tree)
+    return;
+  DCHECK(old_tree->has_committed_);
+
+  // Match the root layer.
+  if (old_tree->scale_factor_ != scale_factor_)
+    return;
+  root_layer_.old_layer_ =
+      old_tree->root_layer_.weak_factory_for_new_layer_.GetWeakPtr();
+
+  // Iterate and match clip and sorting layers.
+  auto old_clip_and_sorting_layer_it =
+      root_layer_.old_layer_
+          ? root_layer_.old_layer_->clip_and_sorting_layers_.begin()
+          : std::list<ClipAndSortingLayer>::iterator();
+  for (auto& clip_and_sorting_layer : root_layer_.clip_and_sorting_layers_) {
+    if (root_layer_.old_layer_ &&
+        old_clip_and_sorting_layer_it !=
+            root_layer_.old_layer_->clip_and_sorting_layers_.end()) {
+      clip_and_sorting_layer.old_layer_ =
+          old_clip_and_sorting_layer_it->weak_factory_for_new_layer_
+              .GetWeakPtr();
+      old_clip_and_sorting_layer_it++;
+    }
+
+    // Iterate and match transform layers.
+    auto old_transform_layer_it =
+        clip_and_sorting_layer.old_layer_
+            ? clip_and_sorting_layer.old_layer_->transform_layers_.begin()
+            : std::list<TransformLayer>::iterator();
+    for (auto& transform_layer : clip_and_sorting_layer.transform_layers_) {
+      if (clip_and_sorting_layer.old_layer_ &&
+          old_transform_layer_it !=
+              clip_and_sorting_layer.old_layer_->transform_layers_.end()) {
+        transform_layer.old_layer_ =
+            old_transform_layer_it->weak_factory_for_new_layer_.GetWeakPtr();
+        old_transform_layer_it++;
+      }
+
+      // Iterate and match content layers.
+      auto old_content_layer_it =
+          transform_layer.old_layer_
+              ? transform_layer.old_layer_->content_layers_.begin()
+              : std::list<ContentLayer>::iterator();
+      for (auto& content_layer : transform_layer.content_layers_) {
+        if (transform_layer.old_layer_ &&
+            old_content_layer_it !=
+                transform_layer.old_layer_->content_layers_.end()) {
+          content_layer.old_layer_ =
+              old_content_layer_it->weak_factory_for_new_layer_.GetWeakPtr();
+          old_content_layer_it++;
+        }
+      }
+    }
+  }
 }
 
 bool CARendererLayerTree::RootLayer::WantsFullcreenLowPowerBackdrop() const {
@@ -345,25 +400,26 @@
     return nullptr;
   }
   const ClipAndSortingLayer& clip_and_sorting =
-      root_layer_.clip_and_sorting_layers_[0];
+      root_layer_.clip_and_sorting_layers_.front();
   size_t transform_count = clip_and_sorting.transform_layers_.size();
   if (transform_count != 1) {
     DLOG(ERROR) << "Can only return contents IOSurface when there is 1 "
                 << "TransformLayer, there are " << transform_count << ".";
     return nullptr;
   }
-  const TransformLayer& transform = clip_and_sorting.transform_layers_[0];
+  const TransformLayer& transform = clip_and_sorting.transform_layers_.front();
   size_t content_count = transform.content_layers_.size();
   if (content_count != 1) {
     DLOG(ERROR) << "Can only return contents IOSurface when there is 1 "
                 << "ContentLayer, there are " << transform_count << ".";
     return nullptr;
   }
-  const ContentLayer& content = transform.content_layers_[0];
+  const ContentLayer& content = transform.content_layers_.front();
   return content.io_surface_.get();
 }
 
-CARendererLayerTree::RootLayer::RootLayer() {}
+CARendererLayerTree::RootLayer::RootLayer(CARendererLayerTree* tree)
+    : tree_(tree) {}
 
 // Note that for all destructors, the the CALayer will have been reset to nil if
 // another layer has taken it.
@@ -372,57 +428,35 @@
 }
 
 CARendererLayerTree::ClipAndSortingLayer::ClipAndSortingLayer(
+    RootLayer* parent_layer,
     bool is_clipped,
     gfx::Rect clip_rect,
     gfx::RRectF rounded_corner_bounds_arg,
     unsigned sorting_context_id,
     bool is_singleton_sorting_context)
-    : is_clipped_(is_clipped),
+    : parent_layer_(parent_layer),
+      is_clipped_(is_clipped),
       clip_rect_(clip_rect),
       rounded_corner_bounds_(rounded_corner_bounds_arg),
       sorting_context_id_(sorting_context_id),
       is_singleton_sorting_context_(is_singleton_sorting_context) {}
 
-CARendererLayerTree::ClipAndSortingLayer::ClipAndSortingLayer(
-    ClipAndSortingLayer&& layer)
-    : transform_layers_(std::move(layer.transform_layers_)),
-      is_clipped_(layer.is_clipped_),
-      clip_rect_(layer.clip_rect_),
-      rounded_corner_bounds_(layer.rounded_corner_bounds_),
-      sorting_context_id_(layer.sorting_context_id_),
-      is_singleton_sorting_context_(layer.is_singleton_sorting_context_),
-      clipping_ca_layer_(layer.clipping_ca_layer_),
-      rounded_corner_ca_layer_(layer.rounded_corner_ca_layer_) {
-  // Ensure that the ca_layer be reset, so that when the destructor is called,
-  // the layer hierarchy is unaffected.
-  // TODO(ccameron): Add a move constructor for scoped_nsobject to do this
-  // automatically.
-  layer.clipping_ca_layer_.reset();
-  layer.rounded_corner_ca_layer_.reset();
-}
-
 CARendererLayerTree::ClipAndSortingLayer::~ClipAndSortingLayer() {
   [clipping_ca_layer_ removeFromSuperlayer];
   [rounded_corner_ca_layer_ removeFromSuperlayer];
 }
 
 CARendererLayerTree::TransformLayer::TransformLayer(
+    ClipAndSortingLayer* parent_layer,
     const gfx::Transform& transform)
-    : transform_(transform) {}
-
-CARendererLayerTree::TransformLayer::TransformLayer(TransformLayer&& layer)
-    : transform_(layer.transform_),
-      content_layers_(std::move(layer.content_layers_)),
-      ca_layer_(layer.ca_layer_) {
-  layer.ca_layer_.reset();
-}
+    : parent_layer_(parent_layer), transform_(transform) {}
 
 CARendererLayerTree::TransformLayer::~TransformLayer() {
   [ca_layer_ removeFromSuperlayer];
 }
 
 CARendererLayerTree::ContentLayer::ContentLayer(
-    CARendererLayerTree* tree,
+    TransformLayer* parent_layer,
     base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
     base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
     const gfx::RectF& contents_rect,
@@ -433,7 +467,8 @@
     float opacity,
     unsigned filter,
     gfx::ProtectedVideoType protected_video_type)
-    : io_surface_(io_surface),
+    : parent_layer_(parent_layer),
+      io_surface_(io_surface),
       cv_pixel_buffer_(cv_pixel_buffer),
       contents_rect_(contents_rect),
       rect_(rect),
@@ -453,7 +488,7 @@
   // transparent layers must use real colors to be eligible for low power
   // detachment in fullscreen.
   // https://crbug.com/633805
-  if (!io_surface && !tree->allow_solid_color_layers_ &&
+  if (!io_surface && !tree()->allow_solid_color_layers_ &&
       background_color_ != SK_ColorBLACK &&
       background_color_ != SK_ColorTRANSPARENT) {
     solid_color_contents_ = SolidColorContents::Get(background_color);
@@ -490,7 +525,7 @@
   } else if (io_surface) {
     // Only allow 4:2:0 frames which fill the layer's contents or protected
     // video to be promoted to AV layers.
-    if (tree->allow_av_sample_buffer_display_layer_) {
+    if (tree()->allow_av_sample_buffer_display_layer_) {
       if (contents_rect == gfx::RectF(0, 0, 1, 1)) {
         switch (IOSurfaceGetPixelFormat(io_surface)) {
           case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
@@ -544,28 +579,6 @@
   }
 }
 
-CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer)
-    : io_surface_(layer.io_surface_),
-      cv_pixel_buffer_(layer.cv_pixel_buffer_),
-      solid_color_contents_(layer.solid_color_contents_),
-      contents_rect_(layer.contents_rect_),
-      rect_(layer.rect_),
-      background_color_(layer.background_color_),
-      io_surface_color_space_(layer.io_surface_color_space_),
-      ca_edge_aa_mask_(layer.ca_edge_aa_mask_),
-      opacity_(layer.opacity_),
-      ca_filter_(layer.ca_filter_),
-      type_(layer.type_),
-      video_type_can_downgrade_(layer.video_type_can_downgrade_),
-      protected_video_type_(layer.protected_video_type_),
-      ca_layer_(std::move(layer.ca_layer_)),
-      av_layer_(std::move(layer.av_layer_)),
-      update_indicator_layer_(std::move(layer.update_indicator_layer_)) {
-  DCHECK(!layer.ca_layer_);
-  DCHECK(!layer.av_layer_);
-  DCHECK(!update_indicator_layer_);
-}
-
 CARendererLayerTree::ContentLayer::~ContentLayer() {
   [ca_layer_ removeFromSuperlayer];
   [update_indicator_layer_ removeFromSuperlayer];
@@ -606,9 +619,9 @@
     }
   }
   if (needs_new_clip_and_sorting_layer) {
-    clip_and_sorting_layers_.push_back(ClipAndSortingLayer(
-        params.is_clipped, params.clip_rect, params.rounded_corner_bounds,
-        params.sorting_context_id, is_singleton_sorting_context));
+    clip_and_sorting_layers_.emplace_back(
+        this, params.is_clipped, params.clip_rect, params.rounded_corner_bounds,
+        params.sorting_context_id, is_singleton_sorting_context);
   }
   clip_and_sorting_layers_.back().AddContentLayer(tree, params);
   return true;
@@ -624,7 +637,7 @@
       needs_new_transform_layer = false;
   }
   if (needs_new_transform_layer)
-    transform_layers_.push_back(TransformLayer(params.transform));
+    transform_layers_.emplace_back(this, params.transform);
   transform_layers_.back().AddContentLayer(tree, params);
 }
 
@@ -649,19 +662,17 @@
     // cv_pixel_buffer = io_surface_image->cv_pixel_buffer();
     io_surface_color_space = params.image->color_space();
   }
-  content_layers_.push_back(ContentLayer(
-      tree, io_surface, cv_pixel_buffer, params.contents_rect, params.rect,
+  content_layers_.emplace_back(
+      this, io_surface, cv_pixel_buffer, params.contents_rect, params.rect,
       params.background_color, io_surface_color_space, params.edge_aa_mask,
-      params.opacity, params.filter, params.protected_video_type));
+      params.opacity, params.filter, params.protected_video_type);
 }
 
 void CARendererLayerTree::RootLayer::CommitToCA(CALayer* superlayer,
-                                                RootLayer* old_layer,
-                                                const gfx::Size& pixel_size,
-                                                float scale_factor) {
-  if (old_layer) {
-    DCHECK(old_layer->ca_layer_);
-    std::swap(ca_layer_, old_layer->ca_layer_);
+                                                const gfx::Size& pixel_size) {
+  if (old_layer_) {
+    DCHECK(old_layer_->ca_layer_);
+    std::swap(ca_layer_, old_layer_->ca_layer_);
   } else {
     ca_layer_.reset([[CALayer alloc] init]);
     [ca_layer_ setAnchorPoint:CGPointZero];
@@ -677,7 +688,7 @@
     // In fullscreen low power mode there exists a single video layer on a
     // solid black background.
     const gfx::RectF bg_rect(
-        ScaleSize(gfx::SizeF(pixel_size), 1 / scale_factor));
+        ScaleSize(gfx::SizeF(pixel_size), 1 / tree_->scale_factor_));
     if (gfx::RectF([ca_layer_ frame]) != bg_rect)
       [ca_layer_ setFrame:bg_rect.ToCGRect()];
     if (![ca_layer_ backgroundColor])
@@ -699,29 +710,22 @@
     DowngradeAVLayersToCALayers();
   }
 
-  for (size_t i = 0; i < clip_and_sorting_layers_.size(); ++i) {
-    ClipAndSortingLayer* old_clip_and_sorting_layer = nullptr;
-    if (old_layer && i < old_layer->clip_and_sorting_layers_.size()) {
-      old_clip_and_sorting_layer = &old_layer->clip_and_sorting_layers_[i];
-    }
-    clip_and_sorting_layers_[i].CommitToCA(
-        ca_layer_.get(), old_clip_and_sorting_layer, scale_factor);
-  }
+  for (auto& child_layer : clip_and_sorting_layers_)
+    child_layer.CommitToCA();
 }
 
-void CARendererLayerTree::ClipAndSortingLayer::CommitToCA(
-    CALayer* superlayer,
-    ClipAndSortingLayer* old_layer,
-    float scale_factor) {
+void CARendererLayerTree::ClipAndSortingLayer::CommitToCA() {
+  CALayer* superlayer = parent_layer_->ca_layer_.get();
   bool update_is_clipped = true;
   bool update_clip_rect = true;
-  if (old_layer) {
-    DCHECK(old_layer->clipping_ca_layer_);
-    DCHECK(old_layer->rounded_corner_ca_layer_);
-    std::swap(clipping_ca_layer_, old_layer->clipping_ca_layer_);
-    std::swap(rounded_corner_ca_layer_, old_layer->rounded_corner_ca_layer_);
-    update_is_clipped = old_layer->is_clipped_ != is_clipped_;
-    update_clip_rect = update_is_clipped || old_layer->clip_rect_ != clip_rect_;
+  if (old_layer_) {
+    DCHECK(old_layer_->clipping_ca_layer_);
+    DCHECK(old_layer_->rounded_corner_ca_layer_);
+    std::swap(clipping_ca_layer_, old_layer_->clipping_ca_layer_);
+    std::swap(rounded_corner_ca_layer_, old_layer_->rounded_corner_ca_layer_);
+    update_is_clipped = old_layer_->is_clipped_ != is_clipped_;
+    update_clip_rect =
+        update_is_clipped || old_layer_->clip_rect_ != clip_rect_;
   } else {
     clipping_ca_layer_.reset([[CALayer alloc] init]);
     [clipping_ca_layer_ setAnchorPoint:CGPointZero];
@@ -732,11 +736,11 @@
   }
 
   if (!rounded_corner_bounds_.IsEmpty()) {
-    if (!old_layer ||
-        old_layer->rounded_corner_bounds_ != rounded_corner_bounds_) {
+    if (!old_layer_ ||
+        old_layer_->rounded_corner_bounds_ != rounded_corner_bounds_) {
       gfx::RectF dip_rounded_corner_bounds =
           gfx::RectF(rounded_corner_bounds_.rect());
-      dip_rounded_corner_bounds.Scale(1 / scale_factor);
+      dip_rounded_corner_bounds.Scale(1 / tree()->scale_factor_);
 
       [rounded_corner_ca_layer_ setMasksToBounds:true];
 
@@ -753,7 +757,7 @@
 
       [rounded_corner_ca_layer_
           setCornerRadius:rounded_corner_bounds_.GetSimpleRadius() /
-                          scale_factor];
+                          tree()->scale_factor_];
     }
   } else {
     [rounded_corner_ca_layer_ setMasksToBounds:false];
@@ -772,7 +776,7 @@
   if (update_clip_rect) {
     if (is_clipped_) {
       gfx::RectF dip_clip_rect = gfx::RectF(clip_rect_);
-      dip_clip_rect.Scale(1 / scale_factor);
+      dip_clip_rect.Scale(1 / tree()->scale_factor_);
       [clipping_ca_layer_
           setPosition:CGPointMake(dip_clip_rect.x(), dip_clip_rect.y())];
       [clipping_ca_layer_ setBounds:CGRectMake(0, 0, dip_clip_rect.width(),
@@ -787,23 +791,17 @@
     }
   }
 
-  for (size_t i = 0; i < transform_layers_.size(); ++i) {
-    TransformLayer* old_transform_layer = nullptr;
-    if (old_layer && i < old_layer->transform_layers_.size())
-      old_transform_layer = &old_layer->transform_layers_[i];
-    transform_layers_[i].CommitToCA(rounded_corner_ca_layer_,
-                                    old_transform_layer, scale_factor);
-  }
+  for (auto& child_layer : transform_layers_)
+    child_layer.CommitToCA();
 }
 
-void CARendererLayerTree::TransformLayer::CommitToCA(CALayer* superlayer,
-                                                     TransformLayer* old_layer,
-                                                     float scale_factor) {
+void CARendererLayerTree::TransformLayer::CommitToCA() {
+  CALayer* superlayer = parent_layer_->rounded_corner_ca_layer_.get();
   bool update_transform = true;
-  if (old_layer) {
-    DCHECK(old_layer->ca_layer_);
-    std::swap(ca_layer_, old_layer->ca_layer_);
-    update_transform = old_layer->transform_ != transform_;
+  if (old_layer_) {
+    DCHECK(old_layer_->ca_layer_);
+    std::swap(ca_layer_, old_layer_->ca_layer_);
+    update_transform = old_layer_->transform_ != transform_;
   } else {
     ca_layer_.reset([[CATransformLayer alloc] init]);
     [superlayer addSublayer:ca_layer_];
@@ -813,8 +811,8 @@
   if (update_transform) {
     gfx::Transform pre_scale;
     gfx::Transform post_scale;
-    pre_scale.Scale(1 / scale_factor, 1 / scale_factor);
-    post_scale.Scale(scale_factor, scale_factor);
+    pre_scale.Scale(1 / tree()->scale_factor_, 1 / tree()->scale_factor_);
+    post_scale.Scale(tree()->scale_factor_, tree()->scale_factor_);
     gfx::Transform conjugated_transform = pre_scale * transform_ * post_scale;
 
     CATransform3D ca_transform =
@@ -822,18 +820,12 @@
     [ca_layer_ setTransform:ca_transform];
   }
 
-  for (size_t i = 0; i < content_layers_.size(); ++i) {
-    ContentLayer* old_content_layer = nullptr;
-    if (old_layer && i < old_layer->content_layers_.size())
-      old_content_layer = &old_layer->content_layers_[i];
-    content_layers_[i].CommitToCA(ca_layer_.get(), old_content_layer,
-                                  scale_factor);
-  }
+  for (auto& child_layer : content_layers_)
+    child_layer.CommitToCA();
 }
 
-void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
-                                                   ContentLayer* old_layer,
-                                                   float scale_factor) {
+void CARendererLayerTree::ContentLayer::CommitToCA() {
+  CALayer* superlayer = parent_layer_->ca_layer_.get();
   bool update_contents = true;
   bool update_contents_rect = true;
   bool update_rect = true;
@@ -841,19 +833,21 @@
   bool update_ca_edge_aa_mask = true;
   bool update_opacity = true;
   bool update_ca_filter = true;
-  if (old_layer && old_layer->type_ == type_) {
-    DCHECK(old_layer->ca_layer_);
-    std::swap(ca_layer_, old_layer->ca_layer_);
-    std::swap(av_layer_, old_layer->av_layer_);
-    update_contents = old_layer->io_surface_ != io_surface_ ||
-                      old_layer->cv_pixel_buffer_ != cv_pixel_buffer_ ||
-                      old_layer->solid_color_contents_ != solid_color_contents_;
-    update_contents_rect = old_layer->contents_rect_ != contents_rect_;
-    update_rect = old_layer->rect_ != rect_;
-    update_background_color = old_layer->background_color_ != background_color_;
-    update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask_ != ca_edge_aa_mask_;
-    update_opacity = old_layer->opacity_ != opacity_;
-    update_ca_filter = old_layer->ca_filter_ != ca_filter_;
+  if (old_layer_ && old_layer_->type_ == type_) {
+    DCHECK(old_layer_->ca_layer_);
+    std::swap(ca_layer_, old_layer_->ca_layer_);
+    std::swap(av_layer_, old_layer_->av_layer_);
+    update_contents =
+        old_layer_->io_surface_ != io_surface_ ||
+        old_layer_->cv_pixel_buffer_ != cv_pixel_buffer_ ||
+        old_layer_->solid_color_contents_ != solid_color_contents_;
+    update_contents_rect = old_layer_->contents_rect_ != contents_rect_;
+    update_rect = old_layer_->rect_ != rect_;
+    update_background_color =
+        old_layer_->background_color_ != background_color_;
+    update_ca_edge_aa_mask = old_layer_->ca_edge_aa_mask_ != ca_edge_aa_mask_;
+    update_opacity = old_layer_->opacity_ != opacity_;
+    update_ca_filter = old_layer_->ca_filter_ != ca_filter_;
   } else {
     switch (type_) {
       case CALayerType::kHDRCopier:
@@ -873,8 +867,8 @@
         ca_layer_.reset([[CALayer alloc] init]);
     }
     [ca_layer_ setAnchorPoint:CGPointZero];
-    if (old_layer && old_layer->ca_layer_)
-      [superlayer replaceSublayer:old_layer->ca_layer_ with:ca_layer_];
+    if (old_layer_ && old_layer_->ca_layer_)
+      [superlayer replaceSublayer:old_layer_->ca_layer_ with:ca_layer_];
     else
       [superlayer addSublayer:ca_layer_];
   }
@@ -924,7 +918,7 @@
           [ca_layer_ setContents:nil];
         }
         if ([ca_layer_ respondsToSelector:(@selector(setContentsScale:))])
-          [ca_layer_ setContentsScale:scale_factor];
+          [ca_layer_ setContentsScale:tree()->scale_factor_];
       }
       break;
   }
@@ -935,7 +929,7 @@
   }
   if (update_rect) {
     gfx::RectF dip_rect = gfx::RectF(rect_);
-    dip_rect.Scale(1 / scale_factor);
+    dip_rect.Scale(1 / tree()->scale_factor_);
     [ca_layer_ setPosition:CGPointMake(dip_rect.x(), dip_rect.y())];
     [ca_layer_ setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())];
   }
diff --git a/ui/accessibility/ax_node_position_fuzzer.cc b/ui/accessibility/ax_node_position_fuzzer.cc
index 07e88b8..847ba9f 100644
--- a/ui/accessibility/ax_node_position_fuzzer.cc
+++ b/ui/accessibility/ax_node_position_fuzzer.cc
@@ -104,7 +104,6 @@
               : 0;
       return ui::AXNodePosition::CreateTreePosition(
           tree_->GetAXTreeID(), anchor_id, child_index_or_text_offset);
-      break;
     case ui::AXPositionKind::TEXT_POSITION: {
       // Avoid division by zero in the case where the node has no text.
       child_index_or_text_offset =
@@ -114,7 +113,6 @@
       return ui::AXNodePosition::CreateTextPosition(
           tree_->GetAXTreeID(), anchor_id, child_index_or_text_offset,
           affinity);
-      break;
       case ui::AXPositionKind::NULL_POSITION:
         NOTREACHED();
         return ui::AXNodePosition::CreateNullPosition();
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index ee763bc..0683972 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -577,7 +577,7 @@
   ]
 }
 
-android_library("ui_javatests") {
+android_library("ui_unit_device_javatests") {
   testonly = true
 
   sources = [
diff --git a/ui/android/event_forwarder.cc b/ui/android/event_forwarder.cc
index 3c2bb248..ebdfd95 100644
--- a/ui/android/event_forwarder.cc
+++ b/ui/android/event_forwarder.cc
@@ -121,25 +121,23 @@
   view_->OnMouseEvent(event);
 }
 
-void EventForwarder::OnDragEvent(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jobj,
-    jint action,
-    jfloat x,
-    jfloat y,
-    jfloat screen_x,
-    jfloat screen_y,
-    const JavaParamRef<jobjectArray>& j_mimeTypes,
-    const JavaParamRef<jobject>& j_drag_data_android) {
+void EventForwarder::OnDragEvent(JNIEnv* env,
+                                 const JavaParamRef<jobject>& jobj,
+                                 jint action,
+                                 jfloat x,
+                                 jfloat y,
+                                 jfloat screen_x,
+                                 jfloat screen_y,
+                                 const JavaParamRef<jobjectArray>& j_mimeTypes,
+                                 const JavaParamRef<jstring>& j_content) {
   float dip_scale = view_->GetDipScale();
   gfx::PointF location(x / dip_scale, y / dip_scale);
   gfx::PointF root_location(screen_x / dip_scale, screen_y / dip_scale);
   std::vector<std::u16string> mime_types;
   AppendJavaStringArrayToStringVector(env, j_mimeTypes, &mime_types);
 
-  DropDataAndroid drop_data_android(env, j_drag_data_android);
   DragEventAndroid event(env, action, location, root_location, mime_types,
-                         drop_data_android);
+                         j_content.obj());
   view_->OnDragEvent(event);
 }
 
diff --git a/ui/android/event_forwarder.h b/ui/android/event_forwarder.h
index c474c559..c54def1a 100644
--- a/ui/android/event_forwarder.h
+++ b/ui/android/event_forwarder.h
@@ -70,16 +70,15 @@
                     jint android_meta_state,
                     jint tool_type);
 
-  void OnDragEvent(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& jobj,
-      jint action,
-      jfloat x,
-      jfloat y,
-      jfloat screen_x,
-      jfloat screen_y,
-      const base::android::JavaParamRef<jobjectArray>& j_mimeTypes,
-      const base::android::JavaParamRef<jobject>& j_drag_data_android);
+  void OnDragEvent(JNIEnv* env,
+                   const base::android::JavaParamRef<jobject>& jobj,
+                   jint action,
+                   jfloat x,
+                   jfloat y,
+                   jfloat screen_x,
+                   jfloat screen_y,
+                   const base::android::JavaParamRef<jobjectArray>& j_mimeTypes,
+                   const base::android::JavaParamRef<jstring>& j_content);
 
   jboolean OnGestureEvent(JNIEnv* env,
                           const base::android::JavaParamRef<jobject>& jobj,
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index a1767460..82c31d6 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -4,6 +4,8 @@
 
 package org.chromium.ui.base;
 
+import android.content.ClipData;
+import android.content.ClipDescription;
 import android.os.Build;
 import android.view.DragEvent;
 import android.view.InputDevice;
@@ -19,7 +21,6 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.base.compat.ApiHelperForQ;
-import org.chromium.ui.dragdrop.DropDataAndroid;
 
 /**
  * Class used to forward view, input events down to native.
@@ -324,15 +325,32 @@
             return false;
         }
 
-        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
-            return mIsDragDropEnabled
-                    && DropDataAndroid.isClipContentSupported(event.getClipDescription());
+        ClipDescription clipDescription = event.getClipDescription();
+
+        // text/* will match text/uri-list, text/html, text/plain.
+        String[] mimeTypes =
+                clipDescription == null ? new String[0] : clipDescription.filterMimeTypes("text/*");
+        // mimeTypes is null iff there is no matching text MIME type.
+        // Try if there is any matching image MIME type.
+        if (mimeTypes == null) {
+            mimeTypes = clipDescription.filterMimeTypes("image/*");
         }
 
-        DropDataAndroid dropDataAndroid = event.getAction() == DragEvent.ACTION_DROP
-                ? DropDataAndroid.createFromClipData(
-                        event.getClipData(), containerView.getContext())
-                : DropDataAndroid.emptyInstance();
+        if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
+            return mimeTypes != null && mimeTypes.length > 0 && mIsDragDropEnabled;
+        }
+
+        StringBuilder content = new StringBuilder("");
+        if (event.getAction() == DragEvent.ACTION_DROP) {
+            // TODO(hush): obtain dragdrop permissions, when dragging files into Chrome/WebView is
+            // supported. Not necessary to do so for now, because only text dragging is supported.
+            ClipData clipData = event.getClipData();
+            final int itemCount = clipData.getItemCount();
+            for (int i = 0; i < itemCount; i++) {
+                ClipData.Item item = clipData.getItemAt(i);
+                content.append(item.coerceToStyledText(containerView.getContext()));
+            }
+        }
 
         int[] locationOnScreen = new int[2];
         containerView.getLocationOnScreen(locationOnScreen);
@@ -347,7 +365,7 @@
 
         EventForwarderJni.get().onDragEvent(mNativeEventForwarder, EventForwarder.this,
                 event.getAction(), x / scale, y / scale, screenX / scale, screenY / scale,
-                dropDataAndroid.mimeTypes, dropDataAndroid);
+                mimeTypes, content.toString());
         return true;
     }
 
@@ -463,7 +481,7 @@
                 float x, float y, int pointerId, float pressure, float orientation, float tilt,
                 int changedButton, int buttonState, int metaState, int toolType);
         void onDragEvent(long nativeEventForwarder, EventForwarder caller, int action, float x,
-                float y, float screenX, float screenY, String[] mimeTypes, DropDataAndroid content);
+                float y, float screenX, float screenY, String[] mimeTypes, String content);
         boolean onGestureEvent(long nativeEventForwarder, EventForwarder caller, int type,
                 long timeMs, float delta);
         boolean onGenericMotionEvent(
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
index 1f02950..1b6e71f0 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DropDataAndroid.java
@@ -4,13 +4,8 @@
 
 package org.chromium.ui.dragdrop;
 
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.Context;
 import android.text.TextUtils;
-import android.view.DragEvent;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.annotations.CalledByNative;
@@ -28,37 +23,21 @@
     public final String imageContentExtension;
     public final String imageFilename;
 
-    /** MIME types that used to pass from Android into natives. */
-    public final @Nullable String[] mimeTypes;
-
-    /** Empty instance that used for placeholder */
-    private static DropDataAndroid sEmptyInstance;
-
+    /** Not generated from java */
     private DropDataAndroid(String text, GURL gurl, byte[] imageContent,
-            String imageContentExtension, String imageFilename, @Nullable String[] mimeTypes) {
+            String imageContentExtension, String imageFilename) {
         this.text = text;
         this.gurl = gurl;
         this.imageContent = imageContent;
         this.imageContentExtension = imageContentExtension;
         this.imageFilename = imageFilename;
-
-        this.mimeTypes = mimeTypes;
-    }
-
-    /** Get an empty instance of {@link DropDataAndroid} that is used as placeholder. */
-    public static DropDataAndroid emptyInstance() {
-        if (sEmptyInstance == null) {
-            sEmptyInstance = new DropDataAndroid("", null, null, "", "", new String[0]);
-        }
-        return sEmptyInstance;
     }
 
     @VisibleForTesting
     @CalledByNative
     static DropDataAndroid create(String text, GURL gurl, byte[] imageContent,
             String imageContentExtension, String imageFilename) {
-        return new DropDataAndroid(
-                text, gurl, imageContent, imageContentExtension, imageFilename, null);
+        return new DropDataAndroid(text, gurl, imageContent, imageContentExtension, imageFilename);
     }
 
     /** Return whether this data presents a plain of text. */
@@ -76,64 +55,4 @@
         return imageContent != null && !TextUtils.isEmpty(imageContentExtension)
                 && !TextUtils.isEmpty(imageFilename);
     }
-
-    /**
-     * Create a DropDataAndroid from clip data from Android.
-     * @param clipData {@link DragEvent#getClipData()}
-     * @param context The caller's Context, from which its ContentResolver and other things can be
-     *         retrieved.
-     * @return A DropDataAndroid presentation of given clipData.
-     */
-    public static DropDataAndroid createFromClipData(ClipData clipData, Context context) {
-        ClipDescription clipDescription = clipData.getDescription();
-        if (clipDescription == null) {
-            return emptyInstance();
-        }
-
-        // Attempt to match text.
-        String[] mimeTypes = clipDescription.filterMimeTypes("text/*");
-
-        if (mimeTypes == null) {
-            // Attempt to match images.
-            // TODO(https://crbug.com/1261249): parse the right data if mimetypes matched for
-            // images.
-            mimeTypes = clipDescription.filterMimeTypes("image/*");
-        }
-
-        if (mimeTypes == null) {
-            return emptyInstance();
-        }
-
-        StringBuilder content = new StringBuilder("");
-        final int itemCount = clipData.getItemCount();
-        for (int i = 0; i < itemCount; i++) {
-            ClipData.Item item = clipData.getItemAt(i);
-            content.append(item.coerceToStyledText(context));
-        }
-        return new DropDataAndroid(content.toString(), null, null, "", "", mimeTypes);
-    }
-
-    /**
-     * @param clipDescription See {@link DragEvent#getClipDescription()}
-     * @return Whether the {@link ClipData} presented by the {@link ClipDescription} is supported.
-     */
-    public static boolean isClipContentSupported(ClipDescription clipDescription) {
-        // text/* will match text/uri-list, text/html, text/plain.
-        String[] mimeTypes =
-                clipDescription == null ? new String[0] : clipDescription.filterMimeTypes("text/*");
-        // mimeTypes is null iff there is no matching text MIME type.
-        // Try if there is any matching image MIME type.
-        if (mimeTypes == null) {
-            mimeTypes = clipDescription.filterMimeTypes("image/*");
-        }
-
-        return mimeTypes != null && mimeTypes.length > 0;
-    }
-
-    // Native getters
-
-    @CalledByNative
-    private String getText() {
-        return text;
-    }
 }
diff --git a/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java b/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
index 9769006..374d2d3 100644
--- a/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
+++ b/ui/android/javatests/src/org/chromium/ui/base/ClipboardAndroidTest.java
@@ -33,6 +33,10 @@
 
 /**
  * Clipboard tests for Android platform that depend on access to the ClipboardManager.
+ *
+ * This test suite can fail on Android 10+ if the activity does not maintain focus during testing.
+ * For more information see: https://crbug.com/1297678 and
+ * https://developer.android.com/about/versions/10/privacy/changes#clipboard-data
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 @Batch(Batch.UNIT_TESTS)
@@ -50,6 +54,14 @@
     @Override
     public void tearDownTest() throws Exception {
         ClipboardAndroidTestSupport.cleanup();
+
+        // Clear the clipboard to avoid leaving any state.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            ClipboardManager clipboardManager =
+                    (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
+            ClipData clipData = ClipData.newPlainText("", "");
+            clipboardManager.setPrimaryClip(clipData);
+        });
         super.tearDownTest();
     }
 
@@ -90,7 +102,7 @@
             clipboardManager.setPrimaryClip(ClipData.newPlainText(null, invalidatingText));
         });
 
-        helper.waitForFirst("ClipboardManager did not notify of PrimaryClip change.");
+        helper.waitForCallback("ClipboardManager did not notify of PrimaryClip change.", 0);
 
         // Assert that the overwrite from another application is registered by the native clipboard.
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/ui/android/junit/src/org/chromium/ui/dragdrop/DropDataAndroidUnitTest.java b/ui/android/junit/src/org/chromium/ui/dragdrop/DropDataAndroidUnitTest.java
index 5073ec2f..f0b101f 100644
--- a/ui/android/junit/src/org/chromium/ui/dragdrop/DropDataAndroidUnitTest.java
+++ b/ui/android/junit/src/org/chromium/ui/dragdrop/DropDataAndroidUnitTest.java
@@ -4,15 +4,10 @@
 
 package org.chromium.ui.dragdrop;
 
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.Context;
-
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import org.chromium.url.GURL;
 import org.chromium.url.JUnitTestGURLs;
@@ -71,40 +66,6 @@
         Assert.assertEquals("Image filename does not match.", IMAGE_FILENAME, data.imageFilename);
     }
 
-    @Test
-    public void testClipSupported() {
-        ClipDescription descriptionText = new ClipDescription("text", new String[] {"text/plain"});
-        ClipDescription descriptionImage =
-                new ClipDescription("image", new String[] {"image/webp"});
-        ClipDescription descriptionVideo = new ClipDescription("video", new String[] {"video/mp4"});
-        ClipDescription descriptionApplication =
-                new ClipDescription("intent", new String[] {"application/octet-stream"});
-
-        Assert.assertTrue("Text dragging is supported.",
-                DropDataAndroid.isClipContentSupported(descriptionText));
-        Assert.assertTrue("Image dragging is supported.",
-                DropDataAndroid.isClipContentSupported(descriptionImage));
-
-        Assert.assertFalse("Video dragging is not supported.",
-                DropDataAndroid.isClipContentSupported(descriptionVideo));
-        Assert.assertFalse("Application dragging is not supported.",
-                DropDataAndroid.isClipContentSupported(descriptionApplication));
-    }
-
-    // TODO(https://crbug.com/1261249): Add more test case for link / image once dropping these are
-    // supported.
-    @Test
-    public void testCreateFromClipData_Text() {
-        String text = "text";
-
-        Context appContext = RuntimeEnvironment.getApplication().getApplicationContext();
-        ClipData textClip = ClipData.newPlainText("label", text);
-        DropDataAndroid dropData = DropDataAndroid.createFromClipData(textClip, appContext);
-
-        assertDragData(dropData, /*isPlainText=*/true, /*hasLink=*/false, /*hasImage=*/false);
-        Assert.assertEquals("DropData Text is different.", text, dropData.text);
-    }
-
     private void assertDragData(
             DropDataAndroid data, boolean isPlainText, boolean hasLink, boolean hasImage) {
         Assert.assertEquals("#isPlainText check failed.", isPlainText, data.isPlainText());
diff --git a/ui/base/x/x11_gl_egl_utility.cc b/ui/base/x/x11_gl_egl_utility.cc
index e625e27..2aca7171 100644
--- a/ui/base/x/x11_gl_egl_utility.cc
+++ b/ui/base/x/x11_gl_egl_utility.cc
@@ -59,7 +59,7 @@
                                             EGLint* buffer_size) {
   // If we're using ANGLE_NULL, we may not have a display, in which case we
   // can't use XVisualManager.
-  if (gl::GLSurfaceEGL::GetGLDisplayEGL()->GetNativeDisplay() !=
+  if (gl::GLSurfaceEGL::GetGLDisplayEGL()->GetNativeDisplay().GetDisplay() !=
       EGL_DEFAULT_DISPLAY) {
     uint8_t depth;
     XVisualManager::GetInstance()->ChooseVisualForWindow(true, nullptr, &depth,
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index dd2cf87..af02344 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -342,7 +342,6 @@
   if (is_android) {
     public += [
       "android/drag_event_android.h",
-      "android/drop_data_android.h",
       "android/event_handler_android.h",
       "android/gesture_event_android.h",
       "android/gesture_event_type.h",
@@ -352,7 +351,6 @@
     ]
     sources += [
       "android/drag_event_android.cc",
-      "android/drop_data_android.cc",
       "android/event_handler_android.cc",
       "android/gesture_event_android.cc",
       "android/key_event_android.cc",
@@ -362,9 +360,6 @@
     deps += [
       ":keyevent_jni_headers",
       ":motionevent_jni_headers",
-      "//ui/android:ui_android_jni_headers",
-      "//url:gurl_android",
-      "//url:url",
     ]
   }
 
diff --git a/ui/events/android/DEPS b/ui/events/android/DEPS
index e19883a5..eaf343a6 100644
--- a/ui/events/android/DEPS
+++ b/ui/events/android/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
-  "+ui/android/ui_android_jni_headers",
   "+ui/events/motionevent_jni_headers",
 ]
diff --git a/ui/events/android/drag_event_android.cc b/ui/events/android/drag_event_android.cc
index cc319b97..13af78c 100644
--- a/ui/events/android/drag_event_android.cc
+++ b/ui/events/android/drag_event_android.cc
@@ -19,15 +19,20 @@
     const gfx::PointF& location,
     const gfx::PointF& screen_location,
     const std::vector<std::u16string>& mime_types,
-    DropDataAndroid drop_data_android)
+    jstring content)
     : action_(action),
       location_(location),
       screen_location_(screen_location),
-      mime_types_(mime_types),
-      drop_data_android_(drop_data_android) {}
+      mime_types_(mime_types) {
+  content_.Reset(env, content);
+}
 
 DragEventAndroid::~DragEventAndroid() {}
 
+ScopedJavaLocalRef<jstring> DragEventAndroid::GetJavaContent() const {
+  return ScopedJavaLocalRef<jstring>(content_);
+}
+
 std::unique_ptr<DragEventAndroid> DragEventAndroid::CreateFor(
     const gfx::PointF& new_location) const {
   gfx::PointF new_screen_location =
@@ -35,7 +40,7 @@
   JNIEnv* env = AttachCurrentThread();
   return std::make_unique<DragEventAndroid>(env, action_, new_location,
                                             new_screen_location, mime_types_,
-                                            drop_data_android_);
+                                            content_.obj());
 }
 
 }  // namespace ui
diff --git a/ui/events/android/drag_event_android.h b/ui/events/android/drag_event_android.h
index 2b37a15..adbf175 100644
--- a/ui/events/android/drag_event_android.h
+++ b/ui/events/android/drag_event_android.h
@@ -9,9 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
-#include "ui/events/android/drop_data_android.h"
 #include "ui/events/events_export.h"
 #include "ui/gfx/geometry/point_conversions.h"
 
@@ -23,8 +21,6 @@
 
 // Event class used to carry the info from Java DragEvent through native.
 // All coordinates are in DIPs.
-// Note that the |drop_data_android| will only be populated when the drop event
-// represents an ACTION_DROP. Otherwise it will be empty.
 class EVENTS_EXPORT DragEventAndroid {
  public:
   DragEventAndroid(JNIEnv* env,
@@ -32,7 +28,7 @@
                    const gfx::PointF& location,
                    const gfx::PointF& screen_location,
                    const std::vector<std::u16string>& mime_types,
-                   DropDataAndroid drop_data_android);
+                   jstring content);
 
   DragEventAndroid(const DragEventAndroid&) = delete;
   DragEventAndroid& operator=(const DragEventAndroid&) = delete;
@@ -44,7 +40,7 @@
   const gfx::PointF& screen_location() const { return screen_location_; }
   const std::vector<std::u16string>& mime_types() const { return mime_types_; }
 
-  DropDataAndroid drop_data_android() const { return drop_data_android_; }
+  base::android::ScopedJavaLocalRef<jstring> GetJavaContent() const;
 
   // Creates a new DragEventAndroid instance different from |this| only by
   // its location.
@@ -59,7 +55,7 @@
   gfx::PointF screen_location_;
   const std::vector<std::u16string>& mime_types_;
   // The Java reference to the drop content to avoid unnecessary copying.
-  DropDataAndroid drop_data_android_;
+  base::android::ScopedJavaGlobalRef<jstring> content_;
 };
 
 }  // namespace ui
diff --git a/ui/events/android/drop_data_android.cc b/ui/events/android/drop_data_android.cc
deleted file mode 100644
index 277e2ac..0000000
--- a/ui/events/android/drop_data_android.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/android/drop_data_android.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
-#include "base/android/jni_string.h"
-#include "url/android/gurl_android.h"
-#include "url/gurl.h"
-
-#include "ui/android/ui_android_jni_headers/DropDataAndroid_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertJavaStringToUTF16;
-using base::android::ConvertUTF16ToJavaString;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::ScopedJavaLocalRef;
-using base::android::ToJavaByteArray;
-
-namespace ui {
-
-DropDataAndroid::DropDataAndroid(
-    JNIEnv* env,
-    const base::android::JavaRef<jobject>& drop_data_android)
-    : env_(env) {
-  java_ref_ = JavaObjectWeakGlobalRef(env, drop_data_android);
-}
-
-DropDataAndroid::~DropDataAndroid() {
-  java_ref_.reset();
-}
-
-std::u16string DropDataAndroid::text() const {
-  return ConvertJavaStringToUTF16(
-      Java_DropDataAndroid_getText(env_, java_ref_.get(env_)));
-}
-
-base::android::ScopedJavaLocalRef<jobject> DropDataAndroid::GetJavaObject()
-    const {
-  return java_ref_.get(env_);
-}
-
-DropDataAndroid DropDataAndroid::Create(const std::u16string& text,
-                                        const GURL& url,
-                                        const std::string& file_content,
-                                        const std::string& image_extension,
-                                        const std::u16string& image_filename) {
-  JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
-  ScopedJavaLocalRef<jobject> jgurl =
-      url::GURLAndroid::FromNativeGURL(env, url);
-  ScopedJavaLocalRef<jbyteArray> jimage_bytes =
-      ToJavaByteArray(env, file_content);
-  ScopedJavaLocalRef<jstring> jimage_extension =
-      ConvertUTF8ToJavaString(env, image_extension);
-  ScopedJavaLocalRef<jstring> jimage_filename =
-      ConvertUTF16ToJavaString(env, image_filename);
-
-  ScopedJavaLocalRef<jobject> jobj = Java_DropDataAndroid_create(
-      env, jtext, jgurl, jimage_bytes, jimage_extension, jimage_filename);
-
-  return DropDataAndroid(env, jobj);
-}
-
-}  // namespace ui
diff --git a/ui/events/android/drop_data_android.h b/ui/events/android/drop_data_android.h
deleted file mode 100644
index 83ad9c0..0000000
--- a/ui/events/android/drop_data_android.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_ANDROID_DROP_DATA_ANDROID_H_
-#define UI_EVENTS_ANDROID_DROP_DATA_ANDROID_H_
-
-#include <jni.h>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_weak_ref.h"
-#include "ui/events/events_export.h"
-#include "url/gurl.h"
-
-namespace ui {
-
-// Generate a Java equivalent DropData object from |drop_data| and used to
-// communicate drop data with Java UI. This object can either created from
-// native, or from Android UI. In either case, this class will always associate
-// to a java object.
-class EVENTS_EXPORT DropDataAndroid {
- public:
-  DropDataAndroid(JNIEnv* env,
-                  const base::android::JavaRef<jobject>& drop_data_android);
-
-  ~DropDataAndroid();
-
-  // Create a new instance of |DropDataAndroid| and its java equivalent.
-  static DropDataAndroid Create(const std::u16string& text,
-                                const GURL& url,
-                                const std::string& file_content,
-                                const std::string& image_extension,
-                                const std::u16string& image_filename);
-
-  // Get the java equivalent instance of this |DropDataAndroid|.
-  base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const;
-
-  std::u16string text() const;
-
- private:
-  JNIEnv* env_;
-  JavaObjectWeakGlobalRef java_ref_;
-};
-
-}  // namespace ui
-#endif  // UI_EVENTS_ANDROID_DROP_DATA_ANDROID_H_
diff --git a/ui/gl/egl_api_unittest.cc b/ui/gl/egl_api_unittest.cc
index 96dffc4..4a7596a 100644
--- a/ui/gl/egl_api_unittest.cc
+++ b/ui/gl/egl_api_unittest.cc
@@ -8,6 +8,7 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_display.h"
+#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_egl_api_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/gl_switches.h"
@@ -52,12 +53,11 @@
     if (disabled_extensions) {
       SetDisabledExtensionsEGL(disabled_extensions);
     }
-    if (display_) {
-      // Clear the display so InitializeDisplay() will re-initialize it.
-      display_->SetDisplay(EGL_NO_DISPLAY);
-    }
-    display_ = GLSurfaceEGL::InitializeDisplay(
-        EGLDisplayPlatform(EGL_DEFAULT_DISPLAY), /*system_device_id=*/0);
+    display_ =
+        GLDisplayManagerEGL::GetInstance()->GetDisplay(GpuPreference::kDefault);
+    // Clear the display so InitializeDisplay() will re-initialize it.
+    display_->SetDisplay(EGL_NO_DISPLAY);
+    display_->InitializeDisplay(EGLDisplayPlatform(EGL_DEFAULT_DISPLAY));
   }
 
   void SetFakeExtensionString(const char* fake_string,
diff --git a/ui/gl/gl_angle_util_vulkan.cc b/ui/gl/gl_angle_util_vulkan.cc
index 847e477..03a1dfc6 100644
--- a/ui/gl/gl_angle_util_vulkan.cc
+++ b/ui/gl/gl_angle_util_vulkan.cc
@@ -12,8 +12,7 @@
 namespace gl {
 namespace {
 EGLDeviceEXT GetEGLDeviceFromANGLE() {
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   if (egl_display == EGL_NO_DISPLAY) {
     LOG(ERROR) << "Failed to retrieve EGLDisplay";
     return nullptr;
diff --git a/ui/gl/gl_angle_util_win.cc b/ui/gl/gl_angle_util_win.cc
index 69f460e..c6d79526 100644
--- a/ui/gl/gl_angle_util_win.cc
+++ b/ui/gl/gl_angle_util_win.cc
@@ -17,8 +17,7 @@
 void* QueryDeviceObjectFromANGLE(int object_type) {
   TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE");
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   if (egl_display == EGL_NO_DISPLAY) {
     DVLOG(1) << "Failed to retrieve EGLDisplay";
     return nullptr;
diff --git a/ui/gl/gl_bindings.cc b/ui/gl/gl_bindings.cc
index 14d2e6d..8092fa1 100644
--- a/ui/gl/gl_bindings.cc
+++ b/ui/gl/gl_bindings.cc
@@ -45,7 +45,7 @@
 // static
 std::string DisplayExtensionsEGL::GetPlatformExtensions(GLDisplayEGL* display) {
   DCHECK(display);
-  EGLDisplay egl_display = display->GetHardwareDisplay();
+  EGLDisplay egl_display = display->GetDisplay();
   if (egl_display == EGL_NO_DISPLAY)
     return "";
   const char* str = eglQueryString(egl_display, EGL_EXTENSIONS);
diff --git a/ui/gl/gl_display.cc b/ui/gl/gl_display.cc
index 92dfb472..e3a2466 100644
--- a/ui/gl/gl_display.cc
+++ b/ui/gl/gl_display.cc
@@ -4,17 +4,662 @@
 
 #include "ui/gl/gl_display.h"
 
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/containers/contains.h"
+#include "base/debug/crash_logging.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/system/sys_info.h"
+#include "build/build_config.h"
+#include "ui/gl/angle_platform_impl.h"
+#include "ui/gl/egl_util.h"
 #include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_display_egl_util.h"
+#include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
 
 #if defined(USE_GLX)
 #include "ui/gl/glx_util.h"
 #endif  // defined(USE_GLX)
 
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#endif  // defined(USE_OZONE)
+
+#if BUILDFLAG(IS_ANDROID)
+#include <android/native_window_jni.h>
+#include "base/android/build_info.h"
+#endif
+
+// From ANGLE's egl/eglext.h.
+
+#ifndef EGL_ANGLE_platform_angle
+#define EGL_ANGLE_platform_angle 1
+#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205
+#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE 0x348E
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x345E
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE 0x3487
+#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348F
+#endif /* EGL_ANGLE_platform_angle */
+
+#ifndef EGL_ANGLE_platform_angle_d3d
+#define EGL_ANGLE_platform_angle_d3d 1
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE 0x320B
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE 0x320C
+#endif /* EGL_ANGLE_platform_angle_d3d */
+
+#ifndef EGL_ANGLE_platform_angle_d3d_luid
+#define EGL_ANGLE_platform_angle_d3d_luid 1
+#define EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE 0x34A0
+#define EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE 0x34A1
+#endif /* EGL_ANGLE_platform_angle_d3d_luid */
+
+#ifndef EGL_ANGLE_platform_angle_d3d11on12
+#define EGL_ANGLE_platform_angle_d3d11on12 1
+#define EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE 0x3488
+#endif /* EGL_ANGLE_platform_angle_d3d11on12 */
+
+#ifndef EGL_ANGLE_platform_angle_opengl
+#define EGL_ANGLE_platform_angle_opengl 1
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
+#endif /* EGL_ANGLE_platform_angle_opengl */
+
+#ifndef EGL_ANGLE_platform_angle_null
+#define EGL_ANGLE_platform_angle_null 1
+#define EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE 0x33AE
+#endif /* EGL_ANGLE_platform_angle_null */
+
+#ifndef EGL_ANGLE_platform_angle_vulkan
+#define EGL_ANGLE_platform_angle_vulkan 1
+#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
+#define EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE 0x34A5
+#endif /* EGL_ANGLE_platform_angle_vulkan */
+
+#ifndef EGL_ANGLE_platform_angle_metal
+#define EGL_ANGLE_platform_angle_metal 1
+#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
+#endif /* EGL_ANGLE_platform_angle_metal */
+
+#ifndef EGL_ANGLE_x11_visual
+#define EGL_ANGLE_x11_visual 1
+#define EGL_X11_VISUAL_ID_ANGLE 0x33A3
+#endif /* EGL_ANGLE_x11_visual */
+
+#ifndef EGL_ANGLE_direct_composition
+#define EGL_ANGLE_direct_composition 1
+#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5
+#endif /* EGL_ANGLE_direct_composition */
+
+#ifndef EGL_ANGLE_display_robust_resource_initialization
+#define EGL_ANGLE_display_robust_resource_initialization 1
+#define EGL_DISPLAY_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453
+#endif /* EGL_ANGLE_display_robust_resource_initialization */
+
+#ifndef EGL_ANGLE_display_power_preference
+#define EGL_ANGLE_display_power_preference 1
+#define EGL_POWER_PREFERENCE_ANGLE 0x3482
+#define EGL_LOW_POWER_ANGLE 0x0001
+#define EGL_HIGH_POWER_ANGLE 0x0002
+#endif /* EGL_ANGLE_power_preference */
+
+#ifndef EGL_ANGLE_platform_angle_device_id
+#define EGL_ANGLE_platform_angle_device_id
+#define EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE 0x34D6
+#define EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE 0x34D7
+#endif /* EGL_ANGLE_platform_angle_device_id */
+
+// From ANGLE's egl/eglext.h.
+#ifndef EGL_ANGLE_feature_control
+#define EGL_ANGLE_feature_control 1
+#define EGL_FEATURE_NAME_ANGLE 0x3460
+#define EGL_FEATURE_CATEGORY_ANGLE 0x3461
+#define EGL_FEATURE_DESCRIPTION_ANGLE 0x3462
+#define EGL_FEATURE_BUG_ANGLE 0x3463
+#define EGL_FEATURE_STATUS_ANGLE 0x3464
+#define EGL_FEATURE_COUNT_ANGLE 0x3465
+#define EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
+#define EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
+#define EGL_FEATURE_ALL_DISABLED_ANGLE 0x3469
+#endif /* EGL_ANGLE_feature_control */
+
+using ui::GetLastEGLErrorString;
+
 namespace gl {
 
+namespace {
+
+std::vector<const char*> GetAttribArrayFromStringVector(
+    const std::vector<std::string>& strings) {
+  std::vector<const char*> attribs;
+  for (const std::string& item : strings) {
+    attribs.push_back(item.c_str());
+  }
+  attribs.push_back(nullptr);
+  return attribs;
+}
+
+std::vector<std::string> GetStringVectorFromCommandLine(
+    const base::CommandLine* command_line,
+    const char switch_name[]) {
+  std::string command_string = command_line->GetSwitchValueASCII(switch_name);
+  return base::SplitString(command_string, ", ;", base::TRIM_WHITESPACE,
+                           base::SPLIT_WANT_NONEMPTY);
+}
+
+EGLDisplay GetPlatformANGLEDisplay(
+    EGLNativeDisplayType display,
+    EGLenum platform_type,
+    const std::vector<std::string>& enabled_features,
+    const std::vector<std::string>& disabled_features,
+    const std::vector<EGLAttrib>& extra_display_attribs) {
+  std::vector<EGLAttrib> display_attribs(extra_display_attribs);
+
+  display_attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+  display_attribs.push_back(static_cast<EGLAttrib>(platform_type));
+
+  if (platform_type == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) {
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    if (command_line->HasSwitch(switches::kUseAdapterLuid)) {
+      // If the LUID is specified, the format is <high part>,<low part>. Split
+      // and add them to the EGL_ANGLE_platform_angle_d3d_luid ext attributes.
+      std::string luid =
+          command_line->GetSwitchValueASCII(switches::kUseAdapterLuid);
+      size_t comma = luid.find(',');
+      if (comma != std::string::npos) {
+        int32_t high;
+        uint32_t low;
+        if (!base::StringToInt(luid.substr(0, comma), &high) ||
+            !base::StringToUint(luid.substr(comma + 1), &low))
+          return EGL_NO_DISPLAY;
+
+        display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE);
+        display_attribs.push_back(high);
+
+        display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE);
+        display_attribs.push_back(low);
+      }
+    }
+  }
+
+  GLDisplayEglUtil::GetInstance()->GetPlatformExtraDisplayAttribs(
+      platform_type, &display_attribs);
+
+  std::vector<const char*> enabled_features_attribs =
+      GetAttribArrayFromStringVector(enabled_features);
+  std::vector<const char*> disabled_features_attribs =
+      GetAttribArrayFromStringVector(disabled_features);
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) {
+    if (!enabled_features_attribs.empty()) {
+      display_attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
+      display_attribs.push_back(
+          reinterpret_cast<EGLAttrib>(enabled_features_attribs.data()));
+    }
+    if (!disabled_features_attribs.empty()) {
+      display_attribs.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
+      display_attribs.push_back(
+          reinterpret_cast<EGLAttrib>(disabled_features_attribs.data()));
+    }
+  }
+  // TODO(dbehr) Add an attrib to Angle to pass EGL platform.
+
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_display_power_preference) {
+    GpuPreference pref =
+        GLSurface::AdjustGpuPreference(GpuPreference::kDefault);
+    switch (pref) {
+      case GpuPreference::kDefault:
+        // Don't request any GPU, let ANGLE and the native driver decide.
+        break;
+      case GpuPreference::kLowPower:
+        display_attribs.push_back(EGL_POWER_PREFERENCE_ANGLE);
+        display_attribs.push_back(EGL_LOW_POWER_ANGLE);
+        break;
+      case GpuPreference::kHighPerformance:
+        display_attribs.push_back(EGL_POWER_PREFERENCE_ANGLE);
+        display_attribs.push_back(EGL_HIGH_POWER_ANGLE);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  display_attribs.push_back(EGL_NONE);
+
+  // This is an EGL 1.5 function that we know ANGLE supports. It's used to pass
+  // EGLAttribs (pointers) instead of EGLints into the display
+  return eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
+                               reinterpret_cast<void*>(display),
+                               &display_attribs[0]);
+}
+
+EGLDisplay GetDisplayFromType(
+    DisplayType display_type,
+    EGLDisplayPlatform native_display,
+    const std::vector<std::string>& enabled_angle_features,
+    const std::vector<std::string>& disabled_angle_features,
+    bool disable_all_angle_features,
+    uint64_t system_device_id) {
+  std::vector<EGLAttrib> extra_display_attribs;
+  if (disable_all_angle_features) {
+    extra_display_attribs.push_back(EGL_FEATURE_ALL_DISABLED_ANGLE);
+    extra_display_attribs.push_back(EGL_TRUE);
+  }
+  if (system_device_id != 0 &&
+      g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_device_id) {
+    uint32_t low_part = system_device_id & 0xffffffff;
+    extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE);
+    extra_display_attribs.push_back(low_part);
+
+    uint32_t high_part = (system_device_id >> 32) & 0xffffffff;
+    extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE);
+    extra_display_attribs.push_back(high_part);
+  }
+  EGLNativeDisplayType display = native_display.GetDisplay();
+  switch (display_type) {
+    case DEFAULT:
+    case SWIFT_SHADER: {
+      if (native_display.GetPlatform() != 0) {
+        return eglGetPlatformDisplay(native_display.GetPlatform(),
+                                     reinterpret_cast<void*>(display), nullptr);
+      }
+      return eglGetDisplay(display);
+    }
+    case ANGLE_D3D9:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_D3D11:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_D3D11_NULL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_OPENGL:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_OPENGL_EGL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_OPENGL_NULL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_OPENGLES:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
+          enabled_angle_features, disabled_angle_features,
+          extra_display_attribs);
+    case ANGLE_OPENGLES_EGL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
+          enabled_angle_features, disabled_angle_features,
+          extra_display_attribs);
+    case ANGLE_OPENGLES_NULL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
+          enabled_angle_features, disabled_angle_features,
+          extra_display_attribs);
+    case ANGLE_NULL:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_VULKAN:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_VULKAN_NULL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_D3D11on12:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE);
+      extra_display_attribs.push_back(EGL_TRUE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_SWIFTSHADER:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE);
+#if defined(USE_OZONE)
+#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11)
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE);
+#endif  // BUILDFLAG(OZONE_PLATFORM_X11)
+#endif  // defined(USE_OZONE)
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_METAL:
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    case ANGLE_METAL_NULL:
+      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+      extra_display_attribs.push_back(
+          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
+      return GetPlatformANGLEDisplay(
+          display, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, enabled_angle_features,
+          disabled_angle_features, extra_display_attribs);
+    default:
+      NOTREACHED();
+      return EGL_NO_DISPLAY;
+  }
+}
+
+ANGLEImplementation GetANGLEImplementationFromDisplayType(
+    DisplayType display_type) {
+  switch (display_type) {
+    case ANGLE_D3D9:
+      return ANGLEImplementation::kD3D9;
+    case ANGLE_D3D11:
+    case ANGLE_D3D11_NULL:
+    case ANGLE_D3D11on12:
+      return ANGLEImplementation::kD3D11;
+    case ANGLE_OPENGL:
+    case ANGLE_OPENGL_NULL:
+      return ANGLEImplementation::kOpenGL;
+    case ANGLE_OPENGLES:
+    case ANGLE_OPENGLES_NULL:
+      return ANGLEImplementation::kOpenGLES;
+    case ANGLE_NULL:
+      return ANGLEImplementation::kNull;
+    case ANGLE_VULKAN:
+    case ANGLE_VULKAN_NULL:
+      return ANGLEImplementation::kVulkan;
+    case ANGLE_SWIFTSHADER:
+      return ANGLEImplementation::kSwiftShader;
+    case ANGLE_METAL:
+    case ANGLE_METAL_NULL:
+      return ANGLEImplementation::kMetal;
+    default:
+      return ANGLEImplementation::kNone;
+  }
+}
+
+const char* DisplayTypeString(DisplayType display_type) {
+  switch (display_type) {
+    case DEFAULT:
+      return "Default";
+    case SWIFT_SHADER:
+      return "SwiftShader";
+    case ANGLE_D3D9:
+      return "D3D9";
+    case ANGLE_D3D11:
+      return "D3D11";
+    case ANGLE_D3D11_NULL:
+      return "D3D11Null";
+    case ANGLE_OPENGL:
+      return "OpenGL";
+    case ANGLE_OPENGL_NULL:
+      return "OpenGLNull";
+    case ANGLE_OPENGLES:
+      return "OpenGLES";
+    case ANGLE_OPENGLES_NULL:
+      return "OpenGLESNull";
+    case ANGLE_NULL:
+      return "Null";
+    case ANGLE_VULKAN:
+      return "Vulkan";
+    case ANGLE_VULKAN_NULL:
+      return "VulkanNull";
+    case ANGLE_D3D11on12:
+      return "D3D11on12";
+    case ANGLE_SWIFTSHADER:
+      return "SwANGLE";
+    case ANGLE_OPENGL_EGL:
+      return "OpenGLEGL";
+    case ANGLE_OPENGLES_EGL:
+      return "OpenGLESEGL";
+    case ANGLE_METAL:
+      return "Metal";
+    case ANGLE_METAL_NULL:
+      return "MetalNull";
+    default:
+      NOTREACHED();
+      return "Err";
+  }
+}
+
+void AddInitDisplay(std::vector<DisplayType>* init_displays,
+                    DisplayType display_type) {
+  // Make sure to not add the same display type twice.
+  if (!base::Contains(*init_displays, display_type))
+    init_displays->push_back(display_type);
+}
+
+const char* GetDebugMessageTypeString(EGLint source) {
+  switch (source) {
+    case EGL_DEBUG_MSG_CRITICAL_KHR:
+      return "Critical";
+    case EGL_DEBUG_MSG_ERROR_KHR:
+      return "Error";
+    case EGL_DEBUG_MSG_WARN_KHR:
+      return "Warning";
+    case EGL_DEBUG_MSG_INFO_KHR:
+      return "Info";
+    default:
+      return "UNKNOWN";
+  }
+}
+
+void EGLAPIENTRY LogEGLDebugMessage(EGLenum error,
+                                    const char* command,
+                                    EGLint message_type,
+                                    EGLLabelKHR thread_label,
+                                    EGLLabelKHR object_label,
+                                    const char* message) {
+  std::string formatted_message = std::string("EGL Driver message (") +
+                                  GetDebugMessageTypeString(message_type) +
+                                  ") " + command + ": " + message;
+
+  // Assume that all labels that have been set are strings
+  if (thread_label) {
+    formatted_message += " thread: ";
+    formatted_message += static_cast<const char*>(thread_label);
+  }
+  if (object_label) {
+    formatted_message += " object: ";
+    formatted_message += static_cast<const char*>(object_label);
+  }
+
+  if (message_type == EGL_DEBUG_MSG_CRITICAL_KHR ||
+      message_type == EGL_DEBUG_MSG_ERROR_KHR) {
+    LOG(ERROR) << formatted_message;
+  } else {
+    DVLOG(1) << formatted_message;
+  }
+}
+
+void GetEGLInitDisplays(bool supports_angle_d3d,
+                        bool supports_angle_opengl,
+                        bool supports_angle_null,
+                        bool supports_angle_vulkan,
+                        bool supports_angle_swiftshader,
+                        bool supports_angle_egl,
+                        bool supports_angle_metal,
+                        const base::CommandLine* command_line,
+                        std::vector<DisplayType>* init_displays) {
+  // If we're already requesting software GL, make sure we don't fallback to the
+  // GPU
+  bool forceSoftwareGL = IsSoftwareGLImplementation(GetGLImplementationParts());
+
+  std::string requested_renderer =
+      forceSoftwareGL ? kANGLEImplementationSwiftShaderName
+                      : command_line->GetSwitchValueASCII(switches::kUseANGLE);
+
+  bool use_angle_default =
+      !forceSoftwareGL &&
+      (!command_line->HasSwitch(switches::kUseANGLE) ||
+       requested_renderer == kANGLEImplementationDefaultName);
+
+  if (supports_angle_null &&
+      requested_renderer == kANGLEImplementationNullName) {
+    AddInitDisplay(init_displays, ANGLE_NULL);
+    return;
+  }
+
+  // If no display has been explicitly requested and the DefaultANGLEOpenGL
+  // experiment is enabled, try creating OpenGL displays first.
+  // TODO(oetuaho@nvidia.com): Only enable this path on specific GPUs with a
+  // blocklist entry. http://crbug.com/693090
+  if (supports_angle_opengl && use_angle_default &&
+      base::FeatureList::IsEnabled(features::kDefaultANGLEOpenGL)) {
+    AddInitDisplay(init_displays, ANGLE_OPENGL);
+    AddInitDisplay(init_displays, ANGLE_OPENGLES);
+  }
+
+  if (supports_angle_metal && use_angle_default &&
+      base::FeatureList::IsEnabled(features::kDefaultANGLEMetal)) {
+    AddInitDisplay(init_displays, ANGLE_METAL);
+  }
+
+  if (supports_angle_vulkan && use_angle_default &&
+      features::IsDefaultANGLEVulkan()) {
+    AddInitDisplay(init_displays, ANGLE_VULKAN);
+  }
+
+  if (supports_angle_d3d) {
+    if (use_angle_default) {
+      // Default mode for ANGLE - try D3D11, else try D3D9
+      if (!command_line->HasSwitch(switches::kDisableD3D11)) {
+        AddInitDisplay(init_displays, ANGLE_D3D11);
+      }
+      AddInitDisplay(init_displays, ANGLE_D3D9);
+    } else {
+      if (requested_renderer == kANGLEImplementationD3D11Name) {
+        AddInitDisplay(init_displays, ANGLE_D3D11);
+      } else if (requested_renderer == kANGLEImplementationD3D9Name) {
+        AddInitDisplay(init_displays, ANGLE_D3D9);
+      } else if (requested_renderer == kANGLEImplementationD3D11NULLName) {
+        AddInitDisplay(init_displays, ANGLE_D3D11_NULL);
+      } else if (requested_renderer == kANGLEImplementationD3D11on12Name) {
+        AddInitDisplay(init_displays, ANGLE_D3D11on12);
+      }
+    }
+  }
+
+  if (supports_angle_opengl) {
+    if (use_angle_default && !supports_angle_d3d) {
+#if BUILDFLAG(IS_ANDROID)
+      // Don't request desktopGL on android
+      AddInitDisplay(init_displays, ANGLE_OPENGLES);
+#else
+      AddInitDisplay(init_displays, ANGLE_OPENGL);
+      AddInitDisplay(init_displays, ANGLE_OPENGLES);
+#endif
+    } else {
+      if (requested_renderer == kANGLEImplementationOpenGLName) {
+        AddInitDisplay(init_displays, ANGLE_OPENGL);
+      } else if (requested_renderer == kANGLEImplementationOpenGLESName) {
+        AddInitDisplay(init_displays, ANGLE_OPENGLES);
+      } else if (requested_renderer == kANGLEImplementationOpenGLNULLName) {
+        AddInitDisplay(init_displays, ANGLE_OPENGL_NULL);
+      } else if (requested_renderer == kANGLEImplementationOpenGLESNULLName) {
+        AddInitDisplay(init_displays, ANGLE_OPENGLES_NULL);
+      } else if (requested_renderer == kANGLEImplementationOpenGLEGLName &&
+                 supports_angle_egl) {
+        AddInitDisplay(init_displays, ANGLE_OPENGL_EGL);
+      } else if (requested_renderer == kANGLEImplementationOpenGLESEGLName &&
+                 supports_angle_egl) {
+        AddInitDisplay(init_displays, ANGLE_OPENGLES_EGL);
+      }
+    }
+  }
+
+  if (supports_angle_vulkan) {
+    if (use_angle_default) {
+      if (!supports_angle_d3d && !supports_angle_opengl) {
+        AddInitDisplay(init_displays, ANGLE_VULKAN);
+      }
+    } else if (requested_renderer == kANGLEImplementationVulkanName) {
+      AddInitDisplay(init_displays, ANGLE_VULKAN);
+    } else if (requested_renderer == kANGLEImplementationVulkanNULLName) {
+      AddInitDisplay(init_displays, ANGLE_VULKAN_NULL);
+    }
+  }
+
+  if (supports_angle_swiftshader) {
+    if (requested_renderer == kANGLEImplementationSwiftShaderName ||
+        requested_renderer == kANGLEImplementationSwiftShaderForWebGLName) {
+      AddInitDisplay(init_displays, ANGLE_SWIFTSHADER);
+    }
+  }
+
+  if (supports_angle_metal) {
+    if (use_angle_default) {
+      if (!supports_angle_opengl) {
+        AddInitDisplay(init_displays, ANGLE_METAL);
+      }
+    } else if (requested_renderer == kANGLEImplementationMetalName) {
+      AddInitDisplay(init_displays, ANGLE_METAL);
+    } else if (requested_renderer == kANGLEImplementationMetalNULLName) {
+      AddInitDisplay(init_displays, ANGLE_METAL_NULL);
+    }
+  }
+
+  // If no displays are available due to missing angle extensions or invalid
+  // flags, request the default display.
+  if (init_displays->empty()) {
+    init_displays->push_back(DEFAULT);
+  }
+}
+
+}  // namespace
+
+void GetEGLInitDisplaysForTesting(bool supports_angle_d3d,
+                                  bool supports_angle_opengl,
+                                  bool supports_angle_null,
+                                  bool supports_angle_vulkan,
+                                  bool supports_angle_swiftshader,
+                                  bool supports_angle_egl,
+                                  bool supports_angle_metal,
+                                  const base::CommandLine* command_line,
+                                  std::vector<DisplayType>* init_displays) {
+  GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
+                     supports_angle_null, supports_angle_vulkan,
+                     supports_angle_swiftshader, supports_angle_egl,
+                     supports_angle_metal, command_line, init_displays);
+}
+
 GLDisplay::GLDisplay(uint64_t system_device_id)
     : system_device_id_(system_device_id) {}
 
@@ -37,16 +682,12 @@
   display_ = display;
 }
 
-EGLDisplay GLDisplayEGL::GetHardwareDisplay() {
-  return GetDisplay();
+EGLDisplayPlatform GLDisplayEGL::GetNativeDisplay() const {
+  return native_display_;
 }
 
-EGLNativeDisplayType GLDisplayEGL::GetNativeDisplay() {
-  return native_display.GetDisplay();
-}
-
-DisplayType GLDisplayEGL::GetDisplayType() {
-  return display_type;
+DisplayType GLDisplayEGL::GetDisplayType() const {
+  return display_type_;
 }
 
 // static
@@ -56,20 +697,247 @@
 }
 
 bool GLDisplayEGL::IsEGLSurfacelessContextSupported() {
-  return egl_surfaceless_context_supported;
+  return egl_surfaceless_context_supported_;
 }
 
 bool GLDisplayEGL::IsEGLContextPrioritySupported() {
-  return egl_context_priority_supported;
+  return egl_context_priority_supported_;
 }
 
 bool GLDisplayEGL::IsAndroidNativeFenceSyncSupported() {
-  return egl_android_native_fence_sync_supported;
+  return egl_android_native_fence_sync_supported_;
 }
 
 bool GLDisplayEGL::IsANGLEExternalContextAndSurfaceSupported() {
   return this->ext->b_EGL_ANGLE_external_context_and_surface;
 }
+
+// InitializeDisplay is necessary because the static binding code
+// needs a full Display init before it can query the Display extensions.
+bool GLDisplayEGL::InitializeDisplay(EGLDisplayPlatform native_display) {
+  if (display_ != EGL_NO_DISPLAY)
+    return true;
+
+  native_display_ = native_display;
+
+  bool supports_egl_debug = g_driver_egl.client_ext.b_EGL_KHR_debug;
+  if (supports_egl_debug) {
+    EGLAttrib controls[] = {
+        EGL_DEBUG_MSG_CRITICAL_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_ERROR_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_WARN_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_INFO_KHR,
+        EGL_TRUE,
+        EGL_NONE,
+        EGL_NONE,
+    };
+
+    eglDebugMessageControlKHR(&LogEGLDebugMessage, controls);
+  }
+
+  bool supports_angle_d3d = false;
+  bool supports_angle_opengl = false;
+  bool supports_angle_null = false;
+  bool supports_angle_vulkan = false;
+  bool supports_angle_swiftshader = false;
+  bool supports_angle_egl = false;
+  bool supports_angle_metal = false;
+  // Check for availability of ANGLE extensions.
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle) {
+    supports_angle_d3d = g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_d3d;
+    supports_angle_opengl =
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_opengl;
+    supports_angle_null =
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_null;
+    supports_angle_vulkan =
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_vulkan;
+    supports_angle_swiftshader =
+        g_driver_egl.client_ext
+            .b_EGL_ANGLE_platform_angle_device_type_swiftshader;
+    supports_angle_egl = g_driver_egl.client_ext
+                             .b_EGL_ANGLE_platform_angle_device_type_egl_angle;
+    supports_angle_metal =
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_metal;
+  }
+
+  bool supports_angle = supports_angle_d3d || supports_angle_opengl ||
+                        supports_angle_null || supports_angle_vulkan ||
+                        supports_angle_swiftshader || supports_angle_metal;
+
+  std::vector<DisplayType> init_displays;
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
+                     supports_angle_null, supports_angle_vulkan,
+                     supports_angle_swiftshader, supports_angle_egl,
+                     supports_angle_metal, command_line, &init_displays);
+
+  std::vector<std::string> enabled_angle_features =
+      GetStringVectorFromCommandLine(command_line,
+                                     switches::kEnableANGLEFeatures);
+  std::vector<std::string> disabled_angle_features =
+      GetStringVectorFromCommandLine(command_line,
+                                     switches::kDisableANGLEFeatures);
+
+  bool disable_all_angle_features =
+      command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds);
+
+  for (size_t disp_index = 0; disp_index < init_displays.size(); ++disp_index) {
+    DisplayType display_type = init_displays[disp_index];
+    EGLDisplay display = GetDisplayFromType(
+        display_type, native_display, enabled_angle_features,
+        disabled_angle_features, disable_all_angle_features, system_device_id_);
+    if (display == EGL_NO_DISPLAY) {
+      LOG(ERROR) << "EGL display query failed with error "
+                 << GetLastEGLErrorString();
+    }
+
+    // Init ANGLE platform now that we have the global display.
+    if (supports_angle) {
+      if (!angle::InitializePlatform(display)) {
+        LOG(ERROR) << "ANGLE Platform initialization failed.";
+      }
+
+      SetANGLEImplementation(
+          GetANGLEImplementationFromDisplayType(display_type));
+    }
+
+    // The platform may need to unset its platform specific display env in case
+    // of vulkan if the platform doesn't support Vulkan surface.
+    absl::optional<base::ScopedEnvironmentVariableOverride> unset_display;
+    if (display_type == ANGLE_VULKAN) {
+      unset_display = GLDisplayEglUtil::GetInstance()
+                          ->MaybeGetScopedDisplayUnsetForVulkan();
+    }
+
+    if (!eglInitialize(display, nullptr, nullptr)) {
+      bool is_last = disp_index == init_displays.size() - 1;
+
+      LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
+                 << " failed with error " << GetLastEGLErrorString()
+                 << (is_last ? "" : ", trying next display type");
+      continue;
+    }
+
+    std::ostringstream display_type_string;
+    auto gl_implementation = GetGLImplementationParts();
+    display_type_string << GetGLImplementationGLName(gl_implementation);
+    if (gl_implementation.gl == kGLImplementationEGLANGLE) {
+      display_type_string << ":" << DisplayTypeString(display_type);
+    }
+
+    static auto* egl_display_type_key = base::debug::AllocateCrashKeyString(
+        "egl-display-type", base::debug::CrashKeySize::Size32);
+    base::debug::SetCrashKeyString(egl_display_type_key,
+                                   display_type_string.str());
+
+    UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
+                              DISPLAY_TYPE_MAX);
+    display_ = display;
+    display_type_ = display_type;
+    ext->InitializeExtensionSettings(this);
+    return true;
+  }
+
+  return false;
+}
+
+void GLDisplayEGL::InitializeCommon() {
+  // According to https://source.android.com/compatibility/android-cdd.html the
+  // EGL_IMG_context_priority extension is mandatory for Virtual Reality High
+  // Performance support, but due to a bug in Android Nougat the extension
+  // isn't being reported even when it's present. As a fallback, check if other
+  // related extensions that were added for VR support are present, and assume
+  // that this implies context priority is also supported. See also:
+  // https://github.com/googlevr/gvr-android-sdk/issues/330
+  egl_context_priority_supported_ =
+      ext->b_EGL_IMG_context_priority ||
+      (ext->b_EGL_ANDROID_front_buffer_auto_refresh &&
+       ext->b_EGL_ANDROID_create_native_client_buffer);
+
+  // Check if SurfacelessEGL is supported.
+  egl_surfaceless_context_supported_ = ext->b_EGL_KHR_surfaceless_context;
+
+  // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
+  // workaround, since code written for Android WebView takes different paths
+  // based on whether GL surface objects have underlying EGL surface handles,
+  // conflicting with the use of surfaceless. ANGLE can still expose surfacelss
+  // because it is emulated with pbuffers if native support is not present. See
+  // https://crbug.com/382349.
+
+#if BUILDFLAG(IS_ANDROID)
+  // Use the WebGL compatibility extension for detecting ANGLE. ANGLE always
+  // exposes it.
+  bool is_angle = ext->b_EGL_ANGLE_create_context_webgl_compatibility;
+  if (!is_angle) {
+    egl_surfaceless_context_supported_ = false;
+  }
+#endif
+
+  if (egl_surfaceless_context_supported_) {
+    // EGL_KHR_surfaceless_context is supported but ensure
+    // GL_OES_surfaceless_context is also supported. We need a current context
+    // to query for supported GL extensions.
+    scoped_refptr<GLSurface> surface =
+        new SurfacelessEGL(this, gfx::Size(1, 1));
+    scoped_refptr<GLContext> context = InitializeGLContext(
+        new GLContextEGL(nullptr), surface.get(), GLContextAttribs());
+    if (!context || !context->MakeCurrent(surface.get()))
+      egl_surfaceless_context_supported_ = false;
+
+    // Ensure context supports GL_OES_surfaceless_context.
+    if (egl_surfaceless_context_supported_) {
+      egl_surfaceless_context_supported_ =
+          context->HasExtension("GL_OES_surfaceless_context");
+      context->ReleaseCurrent(surface.get());
+    }
+  }
+
+  // The native fence sync extension is a bit complicated. It's reported as
+  // present for ChromeOS, but Android currently doesn't report this extension
+  // even when it's present, and older devices and Android emulator may export
+  // a useless wrapper function. See crbug.com/775707 for details. In short, if
+  // the symbol is present and we're on Android N or newer and we are not on
+  // Android emulator, assume that it's usable even if the extension wasn't
+  // reported. TODO(https://crbug.com/1086781): Once this is fixed at the
+  // Android level, update the heuristic to trust the reported extension from
+  // that version onward.
+  egl_android_native_fence_sync_supported_ =
+      ext->b_EGL_ANDROID_native_fence_sync;
+#if BUILDFLAG(IS_ANDROID)
+  if (!egl_android_native_fence_sync_supported_ &&
+      base::android::BuildInfo::GetInstance()->sdk_int() >=
+          base::android::SDK_VERSION_NOUGAT &&
+      g_driver_egl.fn.eglDupNativeFenceFDANDROIDFn &&
+      base::SysInfo::GetAndroidHardwareEGL() != "swiftshader" &&
+      base::SysInfo::GetAndroidHardwareEGL() != "emulation") {
+    egl_android_native_fence_sync_supported_ = true;
+  }
+#endif
+}
+
+bool GLDisplayEGL::InitializeExtensionSettings() {
+  if (display_ == EGL_NO_DISPLAY)
+    return false;
+  ext->UpdateConditionalExtensionSettings(this);
+  return true;
+}
+
+void GLDisplayEGL::Shutdown() {
+  if (display_ == EGL_NO_DISPLAY)
+    return;
+
+  angle::ResetPlatform(display_);
+  DCHECK(g_driver_egl.fn.eglTerminateFn);
+  eglTerminate(display_);
+
+  display_ = EGL_NO_DISPLAY;
+  egl_surfaceless_context_supported_ = false;
+  egl_context_priority_supported_ = false;
+  egl_android_native_fence_sync_supported_ = false;
+}
 #endif  // defined(USE_EGL)
 
 #if defined(USE_GLX)
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h
index ef4f069..a55edd5 100644
--- a/ui/gl/gl_display.h
+++ b/ui/gl/gl_display.h
@@ -15,6 +15,10 @@
 #include <EGL/egl.h>
 #endif  // defined(USE_EGL)
 
+namespace base {
+class CommandLine;
+}  // namespace base
+
 namespace gl {
 struct DisplayExtensionsEGL;
 template <typename GLDisplayPlatform>
@@ -64,6 +68,17 @@
   DISPLAY_TYPE_MAX = 19,
 };
 
+GL_EXPORT void GetEGLInitDisplaysForTesting(
+    bool supports_angle_d3d,
+    bool supports_angle_opengl,
+    bool supports_angle_null,
+    bool supports_angle_vulkan,
+    bool supports_angle_swiftshader,
+    bool supports_angle_egl,
+    bool supports_angle_metal,
+    const base::CommandLine* command_line,
+    std::vector<DisplayType>* init_displays);
+
 class GL_EXPORT GLDisplay {
  public:
   GLDisplay(const GLDisplay&) = delete;
@@ -93,24 +108,18 @@
 
   EGLDisplay GetDisplay() override;
   void SetDisplay(EGLDisplay display);
-
-  EGLDisplay GetHardwareDisplay();
-
-  EGLNativeDisplayType GetNativeDisplay();
-  DisplayType GetDisplayType();
+  EGLDisplayPlatform GetNativeDisplay() const;
+  DisplayType GetDisplayType() const;
 
   bool IsEGLSurfacelessContextSupported();
   bool IsEGLContextPrioritySupported();
   bool IsAndroidNativeFenceSyncSupported();
   bool IsANGLEExternalContextAndSurfaceSupported();
 
-  EGLDisplayPlatform native_display = EGLDisplayPlatform(EGL_DEFAULT_DISPLAY);
-
-  DisplayType display_type = DisplayType::DEFAULT;
-
-  bool egl_surfaceless_context_supported = false;
-  bool egl_context_priority_supported = false;
-  bool egl_android_native_fence_sync_supported = false;
+  bool InitializeDisplay(EGLDisplayPlatform native_display);
+  void InitializeCommon();
+  bool InitializeExtensionSettings();
+  void Shutdown();
 
   std::unique_ptr<DisplayExtensionsEGL> ext;
 
@@ -119,7 +128,13 @@
 
   explicit GLDisplayEGL(uint64_t system_device_id);
 
-  EGLDisplay display_;
+  EGLDisplay display_ = EGL_NO_DISPLAY;
+  EGLDisplayPlatform native_display_ = EGLDisplayPlatform(EGL_DEFAULT_DISPLAY);
+  DisplayType display_type_ = DisplayType::DEFAULT;
+
+  bool egl_surfaceless_context_supported_ = false;
+  bool egl_context_priority_supported_ = false;
+  bool egl_android_native_fence_sync_supported_ = false;
 };
 #endif  // defined(USE_EGL)
 
diff --git a/ui/gl/gl_egl_api_implementation.cc b/ui/gl/gl_egl_api_implementation.cc
index 597db1b..d384bbd 100644
--- a/ui/gl/gl_egl_api_implementation.cc
+++ b/ui/gl/gl_egl_api_implementation.cc
@@ -136,7 +136,7 @@
 }
 
 bool InitializeExtensionSettingsOneOffEGL(GLDisplayEGL* display) {
-  return GLSurfaceEGL::InitializeExtensionSettingsOneOff(display);
+  return display->InitializeExtensionSettings();
 }
 
 }  // namespace gl
diff --git a/ui/gl/gl_image_d3d.cc b/ui/gl/gl_image_d3d.cc
index 00cce39..b98cac6 100644
--- a/ui/gl/gl_image_d3d.cc
+++ b/ui/gl/gl_image_d3d.cc
@@ -39,9 +39,8 @@
 
 GLImageD3D::~GLImageD3D() {
   if (egl_image_ != EGL_NO_IMAGE_KHR) {
-    if (eglDestroyImageKHR(
-            GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
-            egl_image_) == EGL_FALSE) {
+    if (eglDestroyImageKHR(GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                           egl_image_) == EGL_FALSE) {
       DLOG(ERROR) << "Error destroying EGLImage: "
                   << ui::GetLastEGLErrorString();
     }
@@ -58,7 +57,7 @@
                             static_cast<EGLint>(plane_index_),
                             EGL_NONE};
   egl_image_ =
-      eglCreateImageKHR(GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
+      eglCreateImageKHR(GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
                         EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
                         static_cast<EGLClientBuffer>(texture_.Get()), attribs);
   if (egl_image_ == EGL_NO_IMAGE_KHR) {
diff --git a/ui/gl/gl_image_dxgi.cc b/ui/gl/gl_image_dxgi.cc
index 15c1166b..6eb0822 100644
--- a/ui/gl/gl_image_dxgi.cc
+++ b/ui/gl/gl_image_dxgi.cc
@@ -64,16 +64,14 @@
                                 EGL_NONE};
 
   EGLint num_config;
-  EGLDisplay display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   EGLBoolean result =
       eglChooseConfig(display, attrib_list, nullptr, 0, &num_config);
   if (result != EGL_TRUE)
     return nullptr;
   std::vector<EGLConfig> all_configs(num_config);
-  result =
-      eglChooseConfig(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
-                      attrib_list, all_configs.data(), num_config, &num_config);
+  result = eglChooseConfig(display, attrib_list, all_configs.data(), num_config,
+                           &num_config);
   if (result != EGL_TRUE)
     return nullptr;
   for (EGLConfig config : all_configs) {
@@ -127,8 +125,8 @@
       EGL_NONE};
 
   return eglCreatePbufferFromClientBuffer(
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
-      EGL_D3D_TEXTURE_ANGLE, texture.Get(), config, pBufferAttributes);
+      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(), EGL_D3D_TEXTURE_ANGLE,
+      texture.Get(), config, pBufferAttributes);
 }
 
 }  // namespace
@@ -174,9 +172,8 @@
     return false;
   }
 
-  return eglBindTexImage(
-             gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
-             surface_, EGL_BACK_BUFFER) == EGL_TRUE;
+  return eglBindTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                         surface_, EGL_BACK_BUFFER) == EGL_TRUE;
 }
 
 bool GLImageDXGI::CopyTexImage(unsigned target) {
@@ -224,7 +221,7 @@
 
   keyed_mutex_->ReleaseSync(KEY_RELEASE);
 
-  eglReleaseTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
+  eglReleaseTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
                      surface_, EGL_BACK_BUFFER);
 }
 
@@ -267,13 +264,12 @@
 GLImageDXGI::~GLImageDXGI() {
   if (handle_.Get()) {
     if (surface_ != EGL_NO_SURFACE) {
-      eglDestroySurface(
-          gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(), surface_);
+      eglDestroySurface(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                        surface_);
     }
   } else if (stream_) {
-    EGLDisplay egl_display =
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
-    eglDestroyStreamKHR(egl_display, stream_);
+    eglDestroyStreamKHR(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                        stream_);
   }
 }
 
@@ -303,8 +299,7 @@
     DLOG(ERROR) << "CreateTexture2D failed: " << std::hex << hr;
     return false;
   }
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
 
   EGLAttrib frame_attributes[] = {
       EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE,
diff --git a/ui/gl/gl_image_egl.cc b/ui/gl/gl_image_egl.cc
index 2baaa0c..791b031 100644
--- a/ui/gl/gl_image_egl.cc
+++ b/ui/gl/gl_image_egl.cc
@@ -20,7 +20,7 @@
     return;
 
   const EGLBoolean result = eglDestroyImageKHR(
-      GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(), egl_image_);
+      GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(), egl_image_);
   if (result == EGL_FALSE)
     DLOG(ERROR) << "Error destroying EGLImage: " << ui::GetLastEGLErrorString();
 }
@@ -31,9 +31,8 @@
                             const EGLint* attrs) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
-  egl_image_ =
-      eglCreateImageKHR(GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
-                        context, target, buffer, attrs);
+  egl_image_ = eglCreateImageKHR(GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                                 context, target, buffer, attrs);
   const bool success = egl_image_ != EGL_NO_IMAGE_KHR;
   if (!success)
     LOG(ERROR) << "Error creating EGLImage: " << ui::GetLastEGLErrorString();
diff --git a/ui/gl/gl_image_io_surface_egl.mm b/ui/gl/gl_image_io_surface_egl.mm
index c03ad34..254c58f 100644
--- a/ui/gl/gl_image_io_surface_egl.mm
+++ b/ui/gl/gl_image_io_surface_egl.mm
@@ -113,7 +113,7 @@
 GLImageIOSurfaceEGL::GLImageIOSurfaceEGL(const gfx::Size& size,
                                          unsigned internalformat)
     : GLImageIOSurface(size, internalformat),
-      display_(GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay()),
+      display_(GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay()),
       pbuffer_(EGL_NO_SURFACE),
       dummy_config_(nullptr),
       texture_target_(EGL_TEXTURE_RECTANGLE_ANGLE),
diff --git a/ui/gl/gl_image_native_pixmap.cc b/ui/gl/gl_image_native_pixmap.cc
index 8d0f6ab..c539c8e 100644
--- a/ui/gl/gl_image_native_pixmap.cc
+++ b/ui/gl/gl_image_native_pixmap.cc
@@ -293,8 +293,8 @@
   EGLuint64KHR modifiers = 0;
 
   if (!eglExportDMABUFImageQueryMESA(
-          GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(), egl_image_,
-          &fourcc, &num_planes, &modifiers)) {
+          GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(), egl_image_, &fourcc,
+          &num_planes, &modifiers)) {
     LOG(ERROR) << "Error querying EGLImage: " << ui::GetLastEGLErrorString();
     return gfx::NativePixmapHandle();
   }
@@ -330,9 +330,9 @@
 
   // It is specified for eglExportDMABUFImageMESA that the app is responsible
   // for closing any fds retrieved.
-  if (!eglExportDMABUFImageMESA(
-          GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(), egl_image_,
-          &fds[0], &strides[0], &offsets[0])) {
+  if (!eglExportDMABUFImageMESA(GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
+                                egl_image_, &fds[0], &strides[0],
+                                &offsets[0])) {
     LOG(ERROR) << "Error exporting EGLImage: " << ui::GetLastEGLErrorString();
     return gfx::NativePixmapHandle();
   }
@@ -392,8 +392,7 @@
   if (!has_image_flush_external_)
     return;
 
-  EGLDisplay display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   const EGLAttrib attribs[] = {
       EGL_NONE,
   };
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 7a8f3ee..b362ea0 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -12,31 +12,22 @@
 #include <sstream>
 #include <vector>
 
-#include "base/command_line.h"
-#include "base/containers/contains.h"
-#include "base/debug/crash_logging.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/scoped_environment_variable_override.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
 #include "base/system/sys_info.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/gpu_fence.h"
-#include "ui/gl/angle_platform_impl.h"
 #include "ui/gl/egl_util.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
-#include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_display_egl_util.h"
 #include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_image.h"
-#include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface_presentation_helper.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/gl_utils.h"
@@ -75,73 +66,11 @@
 
 // From ANGLE's egl/eglext.h.
 
-#ifndef EGL_ANGLE_platform_angle
-#define EGL_ANGLE_platform_angle 1
-#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
-#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
-#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204
-#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205
-#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206
-#define EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE 0x348E
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x345E
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE 0x3487
-#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348F
-#endif /* EGL_ANGLE_platform_angle */
-
-#ifndef EGL_ANGLE_platform_angle_d3d
-#define EGL_ANGLE_platform_angle_d3d 1
-#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE 0x320B
-#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE 0x320C
-#endif /* EGL_ANGLE_platform_angle_d3d */
-
-#ifndef EGL_ANGLE_platform_angle_d3d_luid
-#define EGL_ANGLE_platform_angle_d3d_luid 1
-#define EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE 0x34A0
-#define EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE 0x34A1
-#endif /* EGL_ANGLE_platform_angle_d3d_luid */
-
-#ifndef EGL_ANGLE_platform_angle_d3d11on12
-#define EGL_ANGLE_platform_angle_d3d11on12 1
-#define EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE 0x3488
-#endif /* EGL_ANGLE_platform_angle_d3d11on12 */
-
-#ifndef EGL_ANGLE_platform_angle_opengl
-#define EGL_ANGLE_platform_angle_opengl 1
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
-#endif /* EGL_ANGLE_platform_angle_opengl */
-
-#ifndef EGL_ANGLE_platform_angle_null
-#define EGL_ANGLE_platform_angle_null 1
-#define EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE 0x33AE
-#endif /* EGL_ANGLE_platform_angle_null */
-
-#ifndef EGL_ANGLE_platform_angle_vulkan
-#define EGL_ANGLE_platform_angle_vulkan 1
-#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
-#define EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE 0x34A5
-#endif /* EGL_ANGLE_platform_angle_vulkan */
-
 #ifndef EGL_ANGLE_robust_resource_initialization
 #define EGL_ANGLE_robust_resource_initialization 1
 #define EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453
 #endif /* EGL_ANGLE_display_robust_resource_initialization */
 
-#ifndef EGL_ANGLE_platform_angle_metal
-#define EGL_ANGLE_platform_angle_metal 1
-#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
-#endif /* EGL_ANGLE_platform_angle_metal */
-
-#ifndef EGL_ANGLE_x11_visual
-#define EGL_ANGLE_x11_visual 1
-#define EGL_X11_VISUAL_ID_ANGLE 0x33A3
-#endif /* EGL_ANGLE_x11_visual */
-
 #ifndef EGL_ANGLE_surface_orientation
 #define EGL_ANGLE_surface_orientation
 #define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7
@@ -150,45 +79,7 @@
 #define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002
 #endif /* EGL_ANGLE_surface_orientation */
 
-#ifndef EGL_ANGLE_direct_composition
-#define EGL_ANGLE_direct_composition 1
-#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5
-#endif /* EGL_ANGLE_direct_composition */
-
-#ifndef EGL_ANGLE_display_robust_resource_initialization
-#define EGL_ANGLE_display_robust_resource_initialization 1
-#define EGL_DISPLAY_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453
-#endif /* EGL_ANGLE_display_robust_resource_initialization */
-
-#ifndef EGL_ANGLE_display_power_preference
-#define EGL_ANGLE_display_power_preference 1
-#define EGL_POWER_PREFERENCE_ANGLE 0x3482
-#define EGL_LOW_POWER_ANGLE 0x0001
-#define EGL_HIGH_POWER_ANGLE 0x0002
-#endif /* EGL_ANGLE_power_preference */
-
-#ifndef EGL_ANGLE_platform_angle_device_id
-#define EGL_ANGLE_platform_angle_device_id
-#define EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE 0x34D6
-#define EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE 0x34D7
-#endif /* EGL_ANGLE_platform_angle_device_id */
-
-// From ANGLE's egl/eglext.h.
-#ifndef EGL_ANGLE_feature_control
-#define EGL_ANGLE_feature_control 1
-#define EGL_FEATURE_NAME_ANGLE 0x3460
-#define EGL_FEATURE_CATEGORY_ANGLE 0x3461
-#define EGL_FEATURE_DESCRIPTION_ANGLE 0x3462
-#define EGL_FEATURE_BUG_ANGLE 0x3463
-#define EGL_FEATURE_STATUS_ANGLE 0x3464
-#define EGL_FEATURE_COUNT_ANGLE 0x3465
-#define EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
-#define EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
-#define EGL_FEATURE_ALL_DISABLED_ANGLE 0x3469
-#endif /* EGL_ANGLE_feature_control */
-
 using ui::GetLastEGLErrorString;
-using ui::PlatformEvent;
 
 namespace gl {
 
@@ -280,335 +171,6 @@
   raw_ptr<GLDisplayEGL> display_ = nullptr;
 };
 
-std::vector<const char*> GetAttribArrayFromStringVector(
-    const std::vector<std::string>& strings) {
-  std::vector<const char*> attribs;
-  for (const std::string& item : strings) {
-    attribs.push_back(item.c_str());
-  }
-  attribs.push_back(0);
-  return attribs;
-}
-
-std::vector<std::string> GetStringVectorFromCommandLine(
-    const base::CommandLine* command_line,
-    const char switch_name[]) {
-  std::string command_string = command_line->GetSwitchValueASCII(switch_name);
-  return base::SplitString(command_string, ", ;", base::TRIM_WHITESPACE,
-                           base::SPLIT_WANT_NONEMPTY);
-}
-
-EGLDisplay GetPlatformANGLEDisplay(
-    GLDisplayEGL* gl_display,
-    EGLenum platform_type,
-    const std::vector<std::string>& enabled_features,
-    const std::vector<std::string>& disabled_features,
-    const std::vector<EGLAttrib>& extra_display_attribs) {
-  std::vector<EGLAttrib> display_attribs(extra_display_attribs);
-
-  display_attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
-  display_attribs.push_back(static_cast<EGLAttrib>(platform_type));
-
-  if (platform_type == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) {
-    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(switches::kUseAdapterLuid)) {
-      // If the LUID is specified, the format is <high part>,<low part>. Split
-      // and add them to the EGL_ANGLE_platform_angle_d3d_luid ext attributes.
-      std::string luid =
-          command_line->GetSwitchValueASCII(switches::kUseAdapterLuid);
-      size_t comma = luid.find(',');
-      if (comma != std::string::npos) {
-        int32_t high;
-        uint32_t low;
-        if (!base::StringToInt(luid.substr(0, comma), &high) ||
-            !base::StringToUint(luid.substr(comma + 1), &low))
-          return EGL_NO_DISPLAY;
-
-        display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE);
-        display_attribs.push_back(high);
-
-        display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE);
-        display_attribs.push_back(low);
-      }
-    }
-  }
-
-  GLDisplayEglUtil::GetInstance()->GetPlatformExtraDisplayAttribs(
-      platform_type, &display_attribs);
-
-  std::vector<const char*> enabled_features_attribs =
-      GetAttribArrayFromStringVector(enabled_features);
-  std::vector<const char*> disabled_features_attribs =
-      GetAttribArrayFromStringVector(disabled_features);
-  if (g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) {
-    if (!enabled_features_attribs.empty()) {
-      display_attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
-      display_attribs.push_back(
-          reinterpret_cast<EGLAttrib>(enabled_features_attribs.data()));
-    }
-    if (!disabled_features_attribs.empty()) {
-      display_attribs.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
-      display_attribs.push_back(
-          reinterpret_cast<EGLAttrib>(disabled_features_attribs.data()));
-    }
-  }
-  // TODO(dbehr) Add an attrib to Angle to pass EGL platform.
-
-  if (g_driver_egl.client_ext.b_EGL_ANGLE_display_power_preference) {
-    GpuPreference pref =
-        GLSurface::AdjustGpuPreference(GpuPreference::kDefault);
-    switch (pref) {
-      case GpuPreference::kDefault:
-        // Don't request any GPU, let ANGLE and the native driver decide.
-        break;
-      case GpuPreference::kLowPower:
-        display_attribs.push_back(EGL_POWER_PREFERENCE_ANGLE);
-        display_attribs.push_back(EGL_LOW_POWER_ANGLE);
-        break;
-      case GpuPreference::kHighPerformance:
-        display_attribs.push_back(EGL_POWER_PREFERENCE_ANGLE);
-        display_attribs.push_back(EGL_HIGH_POWER_ANGLE);
-        break;
-      default:
-        NOTREACHED();
-    }
-  }
-
-  display_attribs.push_back(EGL_NONE);
-
-  // This is an EGL 1.5 function that we know ANGLE supports. It's used to pass
-  // EGLAttribs (pointers) instead of EGLints into the display
-  return eglGetPlatformDisplay(
-      EGL_PLATFORM_ANGLE_ANGLE,
-      reinterpret_cast<void*>(gl_display->GetNativeDisplay()),
-      &display_attribs[0]);
-}
-
-EGLDisplay GetDisplayFromType(
-    DisplayType display_type,
-    GLDisplayEGL* gl_display,
-    const std::vector<std::string>& enabled_angle_features,
-    const std::vector<std::string>& disabled_angle_features,
-    bool disable_all_angle_features,
-    uint64_t system_device_id) {
-  DCHECK(gl_display);
-  std::vector<EGLAttrib> extra_display_attribs;
-  if (disable_all_angle_features) {
-    extra_display_attribs.push_back(EGL_FEATURE_ALL_DISABLED_ANGLE);
-    extra_display_attribs.push_back(EGL_TRUE);
-  }
-  if (system_device_id != 0 &&
-      g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_device_id) {
-    uint32_t low_part = system_device_id & 0xffffffff;
-    extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE);
-    extra_display_attribs.push_back(low_part);
-
-    uint32_t high_part = (system_device_id >> 32) & 0xffffffff;
-    extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE);
-    extra_display_attribs.push_back(high_part);
-  }
-  switch (display_type) {
-    case DEFAULT:
-    case SWIFT_SHADER: {
-      EGLDisplayPlatform native_display = gl_display->native_display;
-      if (native_display.GetPlatform() != 0) {
-        return eglGetPlatformDisplay(
-            native_display.GetPlatform(),
-            reinterpret_cast<void*>(native_display.GetDisplay()), nullptr);
-      } else {
-        return eglGetDisplay(native_display.GetDisplay());
-      }
-    }
-    case ANGLE_D3D9:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_D3D11:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_D3D11_NULL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGL:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGL_EGL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGL_NULL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGLES:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGLES_EGL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_OPENGLES_NULL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_NULL:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_VULKAN:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_VULKAN_NULL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_D3D11on12:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE);
-      extra_display_attribs.push_back(EGL_TRUE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_SWIFTSHADER:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE);
-#if defined(USE_OZONE)
-#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(OZONE_PLATFORM_X11)
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
-      extra_display_attribs.push_back(EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE);
-#endif  // BUILDFLAG(OZONE_PLATFORM_X11)
-#endif  // defined(USE_OZONE)
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_METAL:
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    case ANGLE_METAL_NULL:
-      extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
-      extra_display_attribs.push_back(
-          EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE);
-      return GetPlatformANGLEDisplay(
-          gl_display, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
-          enabled_angle_features, disabled_angle_features,
-          extra_display_attribs);
-    default:
-      NOTREACHED();
-      return EGL_NO_DISPLAY;
-  }
-}
-
-ANGLEImplementation GetANGLEImplementationFromDisplayType(
-    DisplayType display_type) {
-  switch (display_type) {
-    case ANGLE_D3D9:
-      return ANGLEImplementation::kD3D9;
-    case ANGLE_D3D11:
-    case ANGLE_D3D11_NULL:
-    case ANGLE_D3D11on12:
-      return ANGLEImplementation::kD3D11;
-    case ANGLE_OPENGL:
-    case ANGLE_OPENGL_NULL:
-      return ANGLEImplementation::kOpenGL;
-    case ANGLE_OPENGLES:
-    case ANGLE_OPENGLES_NULL:
-      return ANGLEImplementation::kOpenGLES;
-    case ANGLE_NULL:
-      return ANGLEImplementation::kNull;
-    case ANGLE_VULKAN:
-    case ANGLE_VULKAN_NULL:
-      return ANGLEImplementation::kVulkan;
-    case ANGLE_SWIFTSHADER:
-      return ANGLEImplementation::kSwiftShader;
-    case ANGLE_METAL:
-    case ANGLE_METAL_NULL:
-      return ANGLEImplementation::kMetal;
-    default:
-      return ANGLEImplementation::kNone;
-  }
-}
-
-const char* DisplayTypeString(DisplayType display_type) {
-  switch (display_type) {
-    case DEFAULT:
-      return "Default";
-    case SWIFT_SHADER:
-      return "SwiftShader";
-    case ANGLE_D3D9:
-      return "D3D9";
-    case ANGLE_D3D11:
-      return "D3D11";
-    case ANGLE_D3D11_NULL:
-      return "D3D11Null";
-    case ANGLE_OPENGL:
-      return "OpenGL";
-    case ANGLE_OPENGL_NULL:
-      return "OpenGLNull";
-    case ANGLE_OPENGLES:
-      return "OpenGLES";
-    case ANGLE_OPENGLES_NULL:
-      return "OpenGLESNull";
-    case ANGLE_NULL:
-      return "Null";
-    case ANGLE_VULKAN:
-      return "Vulkan";
-    case ANGLE_VULKAN_NULL:
-      return "VulkanNull";
-    case ANGLE_D3D11on12:
-      return "D3D11on12";
-    case ANGLE_SWIFTSHADER:
-      return "SwANGLE";
-    case ANGLE_OPENGL_EGL:
-      return "OpenGLEGL";
-    case ANGLE_OPENGLES_EGL:
-      return "OpenGLESEGL";
-    case ANGLE_METAL:
-      return "Metal";
-    case ANGLE_METAL_NULL:
-      return "MetalNull";
-    default:
-      NOTREACHED();
-      return "Err";
-  }
-}
-
 bool ValidateEglConfig(EGLDisplay display,
                        const EGLint* config_attribs,
                        EGLint* num_configs) {
@@ -784,192 +346,8 @@
   return nullptr;
 }
 
-void AddInitDisplay(std::vector<DisplayType>* init_displays,
-                    DisplayType display_type) {
-  // Make sure to not add the same display type twice.
-  if (!base::Contains(*init_displays, display_type))
-    init_displays->push_back(display_type);
-}
-
-const char* GetDebugMessageTypeString(EGLint source) {
-  switch (source) {
-    case EGL_DEBUG_MSG_CRITICAL_KHR:
-      return "Critical";
-    case EGL_DEBUG_MSG_ERROR_KHR:
-      return "Error";
-    case EGL_DEBUG_MSG_WARN_KHR:
-      return "Warning";
-    case EGL_DEBUG_MSG_INFO_KHR:
-      return "Info";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-static void EGLAPIENTRY LogEGLDebugMessage(EGLenum error,
-                                           const char* command,
-                                           EGLint message_type,
-                                           EGLLabelKHR thread_label,
-                                           EGLLabelKHR object_label,
-                                           const char* message) {
-  std::string formatted_message = std::string("EGL Driver message (") +
-                                  GetDebugMessageTypeString(message_type) +
-                                  ") " + command + ": " + message;
-
-  // Assume that all labels that have been set are strings
-  if (thread_label) {
-    formatted_message += " thread: ";
-    formatted_message += static_cast<const char*>(thread_label);
-  }
-  if (object_label) {
-    formatted_message += " object: ";
-    formatted_message += static_cast<const char*>(object_label);
-  }
-
-  if (message_type == EGL_DEBUG_MSG_CRITICAL_KHR ||
-      message_type == EGL_DEBUG_MSG_ERROR_KHR) {
-    LOG(ERROR) << formatted_message;
-  } else {
-    DVLOG(1) << formatted_message;
-  }
-}
-
 }  // namespace
 
-void GetEGLInitDisplays(bool supports_angle_d3d,
-                        bool supports_angle_opengl,
-                        bool supports_angle_null,
-                        bool supports_angle_vulkan,
-                        bool supports_angle_swiftshader,
-                        bool supports_angle_egl,
-                        bool supports_angle_metal,
-                        const base::CommandLine* command_line,
-                        std::vector<DisplayType>* init_displays) {
-  // If we're already requesting software GL, make sure we don't fallback to the
-  // GPU
-  bool forceSoftwareGL = IsSoftwareGLImplementation(GetGLImplementationParts());
-
-  std::string requested_renderer =
-      forceSoftwareGL ? kANGLEImplementationSwiftShaderName
-                      : command_line->GetSwitchValueASCII(switches::kUseANGLE);
-
-  bool use_angle_default =
-      !forceSoftwareGL &&
-      (!command_line->HasSwitch(switches::kUseANGLE) ||
-       requested_renderer == kANGLEImplementationDefaultName);
-
-  if (supports_angle_null &&
-      requested_renderer == kANGLEImplementationNullName) {
-    AddInitDisplay(init_displays, ANGLE_NULL);
-    return;
-  }
-
-  // If no display has been explicitly requested and the DefaultANGLEOpenGL
-  // experiment is enabled, try creating OpenGL displays first.
-  // TODO(oetuaho@nvidia.com): Only enable this path on specific GPUs with a
-  // blocklist entry. http://crbug.com/693090
-  if (supports_angle_opengl && use_angle_default &&
-      base::FeatureList::IsEnabled(features::kDefaultANGLEOpenGL)) {
-    AddInitDisplay(init_displays, ANGLE_OPENGL);
-    AddInitDisplay(init_displays, ANGLE_OPENGLES);
-  }
-
-  if (supports_angle_metal && use_angle_default &&
-      base::FeatureList::IsEnabled(features::kDefaultANGLEMetal)) {
-    AddInitDisplay(init_displays, ANGLE_METAL);
-  }
-
-  if (supports_angle_vulkan && use_angle_default &&
-      features::IsDefaultANGLEVulkan()) {
-    AddInitDisplay(init_displays, ANGLE_VULKAN);
-  }
-
-  if (supports_angle_d3d) {
-    if (use_angle_default) {
-      // Default mode for ANGLE - try D3D11, else try D3D9
-      if (!command_line->HasSwitch(switches::kDisableD3D11)) {
-        AddInitDisplay(init_displays, ANGLE_D3D11);
-      }
-      AddInitDisplay(init_displays, ANGLE_D3D9);
-    } else {
-      if (requested_renderer == kANGLEImplementationD3D11Name) {
-        AddInitDisplay(init_displays, ANGLE_D3D11);
-      } else if (requested_renderer == kANGLEImplementationD3D9Name) {
-        AddInitDisplay(init_displays, ANGLE_D3D9);
-      } else if (requested_renderer == kANGLEImplementationD3D11NULLName) {
-        AddInitDisplay(init_displays, ANGLE_D3D11_NULL);
-      } else if (requested_renderer == kANGLEImplementationD3D11on12Name) {
-        AddInitDisplay(init_displays, ANGLE_D3D11on12);
-      }
-    }
-  }
-
-  if (supports_angle_opengl) {
-    if (use_angle_default && !supports_angle_d3d) {
-#if BUILDFLAG(IS_ANDROID)
-      // Don't request desktopGL on android
-      AddInitDisplay(init_displays, ANGLE_OPENGLES);
-#else
-      AddInitDisplay(init_displays, ANGLE_OPENGL);
-      AddInitDisplay(init_displays, ANGLE_OPENGLES);
-#endif
-    } else {
-      if (requested_renderer == kANGLEImplementationOpenGLName) {
-        AddInitDisplay(init_displays, ANGLE_OPENGL);
-      } else if (requested_renderer == kANGLEImplementationOpenGLESName) {
-        AddInitDisplay(init_displays, ANGLE_OPENGLES);
-      } else if (requested_renderer == kANGLEImplementationOpenGLNULLName) {
-        AddInitDisplay(init_displays, ANGLE_OPENGL_NULL);
-      } else if (requested_renderer == kANGLEImplementationOpenGLESNULLName) {
-        AddInitDisplay(init_displays, ANGLE_OPENGLES_NULL);
-      } else if (requested_renderer == kANGLEImplementationOpenGLEGLName &&
-                 supports_angle_egl) {
-        AddInitDisplay(init_displays, ANGLE_OPENGL_EGL);
-      } else if (requested_renderer == kANGLEImplementationOpenGLESEGLName &&
-                 supports_angle_egl) {
-        AddInitDisplay(init_displays, ANGLE_OPENGLES_EGL);
-      }
-    }
-  }
-
-  if (supports_angle_vulkan) {
-    if (use_angle_default) {
-      if (!supports_angle_d3d && !supports_angle_opengl) {
-        AddInitDisplay(init_displays, ANGLE_VULKAN);
-      }
-    } else if (requested_renderer == kANGLEImplementationVulkanName) {
-      AddInitDisplay(init_displays, ANGLE_VULKAN);
-    } else if (requested_renderer == kANGLEImplementationVulkanNULLName) {
-      AddInitDisplay(init_displays, ANGLE_VULKAN_NULL);
-    }
-  }
-
-  if (supports_angle_swiftshader) {
-    if (requested_renderer == kANGLEImplementationSwiftShaderName ||
-        requested_renderer == kANGLEImplementationSwiftShaderForWebGLName) {
-      AddInitDisplay(init_displays, ANGLE_SWIFTSHADER);
-    }
-  }
-
-  if (supports_angle_metal) {
-    if (use_angle_default) {
-      if (!supports_angle_opengl) {
-        AddInitDisplay(init_displays, ANGLE_METAL);
-      }
-    } else if (requested_renderer == kANGLEImplementationMetalName) {
-      AddInitDisplay(init_displays, ANGLE_METAL);
-    } else if (requested_renderer == kANGLEImplementationMetalNULLName) {
-      AddInitDisplay(init_displays, ANGLE_METAL_NULL);
-    }
-  }
-
-  // If no displays are available due to missing angle extensions or invalid
-  // flags, request the default display.
-  if (init_displays->empty()) {
-    init_displays->push_back(DEFAULT);
-  }
-}
-
 GLSurfaceEGL::GLSurfaceEGL(GLDisplayEGL* display) : display_(display) {
   DCHECK(display_);
 }
@@ -1010,10 +388,14 @@
   GLDisplayEGL* display =
       GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
   if (display->GetDisplay() == EGL_NO_DISPLAY) {
-    display = InitializeDisplay(native_display, system_device_id);
-    if (display->GetDisplay() == EGL_NO_DISPLAY)
+    if (!display->InitializeDisplay(native_display))
       return nullptr;
-    InitializeOneOffCommon(display);
+    display->InitializeCommon();
+    if (display->ext->b_EGL_ANGLE_power_preference) {
+      g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver(display);
+      ui::GpuSwitchingManager::GetInstance()->AddObserver(
+          g_egl_gpu_switching_observer);
+    }
   }
   return display;
 }
@@ -1024,102 +406,11 @@
       GLDisplayManagerEGL::GetInstance()->GetDisplay(GpuPreference::kDefault);
   display->SetDisplay(eglGetCurrentDisplay());
   display->ext->InitializeExtensionSettings(display);
-  InitializeOneOffCommon(display);
+  display->InitializeCommon();
   return display;
 }
 
 // static
-void GLSurfaceEGL::InitializeOneOffCommon(GLDisplayEGL* display) {
-  // According to https://source.android.com/compatibility/android-cdd.html the
-  // EGL_IMG_context_priority extension is mandatory for Virtual Reality High
-  // Performance support, but due to a bug in Android Nougat the extension
-  // isn't being reported even when it's present. As a fallback, check if other
-  // related extensions that were added for VR support are present, and assume
-  // that this implies context priority is also supported. See also:
-  // https://github.com/googlevr/gvr-android-sdk/issues/330
-  display->egl_context_priority_supported =
-      display->ext->b_EGL_IMG_context_priority ||
-      (display->ext->b_EGL_ANDROID_front_buffer_auto_refresh &&
-       display->ext->b_EGL_ANDROID_create_native_client_buffer);
-
-  // Check if SurfacelessEGL is supported.
-  display->egl_surfaceless_context_supported =
-      display->ext->b_EGL_KHR_surfaceless_context;
-
-  // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
-  // workaround, since code written for Android WebView takes different paths
-  // based on whether GL surface objects have underlying EGL surface handles,
-  // conflicting with the use of surfaceless. ANGLE can still expose surfacelss
-  // because it is emulated with pbuffers if native support is not present. See
-  // https://crbug.com/382349.
-
-#if BUILDFLAG(IS_ANDROID)
-  // Use the WebGL compatibility extension for detecting ANGLE. ANGLE always
-  // exposes it.
-  bool is_angle = display->ext->b_EGL_ANGLE_create_context_webgl_compatibility;
-  if (!is_angle) {
-    display->egl_surfaceless_context_supported = false;
-  }
-#endif
-
-  if (display->egl_surfaceless_context_supported) {
-    // EGL_KHR_surfaceless_context is supported but ensure
-    // GL_OES_surfaceless_context is also supported. We need a current context
-    // to query for supported GL extensions.
-    scoped_refptr<GLSurface> surface =
-        new SurfacelessEGL(display, gfx::Size(1, 1));
-    scoped_refptr<GLContext> context = InitializeGLContext(
-        new GLContextEGL(nullptr), surface.get(), GLContextAttribs());
-    if (!context || !context->MakeCurrent(surface.get()))
-      display->egl_surfaceless_context_supported = false;
-
-    // Ensure context supports GL_OES_surfaceless_context.
-    if (display->egl_surfaceless_context_supported) {
-      display->egl_surfaceless_context_supported =
-          context->HasExtension("GL_OES_surfaceless_context");
-      context->ReleaseCurrent(surface.get());
-    }
-  }
-
-  // The native fence sync extension is a bit complicated. It's reported as
-  // present for ChromeOS, but Android currently doesn't report this extension
-  // even when it's present, and older devices and Android emulator may export
-  // a useless wrapper function. See crbug.com/775707 for details. In short, if
-  // the symbol is present and we're on Android N or newer and we are not on
-  // Android emulator, assume that it's usable even if the extension wasn't
-  // reported. TODO(https://crbug.com/1086781): Once this is fixed at the
-  // Android level, update the heuristic to trust the reported extension from
-  // that version onward.
-  display->egl_android_native_fence_sync_supported =
-      display->ext->b_EGL_ANDROID_native_fence_sync;
-#if BUILDFLAG(IS_ANDROID)
-  if (!display->egl_android_native_fence_sync_supported &&
-      base::android::BuildInfo::GetInstance()->sdk_int() >=
-          base::android::SDK_VERSION_NOUGAT &&
-      g_driver_egl.fn.eglDupNativeFenceFDANDROIDFn &&
-      base::SysInfo::GetAndroidHardwareEGL() != "swiftshader" &&
-      base::SysInfo::GetAndroidHardwareEGL() != "emulation") {
-    display->egl_android_native_fence_sync_supported = true;
-  }
-#endif
-
-  if (display->ext->b_EGL_ANGLE_power_preference) {
-    g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver(display);
-    ui::GpuSwitchingManager::GetInstance()->AddObserver(
-        g_egl_gpu_switching_observer);
-  }
-}
-
-// static
-bool GLSurfaceEGL::InitializeExtensionSettingsOneOff(GLDisplayEGL* display) {
-  DCHECK(display);
-  if (display->GetDisplay() == EGL_NO_DISPLAY)
-    return false;
-  display->ext->UpdateConditionalExtensionSettings(display);
-  return true;
-}
-
-// static
 void GLSurfaceEGL::ShutdownOneOff(GLDisplayEGL* display) {
   if (!display || display->GetDisplay() == EGL_NO_DISPLAY) {
     return;
@@ -1131,155 +422,12 @@
     delete g_egl_gpu_switching_observer;
     g_egl_gpu_switching_observer = nullptr;
   }
-  angle::ResetPlatform(display->GetDisplay());
-  DCHECK(g_driver_egl.fn.eglTerminateFn);
-  eglTerminate(display->GetDisplay());
-  display->SetDisplay(EGL_NO_DISPLAY);
 
-  display->egl_surfaceless_context_supported = false;
-  display->egl_context_priority_supported = false;
-  display->egl_android_native_fence_sync_supported = false;
+  display->Shutdown();
 }
 
 GLSurfaceEGL::~GLSurfaceEGL() = default;
 
-// InitializeDisplay is necessary because the static binding code
-// needs a full Display init before it can query the Display extensions.
-// static
-GLDisplayEGL* GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform native_display,
-                                              uint64_t system_device_id) {
-  GLDisplayEGL* gl_display =
-      GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
-  if (gl_display->GetDisplay() != EGL_NO_DISPLAY) {
-    return gl_display;
-  }
-
-  gl_display->native_display = native_display;
-
-  bool supports_egl_debug = g_driver_egl.client_ext.b_EGL_KHR_debug;
-  if (supports_egl_debug) {
-    EGLAttrib controls[] = {
-        EGL_DEBUG_MSG_CRITICAL_KHR,
-        EGL_TRUE,
-        EGL_DEBUG_MSG_ERROR_KHR,
-        EGL_TRUE,
-        EGL_DEBUG_MSG_WARN_KHR,
-        EGL_TRUE,
-        EGL_DEBUG_MSG_INFO_KHR,
-        EGL_TRUE,
-        EGL_NONE,
-        EGL_NONE,
-    };
-
-    eglDebugMessageControlKHR(&LogEGLDebugMessage, controls);
-  }
-
-  bool supports_angle_d3d = false;
-  bool supports_angle_opengl = false;
-  bool supports_angle_null = false;
-  bool supports_angle_vulkan = false;
-  bool supports_angle_swiftshader = false;
-  bool supports_angle_egl = false;
-  bool supports_angle_metal = false;
-  // Check for availability of ANGLE extensions.
-  if (g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle) {
-    supports_angle_d3d = g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_d3d;
-    supports_angle_opengl =
-        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_opengl;
-    supports_angle_null =
-        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_null;
-    supports_angle_vulkan =
-        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_vulkan;
-    supports_angle_swiftshader =
-        g_driver_egl.client_ext
-            .b_EGL_ANGLE_platform_angle_device_type_swiftshader;
-    supports_angle_egl = g_driver_egl.client_ext
-                             .b_EGL_ANGLE_platform_angle_device_type_egl_angle;
-    supports_angle_metal =
-        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_metal;
-  }
-
-  bool supports_angle = supports_angle_d3d || supports_angle_opengl ||
-                        supports_angle_null || supports_angle_vulkan ||
-                        supports_angle_swiftshader || supports_angle_metal;
-
-  std::vector<DisplayType> init_displays;
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
-                     supports_angle_null, supports_angle_vulkan,
-                     supports_angle_swiftshader, supports_angle_egl,
-                     supports_angle_metal, command_line, &init_displays);
-
-  std::vector<std::string> enabled_angle_features =
-      GetStringVectorFromCommandLine(command_line,
-                                     switches::kEnableANGLEFeatures);
-  std::vector<std::string> disabled_angle_features =
-      GetStringVectorFromCommandLine(command_line,
-                                     switches::kDisableANGLEFeatures);
-
-  bool disable_all_angle_features =
-      command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds);
-
-  for (size_t disp_index = 0; disp_index < init_displays.size(); ++disp_index) {
-    DisplayType display_type = init_displays[disp_index];
-    EGLDisplay egl_display = GetDisplayFromType(
-        display_type, gl_display, enabled_angle_features,
-        disabled_angle_features, disable_all_angle_features, system_device_id);
-    if (egl_display == EGL_NO_DISPLAY) {
-      LOG(ERROR) << "EGL display query failed with error "
-                 << GetLastEGLErrorString();
-    }
-
-    // Init ANGLE platform now that we have the global display.
-    if (supports_angle) {
-      if (!angle::InitializePlatform(egl_display)) {
-        LOG(ERROR) << "ANGLE Platform initialization failed.";
-      }
-
-      SetANGLEImplementation(
-          GetANGLEImplementationFromDisplayType(display_type));
-    }
-
-    // The platform may need to unset its platform specific display env in case
-    // of vulkan if the platform doesn't support Vulkan surface.
-    absl::optional<base::ScopedEnvironmentVariableOverride> unset_display;
-    if (display_type == ANGLE_VULKAN) {
-      unset_display = GLDisplayEglUtil::GetInstance()
-                          ->MaybeGetScopedDisplayUnsetForVulkan();
-    }
-
-    if (!eglInitialize(egl_display, nullptr, nullptr)) {
-      bool is_last = disp_index == init_displays.size() - 1;
-
-      LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
-                 << " failed with error " << GetLastEGLErrorString()
-                 << (is_last ? "" : ", trying next display type");
-      continue;
-    }
-
-    std::ostringstream display_type_string;
-    auto gl_implementation = GetGLImplementationParts();
-    display_type_string << GetGLImplementationGLName(gl_implementation);
-    if (gl_implementation.gl == kGLImplementationEGLANGLE) {
-      display_type_string << ":" << DisplayTypeString(display_type);
-    }
-
-    static auto* egl_display_type_key = base::debug::AllocateCrashKeyString(
-        "egl-display-type", base::debug::CrashKeySize::Size32);
-    base::debug::SetCrashKeyString(egl_display_type_key,
-                                   display_type_string.str());
-
-    UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
-                              DISPLAY_TYPE_MAX);
-    gl_display->SetDisplay(egl_display);
-    gl_display->display_type = display_type;
-    gl_display->ext->InitializeExtensionSettings(gl_display);
-    break;
-  }
-
-  return gl_display;
-}
-
 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(
     GLDisplayEGL* display,
     EGLNativeWindowType window,
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 8b24400..ffb507c 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -33,16 +33,6 @@
 
 class GLSurfacePresentationHelper;
 
-GL_EXPORT void GetEGLInitDisplays(bool supports_angle_d3d,
-                                  bool supports_angle_opengl,
-                                  bool supports_angle_null,
-                                  bool supports_angle_vulkan,
-                                  bool supports_angle_swiftshader,
-                                  bool supports_angle_egl,
-                                  bool supports_angle_metal,
-                                  const base::CommandLine* command_line,
-                                  std::vector<DisplayType>* init_displays);
-
 // Interface for EGL surface.
 class GL_EXPORT GLSurfaceEGL : public GLSurface {
  public:
@@ -69,12 +59,7 @@
   static GLDisplayEGL* InitializeOneOff(EGLDisplayPlatform native_display,
                                         uint64_t system_device_id);
   static GLDisplayEGL* InitializeOneOffForTesting();
-  static bool InitializeExtensionSettingsOneOff(GLDisplayEGL* display);
   static void ShutdownOneOff(GLDisplayEGL* display);
-  // |system_device_id| specifies which GPU to use on a multi-GPU system.
-  // If its value is 0, use the default GPU of the system.
-  static GLDisplayEGL* InitializeDisplay(EGLDisplayPlatform native_display,
-                                         uint64_t system_device_id);
 
  protected:
   ~GLSurfaceEGL() override;
@@ -82,9 +67,6 @@
   EGLConfig config_ = nullptr;
   GLSurfaceFormat format_;
   raw_ptr<GLDisplayEGL> display_ = nullptr;
-
- private:
-  static void InitializeOneOffCommon(GLDisplayEGL* display);
 };
 
 // Encapsulates an EGL surface bound to a view.
diff --git a/ui/gl/gl_surface_egl_x11_gles2.cc b/ui/gl/gl_surface_egl_x11_gles2.cc
index 4133662..eebd999e 100644
--- a/ui/gl/gl_surface_egl_x11_gles2.cc
+++ b/ui/gl/gl_surface_egl_x11_gles2.cc
@@ -94,7 +94,7 @@
                                EGL_NONE};
     config_attribs[kBufferSizeOffset] = geometry->depth;
 
-    EGLDisplay display = GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+    EGLDisplay display = GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
     x11::VisualId visual_id;
     ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
         true, &visual_id, nullptr, nullptr, nullptr);
diff --git a/ui/gl/test/egl_initialization_displays_unittest.cc b/ui/gl/test/egl_initialization_displays_unittest.cc
index b0d34ba..7a2f4e80 100644
--- a/ui/gl/test/egl_initialization_displays_unittest.cc
+++ b/ui/gl/test/egl_initialization_displays_unittest.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_display.h"
+#include "ui/gl/gl_switches.h"
 
 namespace {
 
@@ -17,8 +19,8 @@
   // using --disable-d3d11 with the default --use-angle should never return
   // D3D11.
   command_line->AppendSwitch(switches::kDisableD3D11);
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_FALSE(base::Contains(displays, gl::ANGLE_D3D11));
 
   // Specifically requesting D3D11 should always return it if the extension is
@@ -26,16 +28,16 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationD3D11Name);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_D3D11));
   EXPECT_EQ(displays.size(), 1u);
 
   // Specifically requesting D3D11 should not return D3D11 if the extension is
   // not available
   displays.clear();
-  GetEGLInitDisplays(false, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(false, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_FALSE(base::Contains(displays, gl::ANGLE_D3D11));
 }
 
@@ -45,16 +47,16 @@
 
   // Default without --use-angle flag
   std::vector<gl::DisplayType> default_no_flag_displays;
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &default_no_flag_displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &default_no_flag_displays);
   EXPECT_FALSE(default_no_flag_displays.empty());
 
   // Default with --use-angle flag
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationDefaultName);
   std::vector<gl::DisplayType> default_with_flag_displays;
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &default_with_flag_displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &default_with_flag_displays);
   EXPECT_FALSE(default_with_flag_displays.empty());
 
   // Make sure the same results are returned
@@ -71,8 +73,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationOpenGLName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_OPENGL));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -80,8 +82,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationOpenGLESName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_OPENGLES));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -89,8 +91,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationNullName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_NULL));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -98,8 +100,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationVulkanName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_VULKAN));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -107,8 +109,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationSwiftShaderName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_SWIFTSHADER));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -116,8 +118,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationOpenGLEGLName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_OPENGL_EGL));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -125,8 +127,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationOpenGLESEGLName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_OPENGLES_EGL));
   EXPECT_EQ(displays.size(), 1u);
 
@@ -134,8 +136,8 @@
   command_line->AppendSwitchASCII(switches::kUseANGLE,
                                   gl::kANGLEImplementationMetalName);
   displays.clear();
-  GetEGLInitDisplays(true, true, true, true, true, true, true,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(true, true, true, true, true, true, true,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::ANGLE_METAL));
   EXPECT_EQ(displays.size(), 1u);
 }
@@ -146,8 +148,8 @@
 
   // With no angle platform extensions, only DEFAULT should be available
   std::vector<gl::DisplayType> displays;
-  GetEGLInitDisplays(false, false, false, false, false, false, false,
-                     command_line.get(), &displays);
+  GetEGLInitDisplaysForTesting(false, false, false, false, false, false, false,
+                               command_line.get(), &displays);
   EXPECT_TRUE(base::Contains(displays, gl::DEFAULT));
   EXPECT_EQ(displays.size(), 1u);
 }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
index a71b56c..0f43dda 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc
@@ -16,6 +16,7 @@
 #ifndef EGL_ANGLE_platform_angle
 #define EGL_ANGLE_platform_angle 1
 #define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348F
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
 #endif /* EGL_ANGLE_platform_angle */
 
 #ifndef EGL_ANGLE_platform_angle_vulkan
@@ -23,9 +24,21 @@
 #define EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE 0x34A5
 #endif /* EGL_ANGLE_platform_angle_vulkan */
 
+#ifndef EGL_ANGLE_platform_angle_device_type_egl_angle
+#define EGL_ANGLE_platform_angle_device_type_egl_angle
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE 0x348E
+#endif /* EGL_ANGLE_platform_angle_device_type_egl_angle */
+
+#ifndef EGL_ANGLE_platform_angle_opengl
+#define EGL_ANGLE_platform_angle_opengl 1
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
+#endif /* EGL_ANGLE_platform_angle_opengl */
+
 namespace ui {
 
 WaylandGLEGLUtility::WaylandGLEGLUtility() = default;
+
 WaylandGLEGLUtility::~WaylandGLEGLUtility() = default;
 
 void WaylandGLEGLUtility::GetAdditionalEGLAttributes(
@@ -40,6 +53,17 @@
         EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE);
     return;
   }
+
+  if (std::find(display_attributes->begin(), display_attributes->end(),
+                EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE) !=
+          display_attributes->end() ||
+      std::find(display_attributes->begin(), display_attributes->end(),
+                EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) !=
+          display_attributes->end()) {
+    display_attributes->push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
+    display_attributes->push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE);
+    return;
+  }
 }
 
 void WaylandGLEGLUtility::ChooseEGLAlphaAndBufferSize(EGLint* alpha_size,
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
index 5ba93b8..1e135da 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -153,8 +153,14 @@
   if (egl_implementation_) {
     impls.emplace_back(
         gl::GLImplementationParts(gl::kGLImplementationEGLGLES2));
+    // Add only supported ANGLE implementations. Otherwise, angle-vulkan might
+    // be requested, which is not supported with this backend yet.
     impls.emplace_back(
         gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader));
+    impls.emplace_back(
+        gl::GLImplementationParts(gl::ANGLEImplementation::kOpenGL));
+    impls.emplace_back(
+        gl::GLImplementationParts(gl::ANGLEImplementation::kOpenGLES));
   }
   return impls;
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 4f46477d..923dad6 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -659,12 +659,6 @@
   if (AsWaylandPopup())
     return;
 
-  // Notify normal window's delegate only as updating the pixel bounds
-  // may close the popup, and popup will not usually enter new display.
-  // TODO(crbug.com/1306688): Revisit this when wayland implementation
-  // is switced to dip based.
-  delegate()->OnMovedToAnotherDisplay();
-
   UpdateWindowScale(true);
 }
 
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.cc b/ui/ozone/platform/x11/x11_screen_ozone.cc
index 53265ab5..9696057 100644
--- a/ui/ozone/platform/x11/x11_screen_ozone.cc
+++ b/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -56,8 +56,12 @@
     return GetPrimaryDisplay();
 
   X11Window* window = window_manager_->GetWindow(widget);
-  if (window)
-    return GetDisplayMatching(window->GetBoundsInDIP());
+  if (window) {
+    // TODO(crbug.com/1306688): Change to use GetBoundsInDIP();
+    gfx::Rect bounds_dip = gfx::ToEnclosingRect(gfx::ConvertRectToDips(
+        window->GetBoundsInPixels(), GetXDisplayScaleFactor()));
+    return GetDisplayMatching(bounds_dip);
+  }
   return GetPrimaryDisplay();
 }
 
diff --git a/ui/platform_window/platform_window_delegate.cc b/ui/platform_window/platform_window_delegate.cc
index 786619c7..ea10ab5 100644
--- a/ui/platform_window/platform_window_delegate.cc
+++ b/ui/platform_window/platform_window_delegate.cc
@@ -55,8 +55,6 @@
   return rect_in_dip;
 }
 
-void PlatformWindowDelegate::OnMovedToAnotherDisplay() {}
-
 gfx::Rect PlatformWindowDelegate::ConvertRectToDIP(
     const gfx::Rect& rect_in_pixels) const {
   return rect_in_pixels;
diff --git a/ui/platform_window/platform_window_delegate.h b/ui/platform_window/platform_window_delegate.h
index e1f168b..1bae07b 100644
--- a/ui/platform_window/platform_window_delegate.h
+++ b/ui/platform_window/platform_window_delegate.h
@@ -140,9 +140,6 @@
   // Enables or disables frame rate throttling.
   virtual void SetFrameRateThrottleEnabled(bool enabled);
 
-  // Called when the platform window is moved to another display.
-  virtual void OnMovedToAnotherDisplay();
-
   // Convert gfx::Rect in pixels to DIP in screen, and vice versa.
   virtual gfx::Rect ConvertRectToPixels(const gfx::Rect& rect_in_dp) const;
   virtual gfx::Rect ConvertRectToDIP(const gfx::Rect& rect_in_pixells) const;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index c0e3f75..f6d94f2 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -774,8 +774,20 @@
 }
 
 gfx::Transform DesktopWindowTreeHostPlatform::GetRootTransform() const {
+  // TODO(crbug.com/1306688): This can use wrong scale during initialization.
+  // Revisit this as a part of 'use dip' work.
+
+  display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
+  // This might be called before the |platform_window| is created. Thus,
+  // explicitly check if that exists before trying to access its visibility and
+  // the display where it is shown.
+  if (platform_window())
+    display = GetDisplayNearestRootWindow();
+  else if (window_parent_)
+    display = window_parent_->GetDisplayNearestRootWindow();
   gfx::Transform transform;
-  transform.Scale(device_scale_factor(), device_scale_factor());
+  float scale = display.device_scale_factor();
+  transform.Scale(scale, scale);
   return transform;
 }
 
@@ -895,10 +907,6 @@
   return window_anchor;
 }
 
-void DesktopWindowTreeHostPlatform::OnMovedToAnotherDisplay() {
-  WindowTreeHost::OnHostResizedInPixels(GetBoundsInPixels().size());
-}
-
 gfx::Rect DesktopWindowTreeHostPlatform::ConvertRectToPixels(
     const gfx::Rect& rect_in_dip) const {
   return ToPixelRect(rect_in_dip);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 505fc97..cbf0abe 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -153,7 +153,6 @@
   absl::optional<ui::MenuType> GetMenuType() override;
   absl::optional<ui::OwnedWindowAnchor> GetOwnedWindowAnchorAndRectInPx()
       override;
-  void OnMovedToAnotherDisplay() override;
   gfx::Rect ConvertRectToPixels(const gfx::Rect& rect_in_dip) const override;
   gfx::Rect ConvertRectToDIP(const gfx::Rect& rect_in_pixels) const override;
   gfx::PointF ConvertScreenPointToLocalDIP(