diff --git a/DEPS b/DEPS
index 1d75bec..beab6de 100644
--- a/DEPS
+++ b/DEPS
@@ -283,15 +283,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b03f278925c6754bdb7a37feae315214b4cc604b',
+  'angle_revision': '5a2cc71c2878ec92be0786c4b0dd038ed4ccf349',
   # 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': '466e443100e66ca7b5df3385ad3bba4fa8bf90f0',
+  'swiftshader_revision': '1bf3ae22a00dc10005886b1d9e58b6159a1e392a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '73c09241bb432ca957bd66555304c5c2b4c9d47c',
+  'pdfium_revision': '110d134c7aef79bb24df6432568172c6076351aa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -346,7 +346,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'fba169d2a9c1f9d16e536eb663ce1fade42ad1bd',
+  'catapult_revision': '1cac3deac84072df4ef5b65c676e619543349a51',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -354,7 +354,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': 'c11af60fb020f514bcbed1177066378819b0828d',
+  'devtools_frontend_revision': '5c04ae509b388530fbe5574b56922448f2b867b2',
   # 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.
@@ -390,7 +390,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': 'e9f8b09063742796695b400a667d44e7260ade6d',
+  'dawn_revision': 'b1d5bc8418bcea98e3227eae00b1a1a237281366',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -920,7 +920,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'TFxpdey4vNeM1KsMbFcQX_jgFBdyUkLPbaCPTqbS77IC',
+          'version': 'M3UVOXjeT-PmTSnZQgUH8_jIRCw3KnvzsroL57LOZagC',
       },
     ],
     'condition': 'checkout_android',
@@ -1136,7 +1136,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e1197f06a8f45c0328d341b30e337d3a4b609716',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5965d3e6fbe0cfc32dcee5a95559f3a8ebdc1228',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1516,7 +1516,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'b4283729c944a55837024e0d70f1482647541d18',
+    Var('chromium_git') + '/openscreen' + '@' + 'dd0f1516b427340e0676675dac9f146deb0d0b1a',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@@ -1708,7 +1708,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'd275c5e1e31566ca21c5ba48cac7706d0d45728a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '80a860532e120bb8ca7bfb088672c6dc53281a80',
+    Var('webrtc_git') + '/src.git' + '@' + 'bccb452eb6acdd0ebeeee2ded284ef3a3279c19c',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1781,7 +1781,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6edeb858b567bffff13a5b37f846bfa38013c054',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e401adfe8456152a4b553c5404e3c383c8bf0c59',
     'condition': 'checkout_src_internal',
   },
 
@@ -1822,7 +1822,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'n_-s6AHGojfZHBSb-a6B7uW3aAIRgNqEB6mpNU6He4QC',
+        'version': 'bOB8ZIQURW8tw81GZjGHvVeauEyHYn160cqlKL-TDO4C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1833,7 +1833,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'Ngb5o5UWP8i8lD1N151CemqExqW0n-qsynp-NXtckmwC',
+        'version': 'bMlGFBW6vXhcbG22vzqhs12pjg7SUUfG8Dowh9Xd57oC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 9b29580b..5d8da871 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -69,15 +69,18 @@
   }
 }
 
-# This version of the WebView APK doesn't include WebLayer java and resources.
+# This version of the WebView APK doesn't include WebLayer.
 # It's used to define the allowlist of resources to be pulled out of language
 # splits. See |shared_resources_allowlist_target|.
 standalone_system_webview_apk_tmpl("system_webview_no_weblayer_apk") {
   exclude_weblayer_java = true
   apk_name = "SystemWebViewNoWebLayer"
 
+  # Don't include any code to speed up compilation. This is used only for the
+  # resources allowlist.
   include_32_bit_webview = false
   include_64_bit_webview = false
+  omit_dex = true
 
   # Adding deps on recycler view in the base WebView APK will end up keeping the
   # Java in the base APK instead of the WebLayer DFM, even though it is not
@@ -787,6 +790,7 @@
     "java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java",
     "java/src/org/chromium/android_webview/common/SafeModeAction.java",
     "java/src/org/chromium/android_webview/common/SafeModeController.java",
+    "java/src/org/chromium/android_webview/common/services/ServiceHelper.java",
     "java/src/org/chromium/android_webview/common/services/ServiceNames.java",
   ]
   deps = [
diff --git a/android_webview/browser/network_service/aw_proxy_config_monitor.cc b/android_webview/browser/network_service/aw_proxy_config_monitor.cc
index f64506fe..b6f06746 100644
--- a/android_webview/browser/network_service/aw_proxy_config_monitor.cc
+++ b/android_webview/browser/network_service/aw_proxy_config_monitor.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/no_destructor.h"
 #include "base/trace_event/trace_event.h"
+#include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -54,6 +55,7 @@
 }  // namespace
 
 AwProxyConfigMonitor::AwProxyConfigMonitor() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   TRACE_EVENT0("startup", "AwProxyConfigMonitor");
   proxy_config_service_android_ =
       std::make_unique<net::ProxyConfigServiceAndroid>(
diff --git a/android_webview/java/src/org/chromium/android_webview/common/services/ServiceHelper.java b/android_webview/java/src/org/chromium/android_webview/common/services/ServiceHelper.java
new file mode 100644
index 0000000..1367a7f
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/common/services/ServiceHelper.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.android_webview.common.services;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.ReceiverCallNotAllowedException;
+import android.content.ServiceConnection;
+
+/**
+ * Helper methods for working with Services in WebView.
+ */
+public class ServiceHelper {
+    /**
+     * Connects to a Service specified by {@code intent} with {@code flags}. This handles edge cases
+     * such as attempting to bind from restricted BroadcastReceiver Contexts.
+     *
+     * @param context the Context to use when binding to the Service.
+     * @param intent should specify a Service.
+     * @param serviceConnection a ServiceConnection object.
+     * @param flags should be {@code 0} or a combination of {@code Context#BIND_*}.
+     */
+    public static boolean bindService(
+            Context context, Intent intent, ServiceConnection serviceConnection, int flags) {
+        try {
+            return context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+        } catch (ReceiverCallNotAllowedException e) {
+            // If we're running in a BroadcastReceiver Context then we cannot bind to Services.
+            return false;
+        }
+    }
+
+    private ServiceHelper() {}
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index 89c1c3c6..fffc7729 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisableIf;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.MessagePort;
 import org.chromium.content_public.browser.SelectionPopupController;
@@ -395,7 +396,7 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.Q, message = "https://crbug.com/1251900")
+    @DisabledTest(message = "https://crbug.com/1331093")
     public void testPopupWindowHasUserGestureForUserInitiatedNoOpener() throws Throwable {
         runPopupUserGestureTest(false);
     }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index cdd9ff79..c4520c5 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -383,11 +383,10 @@
   logging::CloseLogFile();
 }
 
-bool AwMainDelegate::ShouldCreateFeatureList() {
-  // TODO(https://crbug.com/887468): Move the creation of FeatureList from
-  // AwBrowserMainParts::PreCreateThreads() to
+bool AwMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
+  // In the browser process the FeatureList is created in
   // AwMainDelegate::PostEarlyInitialization().
-  return false;
+  return invoked_in == InvokedIn::kChildProcess;
 }
 
 variations::VariationsIdsProvider*
@@ -396,23 +395,20 @@
       variations::VariationsIdsProvider::Mode::kDontSendSignedInVariations);
 }
 
-// This function is called only on the browser process.
-void AwMainDelegate::PostEarlyInitialization(bool is_running_tests) {
-  InitIcuAndResourceBundleBrowserSide();
-  aw_feature_list_creator_->CreateFeatureListAndFieldTrials();
-  PostFieldTrialInitialization();
-}
+void AwMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
+  const bool is_browser_process = invoked_in != InvokedIn::kChildProcess;
+  if (is_browser_process) {
+    InitIcuAndResourceBundleBrowserSide();
+    aw_feature_list_creator_->CreateFeatureListAndFieldTrials();
+  }
 
-void AwMainDelegate::PostFieldTrialInitialization() {
   version_info::Channel channel = version_info::android::GetChannel();
-  [[maybe_unused]] bool is_canary_dev =
+  [[maybe_unused]] const bool is_canary_dev =
       (channel == version_info::Channel::CANARY ||
        channel == version_info::Channel::DEV);
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  std::string process_type =
-      command_line.GetSwitchValueASCII(switches::kProcessType);
-  [[maybe_unused]] bool is_browser_process = process_type.empty();
+  [[maybe_unused]] const std::string process_type =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kProcessType);
 
 #if BUILDFLAG(ENABLE_GWP_ASAN_MALLOC)
   gwp_asan::EnableForMalloc(is_canary_dev || is_browser_process,
diff --git a/android_webview/lib/aw_main_delegate.h b/android_webview/lib/aw_main_delegate.h
index 756da29..1d9a0b2 100644
--- a/android_webview/lib/aw_main_delegate.h
+++ b/android_webview/lib/aw_main_delegate.h
@@ -43,10 +43,9 @@
       const std::string& process_type,
       content::MainFunctionParams main_function_params) override;
   void ProcessExiting(const std::string& process_type) override;
-  bool ShouldCreateFeatureList() override;
+  bool ShouldCreateFeatureList(InvokedIn invoked_in) override;
   variations::VariationsIdsProvider* CreateVariationsIdsProvider() override;
-  void PostEarlyInitialization(bool is_running_tests) override;
-  void PostFieldTrialInitialization() override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
   content::ContentClient* CreateContentClient() override;
   content::ContentBrowserClient* CreateContentBrowserClient() override;
   content::ContentGpuClient* CreateContentGpuClient() override;
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwNonembeddedUmaRecorder.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwNonembeddedUmaRecorder.java
index b7d5a686..45326146 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwNonembeddedUmaRecorder.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwNonembeddedUmaRecorder.java
@@ -15,6 +15,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.android_webview.common.services.IMetricsBridgeService;
+import org.chromium.android_webview.common.services.ServiceHelper;
 import org.chromium.android_webview.common.services.ServiceNames;
 import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord;
 import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord.Metadata;
@@ -222,7 +223,8 @@
         final Context appContext = ContextUtils.getApplicationContext();
         final Intent intent = new Intent();
         intent.setClassName(appContext, mRecordingDelegate.getServiceName());
-        mIsBound = appContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        mIsBound = ServiceHelper.bindService(
+                appContext, intent, mServiceConnection, Context.BIND_AUTO_CREATE);
         if (!mIsBound) {
             Log.w(TAG, "Could not bind to MetricsBridgeService " + intent);
         }
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 86f8504..8b3da5cb 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -45,6 +45,8 @@
                              "include_64_bit_webview",
                            ])
 
+    _omit_dex = defined(omit_dex) && omit_dex
+
     deps += [
       "//android_webview:locale_pak_assets",
       "//android_webview:pak_file_assets",
@@ -80,7 +82,9 @@
       }
     }
 
-    product_config_java_packages = [ webview_product_config_java_package ]
+    if (!_omit_dex) {
+      product_config_java_packages = [ webview_product_config_java_package ]
+    }
 
     if (webview_includes_weblayer) {
       if (_is_bundle_module) {
@@ -88,7 +92,9 @@
       } else {
         deps += [ "//weblayer:locale_pak_assets" ]
       }
-      product_config_java_packages += [ weblayer_product_config_java_package ]
+      if (!_omit_dex) {
+        product_config_java_packages += [ weblayer_product_config_java_package ]
+      }
     }
 
     if (!defined(alternative_android_sdk_dep)) {
@@ -106,14 +112,18 @@
         "If trichrome library is used, static_library_provider must be set " +
             "so that a dep can be added on the library APK.")
 
+    _include_32_bit_webview = !defined(invoker.include_32_bit_webview) ||
+                              invoker.include_32_bit_webview
+    if (android_64bit_target_cpu) {
+      _include_64_bit_webview = !defined(invoker.include_64_bit_webview) ||
+                                invoker.include_64_bit_webview
+    }
+
     # Pure 32-bit implies a 32-bit only Webview built on a 64-bit configuration.
-    _pure_32_bit =
-        android_64bit_target_cpu && defined(invoker.include_64_bit_webview) &&
-        !invoker.include_64_bit_webview
-    _pure_64_bit =
-        android_64bit_target_cpu && defined(invoker.include_32_bit_webview) &&
-        !invoker.include_32_bit_webview
+    _pure_32_bit = android_64bit_target_cpu && !_include_64_bit_webview
+    _pure_64_bit = android_64bit_target_cpu && !_include_32_bit_webview
     not_needed([
+                 "_include_32_bit_webview",
                  "_pure_32_bit",
                  "_pure_64_bit",
                ])
@@ -125,7 +135,8 @@
     if (!_use_trichrome_library) {
       shared_resources = true
 
-      if (!android_64bit_target_cpu || !_pure_32_bit) {
+      if ((!android_64bit_target_cpu && _include_32_bit_webview) ||
+          (android_64bit_target_cpu && !_pure_32_bit)) {
         shared_libraries = [ "//android_webview:libwebviewchromium" ]
         _include_primary_support = true
       }
@@ -143,16 +154,26 @@
       if (android_64bit_target_cpu) {
         if (invoker.is_64_bit_browser) {
           native_lib_placeholders = [ "libdummy.so" ]
-          if (invoker.include_32_bit_webview) {
+          if (_include_32_bit_webview) {
             secondary_abi_shared_libraries = [ "//android_webview:monochrome_64($android_secondary_abi_toolchain)" ]
             _include_secondary_support = true
           }
         } else {
-          if (invoker.include_64_bit_webview) {
+          if (_include_64_bit_webview) {
             shared_libraries = [ "//android_webview:monochrome" ]
             _include_primary_support = true
           }
           secondary_native_lib_placeholders = [ "libdummy.so" ]
+          static_library_provider_use_secondary_abi = true
+        }
+
+        # http://crbug.com/1042107.
+        if (is_component_build) {
+          if (invoker.is_64_bit_browser) {
+            main_component_library = "libmonochrome_64.cr.so"
+          } else {
+            main_component_library = "libmonochrome.cr.so"
+          }
         }
       } else {
         native_lib_placeholders = [ "libdummy.so" ]
@@ -246,7 +267,7 @@
       command_line_flags_file = "webview-command-line"
     }
 
-    if (!is_java_debug) {
+    if (!is_java_debug && !_omit_dex) {
       proguard_enabled = true
       if (!defined(proguard_configs)) {
         proguard_configs = []
@@ -263,13 +284,13 @@
       if (_use_trichrome_library) {
         if (android_64bit_target_cpu) {
           if (invoker.is_64_bit_browser) {
-            if (invoker.include_32_bit_webview) {
+            if (_include_32_bit_webview) {
               version_code = trichrome_64_32_version_code
             } else {
               version_code = trichrome_64_version_code
             }
           } else {
-            if (invoker.include_64_bit_webview) {
+            if (_include_64_bit_webview) {
               version_code = trichrome_32_64_version_code
             } else {
               version_code = trichrome_32_version_code
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index d43bedf..660aef5 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -28,6 +28,7 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/projector/projector_controller_impl.h"
+#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
@@ -250,11 +251,10 @@
       display::Screen::GetScreen()->GetDisplayNearestWindow(
           GetPreferredRootWindow());
   const float device_scale_factor = display.device_scale_factor();
-  // TODO: Adjust the icon color after spec is updated.
-  const gfx::ImageSkia icon = gfx::CreateVectorIcon(
-      capture_image ? kCaptureModeImageIcon : kCaptureModeVideoIcon,
-      SK_ColorBLACK);
-  SkBitmap bitmap = *icon.bitmap();
+  const gfx::ImageSkia* icon =
+      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+          capture_image ? IDR_CAPTURE_IMAGE_CURSOR : IDR_CAPTURE_VIDEO_CURSOR);
+  SkBitmap bitmap = *icon->bitmap();
   gfx::Point hotspot(bitmap.width() / 2, bitmap.height() / 2);
   aura::ScaleAndRotateCursorBitmapAndHotpoint(
       device_scale_factor, display.panel_rotation(), &bitmap, &hotspot);
@@ -1364,8 +1364,8 @@
   const CaptureModeSource source = controller_->source();
   if (source == CaptureModeSource::kWindow && !GetSelectedWindow()) {
     // If we're in window capture mode and there is no select window at the
-    // moment, we should use the original mouse.
-    cursor_setter_->ResetCursor();
+    // moment, we should use a pointer cursor.
+    cursor_setter_->UpdateCursor(ui::mojom::CursorType::kPointer);
     return;
   }
 
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc
index 7f1a715..4c8725c 100644
--- a/ash/capture_mode/capture_mode_unittests.cc
+++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -1464,11 +1464,11 @@
   CaptureModeSessionTestApi test_api(controller->capture_mode_session());
   EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
 
-  // If the mouse is not above the window, use the original mouse cursor.
+  // If the mouse is not above the window, use a pointer.
   event_generator->MoveMouseTo(gfx::Point(300, 300));
-  EXPECT_FALSE(cursor_manager->IsCursorLocked());
+  EXPECT_TRUE(cursor_manager->IsCursorLocked());
   EXPECT_TRUE(cursor_manager->IsCursorVisible());
-  EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
+  EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
 
   // Use pointer mouse if the event is on the capture bar.
   ClickOnView(GetVideoToggleButton(), event_generator);
@@ -1486,9 +1486,9 @@
 
   // If the mouse is not above the window, use the original mouse cursor.
   event_generator->MoveMouseTo(gfx::Point(300, 300));
-  EXPECT_FALSE(cursor_manager->IsCursorLocked());
+  EXPECT_TRUE(cursor_manager->IsCursorLocked());
   EXPECT_TRUE(cursor_manager->IsCursorVisible());
-  EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
+  EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
 
   // Move above the window again, the cursor should change back to the video
   // record icon.
@@ -1552,11 +1552,11 @@
   EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
 
   // Destroy the window while hovering. There is no window underneath, so it
-  // should revert back to the original cursor.
+  // should revert back to a pointer.
   window2.reset();
-  EXPECT_FALSE(cursor_manager->IsCursorLocked());
+  EXPECT_TRUE(cursor_manager->IsCursorLocked());
   EXPECT_TRUE(cursor_manager->IsCursorVisible());
-  EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
+  EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
 
   // Destroy the window while mouse is in a pressed state. Cursor should revert
   // back to the original cursor.
diff --git a/ash/display/screen_ash.cc b/ash/display/screen_ash.cc
index 6400703a..e3ead6a 100644
--- a/ash/display/screen_ash.cc
+++ b/ash/display/screen_ash.cc
@@ -42,6 +42,7 @@
       : display_list_(screen_ash->GetAllDisplays()),
         primary_display_(screen_ash->GetPrimaryDisplay()) {
     SetDisplayForNewWindows(primary_display_.id());
+    set_shutdown(true);
   }
 
   ScreenForShutdown(const ScreenForShutdown&) = delete;
diff --git a/ash/public/cpp/resources/ash_public_unscaled_resources.grd b/ash/public/cpp/resources/ash_public_unscaled_resources.grd
index ef41bb09..7c776f3 100644
--- a/ash/public/cpp/resources/ash_public_unscaled_resources.grd
+++ b/ash/public/cpp/resources/ash_public_unscaled_resources.grd
@@ -14,6 +14,9 @@
   </outputs>
   <release seq="1">
     <includes>
+      <!-- Capture Mode custom cursor images -->
+      <include name="IDR_CAPTURE_IMAGE_CURSOR" file="unscaled_resources/capture_image_cursor.png" type="BINDATA" />
+      <include name="IDR_CAPTURE_VIDEO_CURSOR" file="unscaled_resources/capture_video_cursor.png" type="BINDATA" />
       <!-- CrOS internal apps images -->
       <include name="IDR_SHORTCUT_VIEWER_LOGO_192" file="unscaled_resources/shortcut_viewer_logo_192.png" type="BINDATA" />
       <include name="IDR_SETTINGS_LOGO_192" file="unscaled_resources/settings_logo_192.png" type="BINDATA" />
diff --git a/ash/public/cpp/resources/unscaled_resources/capture_image_cursor.png b/ash/public/cpp/resources/unscaled_resources/capture_image_cursor.png
new file mode 100644
index 0000000..4ec23ea2
--- /dev/null
+++ b/ash/public/cpp/resources/unscaled_resources/capture_image_cursor.png
Binary files differ
diff --git a/ash/public/cpp/resources/unscaled_resources/capture_video_cursor.png b/ash/public/cpp/resources/unscaled_resources/capture_video_cursor.png
new file mode 100644
index 0000000..ec1e246
--- /dev/null
+++ b/ash/public/cpp/resources/unscaled_resources/capture_video_cursor.png
Binary files differ
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 645e41a..48ad749 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -119,7 +119,8 @@
     "ksv_search_back.icon",
     "ksv_search_bar.icon",
     "ksv_search_close.icon",
-    "ksv_search_no_result.icon",
+    "ksv_search_no_result_dark.icon",
+    "ksv_search_no_result_light.icon",
     "ksv_separator_plus.icon",
     "ksv_snapshot.icon",
     "ksv_volume_down.icon",
diff --git a/ash/resources/vector_icons/ksv_search_no_result_dark.icon b/ash/resources/vector_icons/ksv_search_no_result_dark.icon
new file mode 100644
index 0000000..6973cf34
--- /dev/null
+++ b/ash/resources/vector_icons/ksv_search_no_result_dark.icon
@@ -0,0 +1,118 @@
+// 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.
+
+CANVAS_DIMENSIONS, 300,
+MOVE_TO, 221.16f, 98,
+H_LINE_TO, 76.93f,
+R_CUBIC_TO, -9.92f, 0, -17.94f, 8.1f, -17.94f, 18,
+R_LINE_TO, -0.09f, 90,
+R_CUBIC_TO, 0, 9.9f, 8.11f, 18, 18.03f, 18,
+R_H_LINE_TO, 144.23f,
+R_CUBIC_TO, 9.91f, 0, 18.03f, -8.1f, 18.03f, -18,
+R_V_LINE_TO, -90,
+R_CUBIC_TO, 0, -9.9f, -8.11f, -18, -18.03f, -18,
+CLOSE,
+NEW_PATH,
+STROKE, 4.507f,
+MOVE_TO, 245.94f, 76.25f,
+R_LINE_TO, 3.87f, -14.16f,
+CLOSE,
+NEW_PATH,
+STROKE, 4.507f,
+MOVE_TO, 260.35f, 90.53f,
+R_LINE_TO, 12.9f, -6.01f,
+CLOSE,
+NEW_PATH,
+STROKE, 4.507f,
+MOVE_TO, 263.36f, 113.62f,
+R_LINE_TO, 13.76f, 5.75f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x20, 0x21, 0x24,
+MOVE_TO, 162, 178,
+R_CUBIC_TO, 0, -6.63f, -5.37f, -12, -12, -12,
+R_CUBIC_TO, -6.63f, 0, -12, 5.37f, -12, 12,
+R_CUBIC_TO, 0, 0.12f, 24, 0.09f, 24, 0,
+CLOSE,
+CIRCLE, 104, 150, 9,
+CIRCLE, 196, 150, 9,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 243.69f, 213,
+R_H_LINE_TO, -3.58f,
+R_LINE_TO, -1.24f, -1.24f,
+R_ARC_TO, 28.95f, 28.95f, 0, 0, 0, 7.08f, -19.01f,
+R_CUBIC_TO, 0, -16.15f, -13.12f, -29.25f, -29.3f, -29.25f,
+R_CUBIC_TO, -16.18f, 0, -29.3f, 13.1f, -29.3f, 29.25f,
+CUBIC_TO_SHORTHAND, 200.47f, 222, 216.65f, 222,
+R_ARC_TO, 29.14f, 29.14f, 0, 0, 0, 19.04f, -7.04f,
+R_LINE_TO, 1.24f, 1.24f,
+R_V_LINE_TO, 3.56f,
+R_LINE_TO, 22.54f, 22.46f,
+R_LINE_TO, 6.72f, -6.7f,
+R_LINE_TO, -22.49f, -22.5f,
+CLOSE,
+R_MOVE_TO, -27.04f, 0,
+R_CUBIC_TO, -11.2f, 0, -20.28f, -9.07f, -20.28f, -20.25f,
+R_CUBIC_TO, 0, -11.18f, 9.08f, -20.25f, 20.28f, -20.25f,
+R_CUBIC_TO, 11.2f, 0, 20.28f, 9.07f, 20.28f, 20.25f,
+R_CUBIC_TO, 0, 11.18f, -9.08f, 20.25f, -20.28f, 20.25f,
+CLOSE
+
+CANVAS_DIMENSIONS, 150,
+MOVE_TO, 110.58f, 49,
+H_LINE_TO, 38.47f,
+R_CUBIC_TO, -4.96f, 0, -8.97f, 4.05f, -8.97f, 9,
+R_LINE_TO, -0.04f, 45,
+R_CUBIC_TO, 0, 4.95f, 4.06f, 9, 9.01f, 9,
+R_H_LINE_TO, 72.11f,
+R_CUBIC_TO, 4.96f, 0, 9.02f, -4.05f, 9.02f, -9,
+V_LINE_TO, 58,
+R_CUBIC_TO, 0, -4.95f, -4.06f, -9, -9.01f, -9,
+CLOSE,
+NEW_PATH,
+STROKE, 2.254f,
+MOVE_TO, 122.97f, 38.12f,
+R_LINE_TO, 1.94f, -7.08f,
+CLOSE,
+NEW_PATH,
+STROKE, 2.254f,
+MOVE_TO, 130.18f, 45.26f,
+R_LINE_TO, 6.45f, -3,
+CLOSE,
+NEW_PATH,
+STROKE, 2.254f,
+MOVE_TO, 131.68f, 56.81f,
+R_LINE_TO, 6.88f, 2.88f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x20, 0x21, 0x24,
+MOVE_TO, 81, 89,
+R_ARC_TO, 6, 6, 0, 1, 0, -12, 0,
+R_CUBIC_TO, 0, 0.06f, 12, 0.05f, 12, 0,
+CLOSE,
+CIRCLE, 52, 75, 4.5,
+CIRCLE, 98, 75, 4.5,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 121.85f, 106.5f,
+R_H_LINE_TO, -1.79f,
+R_LINE_TO, -0.62f, -0.62f,
+R_ARC_TO, 14.47f, 14.47f, 0, 0, 0, 3.54f, -9.51f,
+R_CUBIC_TO, 0, -8.08f, -6.56f, -14.62f, -14.65f, -14.62f,
+R_CUBIC_TO, -8.09f, 0, -14.65f, 6.55f, -14.65f, 14.63f,
+CUBIC_TO_SHORTHAND, 100.23f, 111, 108.32f, 111,
+R_CUBIC_TO, 3.64f, 0, 6.96f, -1.33f, 9.52f, -3.52f,
+R_LINE_TO, 0.62f, 0.62f,
+R_V_LINE_TO, 1.78f,
+R_LINE_TO, 11.27f, 11.23f,
+R_LINE_TO, 3.36f, -3.35f,
+R_LINE_TO, -11.24f, -11.25f,
+CLOSE,
+R_MOVE_TO, -13.52f, 0,
+R_CUBIC_TO, -5.6f, 0, -10.14f, -4.53f, -10.14f, -10.12f,
+R_CUBIC_TO, 0, -5.59f, 4.54f, -10.12f, 10.14f, -10.12f,
+R_CUBIC_TO, 5.6f, 0, 10.14f, 4.53f, 10.14f, 10.13f,
+R_CUBIC_TO, 0, 5.6f, -4.54f, 10.13f, -10.14f, 10.13f,
+CLOSE
diff --git a/ash/resources/vector_icons/ksv_search_no_result.icon b/ash/resources/vector_icons/ksv_search_no_result_light.icon
similarity index 100%
rename from ash/resources/vector_icons/ksv_search_no_result.icon
rename to ash/resources/vector_icons/ksv_search_no_result_light.icon
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc
index 82d63cf..55c1d01 100644
--- a/ash/search_box/search_box_view_base.cc
+++ b/ash/search_box/search_box_view_base.cc
@@ -43,7 +43,7 @@
 
 // The duration for the animation which changes the search icon.
 constexpr base::TimeDelta kSearchIconAnimationDuration =
-    base::Milliseconds(250);
+    base::Milliseconds(150);
 
 constexpr int kInnerPadding = 16;
 
@@ -61,7 +61,7 @@
 constexpr base::TimeDelta kButtonFadeInDelay = base::Milliseconds(50);
 
 // The duration for the button fade in animation.
-constexpr base::TimeDelta kButtonFadeInDuration = base::Milliseconds(200);
+constexpr base::TimeDelta kButtonFadeInDuration = base::Milliseconds(100);
 
 }  // namespace
 
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
index b0e743d..32028b4 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
@@ -73,6 +73,37 @@
 constexpr SkColor kSearchIllustrationTextColorLight =
     SkColorSetARGB(0xFF, 0x20, 0x21, 0x24);
 
+constexpr SkColor kSearchIllustrationIconColorDark =
+    SkColorSetARGB(0xFF, 0x3C, 0x40, 0x43);
+
+// Custom No Results image view to handle color theme changes.
+class KSVNoResultsImageView : public views::ImageView {
+ public:
+  KSVNoResultsImageView() : color_provider_(ash::ColorProvider::Get()) {}
+
+  KSVNoResultsImageView(const KSVNoResultsImageView&) = delete;
+  KSVNoResultsImageView operator=(const KSVNoResultsImageView&) = delete;
+
+  ~KSVNoResultsImageView() override = default;
+
+ protected:
+  void OnThemeChanged() override {
+    ImageView::OnThemeChanged();
+
+    if (ash::features::IsDarkLightModeEnabled() &&
+        color_provider_->IsDarkModeEnabled()) {
+      SetImage(gfx::CreateVectorIcon(ash::kKsvSearchNoResultDarkIcon,
+                                     kSearchIllustrationIconColorDark));
+    } else {
+      SetImage(gfx::CreateVectorIcon(ash::kKsvSearchNoResultLightIcon,
+                                     kSearchIllustrationIconColorLight));
+    }
+  }
+
+ private:
+  ash::ColorProvider* const color_provider_;
+};
+
 // Creates the no search result view.
 std::unique_ptr<views::View> CreateNoSearchResultView() {
   constexpr int kSearchIllustrationIconSize = 150;
@@ -92,8 +123,8 @@
           views::BoxLayout::Orientation::kVertical,
           gfx::Insets::TLBR(kTopPadding, 0, 0, 0)));
   layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
-  auto image_view = std::make_unique<views::ImageView>();
-  image_view->SetImage(gfx::CreateVectorIcon(ash::kKsvSearchNoResultIcon,
+  auto image_view = std::make_unique<KSVNoResultsImageView>();
+  image_view->SetImage(gfx::CreateVectorIcon(ash::kKsvSearchNoResultLightIcon,
                                              kSearchIllustrationIconColor));
   image_view->SetImageSize(
       gfx::Size(kSearchIllustrationIconSize, kSearchIllustrationIconSize));
diff --git a/ash/system/eche/eche_tray.cc b/ash/system/eche/eche_tray.cc
index 320b991c6..3bde1b14 100644
--- a/ash/system/eche/eche_tray.cc
+++ b/ash/system/eche/eche_tray.cc
@@ -124,11 +124,6 @@
     event->StopPropagation();
     return;
   }
-  if (AcceleratorController::Get()->IsRegistered(accelerator)) {
-    views::ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
-        accelerator);
-    event->StopPropagation();
-  }
 }
 
 EcheTray::EcheTray(Shelf* shelf)
diff --git a/ash/system/power/adaptive_charging_nudge_controller_unittest.cc b/ash/system/power/adaptive_charging_nudge_controller_unittest.cc
index 0976073..bd5d668 100644
--- a/ash/system/power/adaptive_charging_nudge_controller_unittest.cc
+++ b/ash/system/power/adaptive_charging_nudge_controller_unittest.cc
@@ -15,40 +15,13 @@
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/test/widget_test.h"
 #include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_observer.h"
 
 namespace ash {
 
 namespace {
 
-// Utility class to wait/observe the closing of the nudge.
-class NudgeWidgetObserver : public views::WidgetObserver {
- public:
-  NudgeWidgetObserver(views::Widget* widget) {
-    if (!widget)
-      return;
-
-    widget_observation_.Observe(widget);
-  }
-
-  void WaitForClose() {
-    run_loop_ = std::make_unique<base::RunLoop>();
-    run_loop_->Run();
-  }
-
-  // views::WidgetObserver:
-  void OnWidgetClosing(views::Widget* widget) override {
-    if (run_loop_)
-      run_loop_->Quit();
-  }
-
- private:
-  base::ScopedObservation<views::Widget, views::WidgetObserver>
-      widget_observation_{this};
-  std::unique_ptr<base::RunLoop> run_loop_;
-};
-
 // Enables or disables the user pref for the entire feature.
 void SetAdaptiveChargingPref(bool enabled) {
   Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
@@ -75,8 +48,8 @@
 
   AdaptiveChargingNudgeController* GetController() { return controller_.get(); }
 
-  void WaitForWidgetClose(AdaptiveChargingNudgeController* controller,
-                          SystemNudge* nudge) {
+  void WaitForWidgetDestruction(AdaptiveChargingNudgeController* controller,
+                                SystemNudge* nudge) {
     views::Widget* nudge_widget = nudge->widget();
     ASSERT_TRUE(nudge_widget);
     EXPECT_FALSE(nudge_widget->IsClosed());
@@ -86,12 +59,11 @@
         ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
 
     // Pretend the hide nudge timer has elapsed.
-    NudgeWidgetObserver widget_close_observer(nudge_widget);
     controller->FireHideNudgeTimerForTesting();
-
     EXPECT_TRUE(nudge_widget->GetLayer()->GetAnimator()->is_animating());
 
-    widget_close_observer.WaitForClose();
+    views::test::WidgetDestroyedWaiter widget_destroyed_waiter(nudge_widget);
+    widget_destroyed_waiter.Wait();
   }
 
  private:
@@ -109,7 +81,7 @@
   SystemNudge* nudge = controller->GetSystemNudgeForTesting();
   ASSERT_TRUE(nudge);
 
-  WaitForWidgetClose(controller, nudge);
+  WaitForWidgetDestruction(controller, nudge);
 }
 
 TEST_F(AdaptiveChargingNudgeControllerTest, NoNudgeShowForDisabledFeature) {
@@ -135,7 +107,7 @@
   controller->GetNudgeDelayTimerForTesting()->FireNow();
   SystemNudge* nudge1 = controller->GetSystemNudgeForTesting();
   ASSERT_TRUE(nudge1);
-  WaitForWidgetClose(controller, nudge1);
+  WaitForWidgetDestruction(controller, nudge1);
 
   // No nudge for the second time.
   controller->ShowNudge();
diff --git a/ash/system/time/calendar_event_list_item_view.cc b/ash/system/time/calendar_event_list_item_view.cc
index 29d3664..23489aa 100644
--- a/ash/system/time/calendar_event_list_item_view.cc
+++ b/ash/system/time/calendar_event_list_item_view.cc
@@ -203,7 +203,7 @@
   bool opened_pwa = false;
   DCHECK(calendar_view_controller_->selected_date().has_value());
   Shell::Get()->system_tray_model()->client()->ShowCalendarEvent(
-      event_url_, calendar_view_controller_->selected_date().value(),
+      event_url_, calendar_view_controller_->selected_date_midnight(),
       opened_pwa, finalized_url);
   return true;
 }
diff --git a/ash/system/time/calendar_event_list_view.cc b/ash/system/time/calendar_event_list_view.cc
index 1e388f6..4237260 100644
--- a/ash/system/time/calendar_event_list_view.cc
+++ b/ash/system/time/calendar_event_list_view.cc
@@ -90,8 +90,10 @@
     GURL finalized_url;
     bool opened_pwa = false;
     DCHECK(controller_->selected_date().has_value());
+
+    // Open Google calendar and land on the local day/month/year.
     Shell::Get()->system_tray_model()->client()->ShowCalendarEvent(
-        absl::nullopt, controller_->selected_date().value(), opened_pwa,
+        absl::nullopt, controller_->selected_date_midnight(), opened_pwa,
         finalized_url);
   }
 
diff --git a/ash/system/time/calendar_view_controller.h b/ash/system/time/calendar_view_controller.h
index 9f65674..3db43b84 100644
--- a/ash/system/time/calendar_view_controller.h
+++ b/ash/system/time/calendar_view_controller.h
@@ -82,12 +82,12 @@
   absl::optional<base::Time> selected_date() { return selected_date_; }
 
   // The midnight of the currently selected date adjusted to the local timezone.
-  base::Time selected_date_midnight() { return selected_date_midnight_; };
+  base::Time selected_date_midnight() { return selected_date_midnight_; }
 
   // The midnight of the selected date in UTC time.
   base::Time selected_date_midnight_utc() {
     return selected_date_midnight_utc_;
-  };
+  }
 
   // The row index of the currently selected date. This is used for auto
   // scrolling to this row when the event list is expanded.
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc
index b26e921..feabb247 100644
--- a/ash/wallpaper/wallpaper_view.cc
+++ b/ash/wallpaper/wallpaper_view.cc
@@ -54,8 +54,6 @@
     window->parent()->StackChildAtBottom(window);
     display::Display display =
         display::Screen::GetScreen()->GetDisplayNearestWindow(window);
-    display::ManagedDisplayInfo info =
-        Shell::Get()->display_manager()->GetDisplayInfo(display.id());
 
     for (auto* child : children()) {
       child->SetBounds(0, 0, display.size().width(), display.size().height());
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 3953851..6dbecb7 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -225,7 +225,7 @@
       // TODO(b/229149314): Finalize error and retry strings.
       {"googlePhotosLabel", IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS},
       {"googlePhotosError", IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR},
-      {"googlePhotosRetry", IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_RETRY},
+      {"googlePhotosTryAgain", IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_TRY_AGAIN},
       {"googlePhotosAlbumsTabLabel",
        IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ALBUMS_TAB},
       {"googlePhotosPhotosTabLabel",
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_albums_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_albums_element.ts
index 56e96bc..a02deaef 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_albums_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_albums_element.ts
@@ -130,7 +130,7 @@
           id: ERROR_ID,
           message: this.i18n('googlePhotosError'),
           dismiss: {
-            message: this.i18n('googlePhotosRetry'),
+            message: this.i18n('googlePhotosTryAgain'),
             callback: (fromUser: boolean) => {
               if (fromUser) {
                 // Post the reattempt instead of performing it immediately to
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts
index ddb645d3..e3d4764a 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_by_album_id_element.ts
@@ -230,7 +230,7 @@
           id: ERROR_ID,
           message: this.i18n('googlePhotosError'),
           dismiss: {
-            message: this.i18n('googlePhotosRetry'),
+            message: this.i18n('googlePhotosTryAgain'),
             callback: (fromUser: boolean) => {
               if (fromUser) {
                 // Post the reattempt instead of performing it immediately to
diff --git a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts
index f6c420f..9f7f766 100644
--- a/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/wallpaper/google_photos_photos_element.ts
@@ -358,7 +358,7 @@
           id: ERROR_ID,
           message: this.i18n('googlePhotosError'),
           dismiss: {
-            message: this.i18n('googlePhotosRetry'),
+            message: this.i18n('googlePhotosTryAgain'),
             callback: (fromUser: boolean) => {
               if (fromUser) {
                 // Post the reattempt instead of performing it immediately to
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 946a164..58e6fcb7 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -992,8 +992,6 @@
       "synchronization/waitable_event_posix.cc",
       "synchronization/waitable_event_watcher_posix.cc",
       "system/sys_info_posix.cc",
-      "task/thread_pool/task_tracker_posix.cc",
-      "task/thread_pool/task_tracker_posix.h",
       "threading/platform_thread_internal_posix.cc",
       "threading/platform_thread_internal_posix.h",
       "threading/platform_thread_posix.cc",
@@ -1845,8 +1843,6 @@
       "synchronization/waitable_event_posix.cc",
       "synchronization/waitable_event_watcher_posix.cc",
       "system/sys_info_fuchsia.cc",
-      "task/thread_pool/task_tracker_posix.cc",
-      "task/thread_pool/task_tracker_posix.h",
       "threading/platform_thread_fuchsia.cc",
       "threading/platform_thread_posix.cc",
       "threading/thread_local_storage_posix.cc",
@@ -1992,8 +1988,6 @@
       "system/sys_info_posix.cc",
       "task/thread_pool/initialization_util.cc",
       "task/thread_pool/initialization_util.h",
-      "task/thread_pool/task_tracker_posix.cc",
-      "task/thread_pool/task_tracker_posix.h",
     ]
   } else {
     # Remove NaCl stuff.
@@ -2019,6 +2013,15 @@
     # partition_alloc code if use_partition_alloc = false because no code uses
     # partition_alloc.
     public_deps += [ "allocator/partition_allocator:partition_alloc" ]
+
+    # PartitionAlloc is not yet built as a standalone component, and
+    # "external" usage of some exported functions causes Win32 component
+    # builds to break (LNK4217). This statement properly belongs _only_
+    # in PA's BUILD.gn, but we need it here to ensure the rest of
+    # `//base` is also considered "inside" the PA implementation.
+    #
+    # TODO(crbug.com/1151236): Remove this when possible.
+    defines += [ "IS_PARTITION_ALLOC_IMPL" ]
   }
 
   # Windows.
@@ -3503,7 +3506,6 @@
       "message_loop/fd_watch_controller_posix_unittest.cc",
       "posix/file_descriptor_shuffle_unittest.cc",
       "posix/unix_domain_socket_unittest.cc",
-      "task/thread_pool/task_tracker_posix_unittest.cc",
     ]
     if (!is_nacl && !is_apple) {
       sources += [
@@ -3652,6 +3654,7 @@
       "allocator/partition_allocator/memory_reclaimer_unittest.cc",
       "allocator/partition_allocator/page_allocator_unittest.cc",
       "allocator/partition_allocator/partition_alloc_base/bits_pa_unittest.cc",
+      "allocator/partition_allocator/partition_alloc_base/component_export_pa_unittest.cc",
       "allocator/partition_allocator/partition_alloc_base/cpu_pa_unittest.cc",
       "allocator/partition_allocator/partition_alloc_base/cxx17_backports_pa_unittest.cc",
       "allocator/partition_allocator/partition_alloc_base/logging_pa_unittest.cc",
@@ -3750,7 +3753,6 @@
       "fuchsia/time_zone_data_unittest.cc",
       "message_loop/fd_watch_controller_posix_unittest.cc",
       "posix/file_descriptor_shuffle_unittest.cc",
-      "task/thread_pool/task_tracker_posix_unittest.cc",
     ]
 
     deps += [
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index a3097d5..4c0d5cb8 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -8,9 +8,8 @@
 # Add partition_alloc.gni and import it for partition_alloc configs.
 
 config("partition_alloc_implementation") {
-  # After introducing partition_alloc_export, replace BASE_IMPLEMENTATION with
-  # PARTITION_ALLOC_IMPLEMENTATION.
-  defines = [ "BASE_IMPLEMENTATION" ]
+  # See also: `partition_alloc_base/component_export.h`
+  defines = [ "IS_PARTITION_ALLOC_IMPL" ]
 }
 
 config("memory_tagging") {
@@ -78,6 +77,7 @@
     "partition_alloc_base/check.cc",
     "partition_alloc_base/check.h",
     "partition_alloc_base/compiler_specific.h",
+    "partition_alloc_base/component_export.h",
     "partition_alloc_base/cpu.cc",
     "partition_alloc_base/cpu.h",
     "partition_alloc_base/cxx17_backports.h",
diff --git a/base/allocator/partition_allocator/DEPS b/base/allocator/partition_allocator/DEPS
index dae6178d..3e23a180 100644
--- a/base/allocator/partition_allocator/DEPS
+++ b/base/allocator/partition_allocator/DEPS
@@ -5,7 +5,6 @@
 
 include_rules = [
     "+base/allocator/buildflags.h",
-    "+base/base_export.h",
     "+base/logging_buildflags.h",
     "+base/mac/foundation_util.h",
     "+base/mac/mac_util.h",
diff --git a/base/allocator/partition_allocator/address_pool_manager.h b/base/allocator/partition_allocator/address_pool_manager.h
index a11b00c7..186bf9c 100644
--- a/base/allocator/partition_allocator/address_pool_manager.h
+++ b/base/allocator/partition_allocator/address_pool_manager.h
@@ -13,12 +13,12 @@
 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -53,7 +53,7 @@
 // IsManagedByPartitionAllocRegularPool use the bitmaps to judge whether a given
 // address is in a pool that supports BackupRefPtr or in a pool that doesn't.
 // All PartitionAlloc allocations must be in either of the pools.
-class BASE_EXPORT AddressPoolManager {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
  public:
   static AddressPoolManager& GetInstance();
 
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.h b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
index 227e2aa..f9ab470 100644
--- a/base/allocator/partition_allocator/address_pool_manager_bitmap.h
+++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
@@ -12,11 +12,11 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if !defined(PA_HAS_64_BITS_POINTERS)
@@ -30,7 +30,7 @@
 // support it. All PartitionAlloc allocations must be in either of the pools.
 //
 // This code is specific to 32-bit systems.
-class BASE_EXPORT AddressPoolManagerBitmap {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManagerBitmap {
  public:
   static constexpr uint64_t kGiB = 1024 * 1024 * 1024ull;
   static constexpr uint64_t kAddressSpaceSize = 4ull * kGiB;
diff --git a/base/allocator/partition_allocator/address_space_randomization.h b/base/allocator/partition_allocator/address_space_randomization.h
index 59161ae0..093fa81 100644
--- a/base/allocator/partition_allocator/address_space_randomization.h
+++ b/base/allocator/partition_allocator/address_space_randomization.h
@@ -9,14 +9,14 @@
 
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
 
 // Calculates a random preferred mapping address. In calculating an address, we
 // balance good ASLR against not fragmenting the address space too badly.
-BASE_EXPORT uintptr_t GetRandomPageBase();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) uintptr_t GetRandomPageBase();
 
 namespace internal {
 
diff --git a/base/allocator/partition_allocator/address_space_stats.h b/base/allocator/partition_allocator/address_space_stats.h
index c37d29e..40fe522d 100644
--- a/base/allocator/partition_allocator/address_space_stats.h
+++ b/base/allocator/partition_allocator/address_space_stats.h
@@ -8,8 +8,8 @@
 #include <cstddef>
 
 #include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
-#include "base/base_export.h"
 
 namespace partition_alloc {
 
@@ -42,7 +42,7 @@
 
 // Interface passed to `AddressPoolManager::DumpStats()` to mediate
 // for `AddressSpaceDumpProvider`.
-class BASE_EXPORT AddressSpaceStatsDumper {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressSpaceStatsDumper {
  public:
   virtual void DumpStats(const AddressSpaceStats* address_space_stats) = 0;
 };
diff --git a/base/allocator/partition_allocator/allocation_guard.h b/base/allocator/partition_allocator/allocation_guard.h
index ebbe83bf..bff238b 100644
--- a/base/allocator/partition_allocator/allocation_guard.h
+++ b/base/allocator/partition_allocator/allocation_guard.h
@@ -5,8 +5,8 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_ALLOCATION_GUARD_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_ALLOCATION_GUARD_H_
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -14,14 +14,14 @@
 #if defined(PA_HAS_ALLOCATION_GUARD)
 
 // Disallow allocations in the scope. Does not nest.
-class BASE_EXPORT ScopedDisallowAllocations {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ScopedDisallowAllocations {
  public:
   ScopedDisallowAllocations();
   ~ScopedDisallowAllocations();
 };
 
 // Disallow allocations in the scope. Does not nest.
-class BASE_EXPORT ScopedAllowAllocations {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ScopedAllowAllocations {
  public:
   ScopedAllowAllocations();
   ~ScopedAllowAllocations();
diff --git a/base/allocator/partition_allocator/build_config.md b/base/allocator/partition_allocator/build_config.md
index cbe134c..90f9d0b0 100644
--- a/base/allocator/partition_allocator/build_config.md
+++ b/base/allocator/partition_allocator/build_config.md
@@ -95,9 +95,17 @@
 * `OFFICIAL_BUILD` - influences crash macros and
   `PA_THREAD_CACHE_ALLOC_STATS`. These are conceptually distinct enough
   to be worth separating into dedicated build controls.
+* `IS_PARTITION_ALLOC_IMPL` - must be defined when PartitionAlloc is
+  built as a shared library. This is required to export symbols.
+* `COMPONENT_BUILD` - component builds (as per
+  `//docs/component_build.md`) must `#define COMPONENT_BUILD`.
+  Additionally, to build Win32, invoker must `#define WIN32`.
 * `MEMORY_TOOL_REPLACES_ALLOCATOR`
 * `*_SANITIZER` - mainly influences unit tests.
 
+TODO(crbug.com/1151236): don't `PA_COMPONENT_EXPORT()` functions defined
+under `partition_alloc_base/`.
+
 *** note
 Over time, the above list should evolve into a list of macros / GN args
 that influence PartitionAlloc's behavior.
diff --git a/base/allocator/partition_allocator/dangling_raw_ptr_checks.cc b/base/allocator/partition_allocator/dangling_raw_ptr_checks.cc
index fb694e3..ce6ed649 100644
--- a/base/allocator/partition_allocator/dangling_raw_ptr_checks.cc
+++ b/base/allocator/partition_allocator/dangling_raw_ptr_checks.cc
@@ -4,8 +4,8 @@
 
 #include "base/allocator/partition_allocator/dangling_raw_ptr_checks.h"
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/base_export.h"
 
 namespace partition_alloc {
 
@@ -36,10 +36,10 @@
 
 namespace internal {
 
-BASE_EXPORT void DanglingRawPtrDetected(uintptr_t id) {
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void DanglingRawPtrDetected(uintptr_t id) {
   g_dangling_raw_ptr_detected_fn(id);
 }
-BASE_EXPORT void DanglingRawPtrReleased(uintptr_t id) {
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void DanglingRawPtrReleased(uintptr_t id) {
   g_dangling_raw_ptr_released_fn(id);
 }
 
diff --git a/base/allocator/partition_allocator/dangling_raw_ptr_checks.h b/base/allocator/partition_allocator/dangling_raw_ptr_checks.h
index 815d144..5234eec 100644
--- a/base/allocator/partition_allocator/dangling_raw_ptr_checks.h
+++ b/base/allocator/partition_allocator/dangling_raw_ptr_checks.h
@@ -7,7 +7,7 @@
 
 #include <cstdint>
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 // When compiled with build flags `enable_dangling_raw_ptr_checks`, dangling
 // raw_ptr are reported. Its behavior can be configured here.
@@ -30,21 +30,25 @@
 // This function is called from within the allocator, and is not allowed to
 // allocate memory.
 using DanglingRawPtrDetectedFn = void(uintptr_t /*id*/);
-BASE_EXPORT DanglingRawPtrDetectedFn* GetDanglingRawPtrDetectedFn();
-BASE_EXPORT void SetDanglingRawPtrDetectedFn(DanglingRawPtrDetectedFn);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+DanglingRawPtrDetectedFn* GetDanglingRawPtrDetectedFn();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetDanglingRawPtrDetectedFn(DanglingRawPtrDetectedFn);
 
 // DanglingRawPtrReleased: Called after DanglingRawPtrDetected(id), once the
 // last dangling raw_ptr stops referencing the memory region.
 //
 // This function is allowed to allocate memory.
 using DanglingRawPtrReleasedFn = void(uintptr_t /*id*/);
-BASE_EXPORT DanglingRawPtrReleasedFn* GetDanglingRawPtrReleasedFn();
-BASE_EXPORT void SetDanglingRawPtrReleasedFn(DanglingRawPtrReleasedFn);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+DanglingRawPtrReleasedFn* GetDanglingRawPtrReleasedFn();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetDanglingRawPtrReleasedFn(DanglingRawPtrReleasedFn);
 
 namespace internal {
 
-BASE_EXPORT void DanglingRawPtrDetected(uintptr_t id);
-BASE_EXPORT void DanglingRawPtrReleased(uintptr_t id);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void DanglingRawPtrDetected(uintptr_t id);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void DanglingRawPtrReleased(uintptr_t id);
 
 }  // namespace internal
 }  // namespace partition_alloc
diff --git a/base/allocator/partition_allocator/memory_reclaimer.h b/base/allocator/partition_allocator/memory_reclaimer.h
index 76952a5..2f52c7f1 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.h
+++ b/base/allocator/partition_allocator/memory_reclaimer.h
@@ -8,12 +8,12 @@
 #include <memory>
 #include <set>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/no_destructor.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
-#include "base/base_export.h"
 
 namespace partition_alloc {
 
@@ -26,7 +26,7 @@
 //
 // Singleton as this runs as long as the process is alive, and
 // having multiple instances would be wasteful.
-class BASE_EXPORT MemoryReclaimer {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) MemoryReclaimer {
  public:
   static MemoryReclaimer* Instance();
 
diff --git a/base/allocator/partition_allocator/oom.h b/base/allocator/partition_allocator/oom.h
index a0d564f..898f990 100644
--- a/base/allocator/partition_allocator/oom.h
+++ b/base/allocator/partition_allocator/oom.h
@@ -9,7 +9,7 @@
 
 #include "base/allocator/partition_allocator/allocation_guard.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -22,12 +22,13 @@
 // |size| is the size of the failed allocation, or 0 if not known.
 // Crash reporting classifies such crashes as OOM.
 // Must be allocation-safe.
-BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void TerminateBecauseOutOfMemory(size_t size);
 
 // Records the size of the allocation that caused the current OOM crash, for
 // consumption by Breakpad.
 // TODO: this can be removed when Breakpad is no longer supported.
-BASE_EXPORT extern size_t g_oom_size;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern size_t g_oom_size;
 
 #if BUILDFLAG(IS_WIN)
 namespace win {
@@ -48,7 +49,8 @@
 // The crash is generated in a PA_NOINLINE function so that we can classify the
 // crash as an OOM solely by analyzing the stack trace. It is tagged as
 // PA_NOT_TAIL_CALLED to ensure that its parent function stays on the stack.
-[[noreturn]] BASE_EXPORT void PA_NOT_TAIL_CALLED OnNoMemory(size_t size);
+[[noreturn]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) void PA_NOT_TAIL_CALLED
+    OnNoMemory(size_t size);
 
 // OOM_CRASH(size) - Specialization of IMMEDIATE_CRASH which will raise a custom
 // exception on Windows to signal this is OOM and not a normal assert.
diff --git a/base/allocator/partition_allocator/oom_callback.h b/base/allocator/partition_allocator/oom_callback.h
index e2e726d3..c06ab0a 100644
--- a/base/allocator/partition_allocator/oom_callback.h
+++ b/base/allocator/partition_allocator/oom_callback.h
@@ -5,7 +5,7 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_CALLBACK_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_CALLBACK_H_
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 namespace partition_alloc {
 
@@ -14,11 +14,11 @@
 // Registers a callback to be invoked during an OOM_CRASH(). OOM_CRASH is
 // invoked by users of PageAllocator (including PartitionAlloc) to signify an
 // allocation failure from the platform.
-BASE_EXPORT void SetPartitionAllocOomCallback(
-    PartitionAllocOomCallback callback);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetPartitionAllocOomCallback(PartitionAllocOomCallback callback);
 
 namespace internal {
-BASE_EXPORT void RunPartitionAllocOomCallback();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void RunPartitionAllocOomCallback();
 }  // namespace internal
 
 }  // namespace partition_alloc
diff --git a/base/allocator/partition_allocator/page_allocator.h b/base/allocator/partition_allocator/page_allocator.h
index 343ba52..b21d602 100644
--- a/base/allocator/partition_allocator/page_allocator.h
+++ b/base/allocator/partition_allocator/page_allocator.h
@@ -10,7 +10,7 @@
 
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -54,9 +54,10 @@
   kLast = kV8             // Maximum tag value.
 };
 
-BASE_EXPORT uintptr_t NextAlignedWithOffset(uintptr_t ptr,
-                                            uintptr_t alignment,
-                                            uintptr_t requested_offset);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+uintptr_t NextAlignedWithOffset(uintptr_t ptr,
+                                uintptr_t alignment,
+                                uintptr_t requested_offset);
 
 // Allocates one or more pages.
 //
@@ -78,27 +79,31 @@
 // allocation. Use PageTag::kChromium as a catch-all category.
 //
 // This call will return 0/nullptr if the allocation cannot be satisfied.
-BASE_EXPORT uintptr_t AllocPages(size_t length,
-                                 size_t align,
-                                 PageAccessibilityConfiguration accessibility,
-                                 PageTag page_tag);
-BASE_EXPORT uintptr_t AllocPages(uintptr_t address,
-                                 size_t length,
-                                 size_t align,
-                                 PageAccessibilityConfiguration accessibility,
-                                 PageTag page_tag);
-BASE_EXPORT void* AllocPages(void* address,
-                             size_t length,
-                             size_t align,
-                             PageAccessibilityConfiguration accessibility,
-                             PageTag page_tag);
-BASE_EXPORT uintptr_t
-AllocPagesWithAlignOffset(uintptr_t address,
-                          size_t length,
-                          size_t align,
-                          size_t align_offset,
-                          PageAccessibilityConfiguration page_accessibility,
-                          PageTag page_tag);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+uintptr_t AllocPages(size_t length,
+                     size_t align,
+                     PageAccessibilityConfiguration accessibility,
+                     PageTag page_tag);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+uintptr_t AllocPages(uintptr_t address,
+                     size_t length,
+                     size_t align,
+                     PageAccessibilityConfiguration accessibility,
+                     PageTag page_tag);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void* AllocPages(void* address,
+                 size_t length,
+                 size_t align,
+                 PageAccessibilityConfiguration accessibility,
+                 PageTag page_tag);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+uintptr_t AllocPagesWithAlignOffset(
+    uintptr_t address,
+    size_t length,
+    size_t align,
+    size_t align_offset,
+    PageAccessibilityConfiguration page_accessibility,
+    PageTag page_tag);
 
 // Frees one or more pages starting at |address| and continuing for |length|
 // bytes.
@@ -106,8 +111,10 @@
 // |address| and |length| must match a previous call to |AllocPages|. Therefore,
 // |address| must be aligned to |PageAllocationGranularity()| bytes, and
 // |length| must be a multiple of |PageAllocationGranularity()|.
-BASE_EXPORT void FreePages(uintptr_t address, size_t length);
-BASE_EXPORT void FreePages(void* address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void FreePages(uintptr_t address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void FreePages(void* address, size_t length);
 
 // Marks one or more system pages, starting at |address| with the given
 // |page_accessibility|. |length| must be a multiple of |SystemPageSize()|
@@ -115,11 +122,11 @@
 //
 // Returns true if the permission change succeeded. In most cases you must
 // |CHECK| the result.
-[[nodiscard]] BASE_EXPORT bool TrySetSystemPagesAccess(
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool TrySetSystemPagesAccess(
     uintptr_t address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility);
-[[nodiscard]] BASE_EXPORT bool TrySetSystemPagesAccess(
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool TrySetSystemPagesAccess(
     void* address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility);
@@ -129,14 +136,14 @@
 // bytes.
 //
 // Performs a CHECK that the operation succeeds.
-BASE_EXPORT void SetSystemPagesAccess(
-    uintptr_t address,
-    size_t length,
-    PageAccessibilityConfiguration page_accessibility);
-BASE_EXPORT void SetSystemPagesAccess(
-    void* address,
-    size_t length,
-    PageAccessibilityConfiguration page_accessibility);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetSystemPagesAccess(uintptr_t address,
+                          size_t length,
+                          PageAccessibilityConfiguration page_accessibility);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetSystemPagesAccess(void* address,
+                          size_t length,
+                          PageAccessibilityConfiguration page_accessibility);
 
 // Decommits one or more system pages starting at |address| and continuing for
 // |length| bytes. |address| and |length| must be aligned to a system page
@@ -170,11 +177,13 @@
 // behaves in a platform-agnostic way by simulating the Windows "decommit" state
 // by both discarding the region (allowing the OS to avoid swap operations)
 // *and* changing the page protections so accesses fault.
-BASE_EXPORT void DecommitSystemPages(
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DecommitSystemPages(
     uintptr_t address,
     size_t length,
     PageAccessibilityDisposition accessibility_disposition);
-BASE_EXPORT void DecommitSystemPages(
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DecommitSystemPages(
     void* address,
     size_t length,
     PageAccessibilityDisposition accessibility_disposition);
@@ -188,12 +197,15 @@
 // setting them to PageAccessibilityConfiguration::kInaccessible).
 //
 // This API will crash if the operation cannot be performed.
-BASE_EXPORT void DecommitAndZeroSystemPages(uintptr_t address, size_t length);
-BASE_EXPORT void DecommitAndZeroSystemPages(void* address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DecommitAndZeroSystemPages(uintptr_t address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DecommitAndZeroSystemPages(void* address, size_t length);
 
 // Whether decommitted memory is guaranteed to be zeroed when it is
 // recommitted. Do not assume that this will not change over time.
-constexpr BASE_EXPORT bool DecommittedMemoryIsAlwaysZeroed() {
+constexpr PA_COMPONENT_EXPORT(
+    PARTITION_ALLOC) bool DecommittedMemoryIsAlwaysZeroed() {
 #if BUILDFLAG(IS_APPLE)
   return false;
 #else
@@ -221,14 +233,15 @@
 // |DecommittedMemoryIsAlwaysZeroed()| is true.
 //
 // This operation may not be atomic on some platforms.
-BASE_EXPORT void RecommitSystemPages(
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void RecommitSystemPages(
     uintptr_t address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility,
     PageAccessibilityDisposition accessibility_disposition);
 
 // Like RecommitSystemPages(), but returns false instead of crashing.
-[[nodiscard]] BASE_EXPORT bool TryRecommitSystemPages(
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool TryRecommitSystemPages(
     uintptr_t address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility,
@@ -255,8 +268,10 @@
 // that the page is required again. Once written to, the content of the page is
 // guaranteed stable once more. After being written to, the page content may be
 // based on the original page content, or a page of zeroes.
-BASE_EXPORT void DiscardSystemPages(uintptr_t address, size_t length);
-BASE_EXPORT void DiscardSystemPages(void* address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DiscardSystemPages(uintptr_t address, size_t length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DiscardSystemPages(void* address, size_t length);
 
 // Rounds up |address| to the next multiple of |SystemPageSize()|. Returns
 // 0 for an |address| of 0.
@@ -292,25 +307,25 @@
 // |PageAllocationGranularity()|. This can be called early on to make it more
 // likely that large allocations will succeed. Returns true if the reservation
 // succeeded, false if the reservation failed or a reservation was already made.
-BASE_EXPORT bool ReserveAddressSpace(size_t size);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool ReserveAddressSpace(size_t size);
 
 // Releases any reserved address space. |AllocPages| calls this automatically on
 // an allocation failure. External allocators may also call this on failure.
 //
 // Returns true when an existing reservation was released.
-BASE_EXPORT bool ReleaseReservation();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool ReleaseReservation();
 
 // Returns true if there is currently an address space reservation.
-BASE_EXPORT bool HasReservationForTesting();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool HasReservationForTesting();
 
 // Returns |errno| (POSIX) or the result of |GetLastError| (Windows) when |mmap|
 // (POSIX) or |VirtualAlloc| (Windows) fails.
-BASE_EXPORT uint32_t GetAllocPageErrorCode();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) uint32_t GetAllocPageErrorCode();
 
 // Returns the total amount of mapped pages from all clients of
 // PageAllocator. These pages may or may not be committed. This is mostly useful
 // to assess address space pressure.
-BASE_EXPORT size_t GetTotalMappedSize();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) size_t GetTotalMappedSize();
 
 }  // namespace partition_alloc
 
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h
index 0c09cf1..0167dba8 100644
--- a/base/allocator/partition_allocator/partition_address_space.h
+++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -14,13 +14,13 @@
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 
@@ -32,7 +32,7 @@
 namespace internal {
 
 // Reserves address space for PartitionAllocator.
-class BASE_EXPORT PartitionAddressSpace {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
  public:
   // BRP stands for BackupRefPtr. GigaCage is split into pools, one which
   // supports BackupRefPtr and one that doesn't.
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index e5c1a3f..bb1ece3 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -6,19 +6,21 @@
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_H_
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_oom.h"
 #include "base/allocator/partition_allocator/partition_root.h"
-#include "base/base_export.h"
 
 namespace partition_alloc {
 
-BASE_EXPORT void PartitionAllocGlobalInit(OomFunction on_out_of_memory);
-BASE_EXPORT void PartitionAllocGlobalUninitForTesting();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void PartitionAllocGlobalInit(OomFunction on_out_of_memory);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void PartitionAllocGlobalUninitForTesting();
 
 namespace internal {
 template <bool thread_safe>
-struct BASE_EXPORT PartitionAllocator {
+struct PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAllocator {
   PartitionAllocator() = default;
   ~PartitionAllocator();
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/check.h b/base/allocator/partition_allocator/partition_alloc_base/check.h
index e066b26..27aee111 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/check.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/check.h
@@ -9,8 +9,8 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
-#include "base/base_export.h"
 
 // This header defines the CHECK, DCHECK, and DPCHECK macros.
 //
@@ -62,12 +62,12 @@
   true ? (void)0                                                     \
        : ::partition_alloc::internal::logging::VoidifyStream(expr) & \
              (*::partition_alloc::internal::logging::g_swallow_stream)
-BASE_EXPORT extern std::ostream* g_swallow_stream;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern std::ostream* g_swallow_stream;
 
 class LogMessage;
 
 // Class used for raising a check error upon destruction.
-class BASE_EXPORT CheckError {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CheckError {
  public:
   static CheckError Check(const char* file, int line, const char* condition);
 
@@ -165,8 +165,8 @@
 #endif
 
 // Async signal safe checking mechanism.
-BASE_EXPORT void RawCheck(const char* message);
-BASE_EXPORT void RawError(const char* message);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void RawCheck(const char* message);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void RawError(const char* message);
 #define PA_RAW_CHECK(condition)                       \
   do {                                                \
     if (!(condition))                                 \
diff --git a/base/allocator/partition_allocator/partition_alloc_base/component_export.h b/base/allocator/partition_allocator/partition_alloc_base/component_export.h
new file mode 100644
index 0000000..f45840c
--- /dev/null
+++ b/base/allocator/partition_allocator/partition_alloc_base/component_export.h
@@ -0,0 +1,76 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_COMPONENT_EXPORT_H_
+#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_COMPONENT_EXPORT_H_
+
+// Used to annotate symbols which are exported by the component named
+// |component|. Note that this only does the right thing if the corresponding
+// component target's sources are compiled with |IS_$component_IMPL| defined
+// as 1. For example:
+//
+//   class PA_COMPONENT_EXPORT(FOO) Bar {};
+//
+// If IS_FOO_IMPL=1 at compile time, then Bar will be annotated using the
+// PA_COMPONENT_EXPORT_ANNOTATION macro defined below. Otherwise it will be
+// annotated using the PA_COMPONENT_IMPORT_ANNOTATION macro.
+#define PA_COMPONENT_EXPORT(component)                            \
+  PA_COMPONENT_MACRO_CONDITIONAL_(IS_##component##_IMPL,          \
+                                  PA_COMPONENT_EXPORT_ANNOTATION, \
+                                  PA_COMPONENT_IMPORT_ANNOTATION)
+
+// Indicates whether the current compilation unit is being compiled as part of
+// the implementation of the component named |component|. Expands to |1| if
+// |IS_$component_IMPL| is defined as |1|; expands to |0| otherwise.
+//
+// Note in particular that if |IS_$component_IMPL| is not defined at all, it is
+// still fine to test PA_INSIDE_COMPONENT_IMPL(component), which expands to |0|
+// as expected.
+#define PA_INSIDE_COMPONENT_IMPL(component) \
+  PA_COMPONENT_MACRO_CONDITIONAL_(IS_##component##_IMPL, 1, 0)
+
+// Compiler-specific macros to annotate for export or import of a symbol. No-op
+// in non-component builds. These should not see much if any direct use.
+// Instead use the PA_COMPONENT_EXPORT macro defined above.
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+#define PA_COMPONENT_EXPORT_ANNOTATION __declspec(dllexport)
+#define PA_COMPONENT_IMPORT_ANNOTATION __declspec(dllimport)
+#else  // defined(WIN32)
+#define PA_COMPONENT_EXPORT_ANNOTATION __attribute__((visibility("default")))
+#define PA_COMPONENT_IMPORT_ANNOTATION
+#endif  // defined(WIN32)
+#else   // defined(COMPONENT_BUILD)
+#define PA_COMPONENT_EXPORT_ANNOTATION
+#define PA_COMPONENT_IMPORT_ANNOTATION
+#endif  // defined(COMPONENT_BUILD)
+
+// Below this point are several internal utility macros used for the
+// implementation of the above macros. Not intended for external use.
+
+// Helper for conditional expansion to one of two token strings. If |condition|
+// expands to |1| then this macro expands to |consequent|; otherwise it expands
+// to |alternate|.
+#define PA_COMPONENT_MACRO_CONDITIONAL_(condition, consequent, alternate) \
+  PA_COMPONENT_MACRO_SELECT_THIRD_ARGUMENT_(                              \
+      PA_COMPONENT_MACRO_CONDITIONAL_COMMA_(condition), consequent, alternate)
+
+// Expands to a comma (,) iff its first argument expands to |1|. Used in
+// conjunction with |PA_COMPONENT_MACRO_SELECT_THIRD_ARGUMENT_()|, as the
+// presence or absense of an extra comma can be used to conditionally shift
+// subsequent argument positions and thus influence which argument is selected.
+#define PA_COMPONENT_MACRO_CONDITIONAL_COMMA_(...) \
+  PA_COMPONENT_MACRO_CONDITIONAL_COMMA_IMPL_(__VA_ARGS__, )
+#define PA_COMPONENT_MACRO_CONDITIONAL_COMMA_IMPL_(x, ...) \
+  PA_COMPONENT_MACRO_CONDITIONAL_COMMA_##x##_
+#define PA_COMPONENT_MACRO_CONDITIONAL_COMMA_1_ ,
+
+// Helper which simply selects its third argument. Used in conjunction with
+// |PA_COMPONENT_MACRO_CONDITIONAL_COMMA_()| above to implement conditional
+// macro expansion.
+#define PA_COMPONENT_MACRO_SELECT_THIRD_ARGUMENT_(...) \
+  PA_COMPONENT_MACRO_SELECT_THIRD_ARGUMENT_IMPL_(__VA_ARGS__)
+#define PA_COMPONENT_MACRO_SELECT_THIRD_ARGUMENT_IMPL_(a, b, c, ...) c
+
+#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_COMPONENT_EXPORT_H_
diff --git a/base/allocator/partition_allocator/partition_alloc_base/component_export_pa_unittest.cc b/base/allocator/partition_allocator/partition_alloc_base/component_export_pa_unittest.cc
new file mode 100644
index 0000000..a0e9af6
--- /dev/null
+++ b/base/allocator/partition_allocator/partition_alloc_base/component_export_pa_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace partition_alloc::internal::base {
+namespace {
+
+using ComponentExportTest = testing::Test;
+
+#define IS_TEST_COMPONENT_A_IMPL 1
+#define IS_TEST_COMPONENT_B_IMPL
+#define IS_TEST_COMPONENT_C_IMPL 0
+#define IS_TEST_COMPONENT_D_IMPL 2
+#define IS_TEST_COMPONENT_E_IMPL xyz
+
+TEST(ComponentExportTest, ImportExport) {
+  // Defined as 1. Treat as export.
+  EXPECT_EQ(1, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_A));
+
+  // Defined, but empty. Treat as import.
+  EXPECT_EQ(0, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_B));
+
+  // Defined, but 0. Treat as import.
+  EXPECT_EQ(0, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_C));
+
+  // Defined, but some other arbitrary thing that isn't 1. Treat as import.
+  EXPECT_EQ(0, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_D));
+  EXPECT_EQ(0, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_E));
+
+  // Undefined. Treat as import.
+  EXPECT_EQ(0, PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_F));
+
+  // And just for good measure, ensure that the macros evaluate properly in the
+  // context of preprocessor #if blocks.
+#if PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_A)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+
+#if !PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_B)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+
+#if !PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_C)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+
+#if !PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_D)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+
+#if !PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_E)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+
+#if !PA_INSIDE_COMPONENT_IMPL(TEST_COMPONENT_F)
+  EXPECT_TRUE(true);
+#else
+  EXPECT_TRUE(false);
+#endif
+}
+
+#undef IS_TEST_COMPONENT_A_IMPL
+#undef IS_TEST_COMPONENT_B_IMPL
+#undef IS_TEST_COMPONENT_C_IMPL
+#undef IS_TEST_COMPONENT_D_IMPL
+#undef IS_TEST_COMPONENT_E_IMPL
+
+}  // namespace
+}  // namespace partition_alloc::internal::base
diff --git a/base/allocator/partition_allocator/partition_alloc_base/cpu.h b/base/allocator/partition_allocator/partition_alloc_base/cpu.h
index 6e6d1d17..2ac93de7 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/cpu.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/cpu.h
@@ -5,14 +5,14 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_CPU_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_CPU_H_
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base {
 
 // Query information about the processor.
-class BASE_EXPORT CPU final {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CPU final {
  public:
   CPU();
   CPU(CPU&&);
diff --git a/base/allocator/partition_allocator/partition_alloc_base/debug/alias.h b/base/allocator/partition_allocator/partition_alloc_base/debug/alias.h
index 58188e5..1b89343 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/debug/alias.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/debug/alias.h
@@ -7,8 +7,8 @@
 
 #include <stddef.h>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 
 namespace partition_alloc::internal::base::debug {
 
@@ -71,7 +71,7 @@
 // stack variable (case #1) using base::debug::Alias() will also inhibit
 // tail calls for calls in earlier lines and prevent code folding.
 
-void BASE_EXPORT Alias(const void* var);
+void PA_COMPONENT_EXPORT(PARTITION_ALLOC) Alias(const void* var);
 
 }  // namespace partition_alloc::internal::base::debug
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/files/file_path.h b/base/allocator/partition_allocator/partition_alloc_base/files/file_path.h
index 9ba578c..dbdd513 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/files/file_path.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/files/file_path.h
@@ -106,8 +106,8 @@
 #include <iosfwd>
 #include <string>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 // Windows-style drive letter support and pathname separator characters can be
@@ -130,7 +130,7 @@
 
 // An abstraction to isolate users from the differences between native
 // pathnames on different platforms.
-class BASE_EXPORT FilePath {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) FilePath {
  public:
 #if BUILDFLAG(IS_WIN)
   // On Windows, for Unicode-aware applications, native pathnames are wchar_t
diff --git a/base/allocator/partition_allocator/partition_alloc_base/files/file_util.h b/base/allocator/partition_allocator/partition_alloc_base/files/file_util.h
index fa87291..6c1eeff0 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/files/file_util.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/files/file_util.h
@@ -12,7 +12,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
@@ -27,7 +27,8 @@
 // Read exactly |bytes| bytes from file descriptor |fd|, storing the result
 // in |buffer|. This function is protected against EINTR and partial reads.
 // Returns true iff |bytes| bytes have been successfully read from |fd|.
-BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+bool ReadFromFD(int fd, char* buffer, size_t bytes);
 
 #endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
index 7e6ec3c..78a8a9be 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
@@ -9,8 +9,8 @@
 #include <zircon/types.h>
 
 #include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 // Use the PA_ZX_LOG family of macros along with a zx_status_t containing a
@@ -19,7 +19,8 @@
 
 namespace partition_alloc::internal::logging {
 
-class BASE_EXPORT ZxLogMessage : public logging::LogMessage {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ZxLogMessage
+    : public logging::LogMessage {
  public:
   ZxLogMessage(const char* file_path,
                int line,
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging.cc b/base/allocator/partition_allocator/partition_alloc_base/logging.cc
index cd33a190..03c819c 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging.cc
@@ -13,10 +13,10 @@
 #error "logging.h should not include check.h"
 #endif
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -88,7 +88,8 @@
 // In DCHECK-enabled Chrome builds, allow the meaning of LOGGING_DCHECK to be
 // determined at run-time. We default it to INFO, to avoid it triggering
 // crashes before the run-time has explicitly chosen the behaviour.
-BASE_EXPORT logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+logging::LogSeverity LOGGING_DCHECK = LOGGING_INFO;
 #endif  // defined(DCHECK_IS_CONFIGURABLE)
 
 // This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have
@@ -188,7 +189,8 @@
 #endif
 }
 
-BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+std::string SystemErrorCodeToString(SystemErrorCode error_code) {
 #if BUILDFLAG(IS_WIN)
   const int kErrorMessageBufferSize = 256;
   char msgbuf[kErrorMessageBufferSize];
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging.h b/base/allocator/partition_allocator/partition_alloc_base/logging.h
index effd044d..9abf1d52 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging.h
@@ -14,9 +14,9 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 // TODO(1151236): Need to update the description, because logging for PA
@@ -142,16 +142,16 @@
 // up to level INFO) if this function is not called.
 // Note that log messages for VLOG(x) are logged at level -x, so setting
 // the min log level to negative values enables verbose logging.
-BASE_EXPORT void SetMinLogLevel(int level);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void SetMinLogLevel(int level);
 
 // Gets the current log level.
-BASE_EXPORT int GetMinLogLevel();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) int GetMinLogLevel();
 
 // Used by PA_LOG_IS_ON to lazy-evaluate stream arguments.
-BASE_EXPORT bool ShouldCreateLogMessage(int severity);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool ShouldCreateLogMessage(int severity);
 
 // Gets the PA_VLOG default verbosity level.
-BASE_EXPORT int GetVlogVerbosity();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) int GetVlogVerbosity();
 
 // Sets the Log Message Handler that gets passed every log message before
 // it's sent to other log destinations (if any).
@@ -162,8 +162,10 @@
                                           int line,
                                           size_t message_start,
                                           const std::string& str);
-BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
-BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void SetLogMessageHandler(LogMessageHandlerFunction handler);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+LogMessageHandlerFunction GetLogMessageHandler();
 
 using LogSeverity = int;
 constexpr LogSeverity LOGGING_VERBOSE = -1;  // This is level 1 verbosity
@@ -340,7 +342,7 @@
   PA_LAZY_STREAM(PA_PLOG_STREAM(severity), \
                  PA_LOG_IS_ON(severity) && (condition))
 
-BASE_EXPORT extern std::ostream* g_swallow_stream;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern std::ostream* g_swallow_stream;
 
 // Note that g_swallow_stream is used instead of an arbitrary PA_LOG() stream to
 // avoid the creation of an object with a non-trivial destructor (LogMessage).
@@ -400,7 +402,7 @@
 // Definitions for DCHECK et al.
 
 #if defined(DCHECK_IS_CONFIGURABLE)
-BASE_EXPORT extern LogSeverity LOGGING_DCHECK;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern LogSeverity LOGGING_DCHECK;
 #else
 constexpr LogSeverity LOGGING_DCHECK = LOGGING_FATAL;
 #endif  // defined(DCHECK_IS_CONFIGURABLE)
@@ -417,7 +419,7 @@
 // You shouldn't actually use LogMessage's constructor to log things,
 // though.  You should use the PA_LOG() macro (and variants thereof)
 // above.
-class BASE_EXPORT LogMessage {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LogMessage {
  public:
   // Used for PA_LOG(severity).
   LogMessage(const char* file, int line, LogSeverity severity);
@@ -469,12 +471,14 @@
 
 // Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
 // pull in windows.h just for GetLastError() and DWORD.
-BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
-BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) SystemErrorCode GetLastSystemErrorCode();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+std::string SystemErrorCodeToString(SystemErrorCode error_code);
 
 #if BUILDFLAG(IS_WIN)
 // Appends a formatted system message of the GetLastError() type.
-class BASE_EXPORT Win32ErrorLogMessage : public LogMessage {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) Win32ErrorLogMessage
+    : public LogMessage {
  public:
   Win32ErrorLogMessage(const char* file,
                        int line,
@@ -490,7 +494,7 @@
 };
 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 // Appends a formatted system message of the errno type
-class BASE_EXPORT ErrnoLogMessage : public LogMessage {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ErrnoLogMessage : public LogMessage {
  public:
   ErrnoLogMessage(const char* file,
                   int line,
@@ -507,7 +511,8 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 // Async signal safe logging mechanism.
-BASE_EXPORT void RawLog(int level, const char* message);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void RawLog(int level, const char* message);
 
 #define PA_RAW_LOG(level, message)              \
   ::partition_alloc::internal::logging::RawLog( \
diff --git a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
index 51c59095..5150fa3 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
@@ -8,15 +8,15 @@
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/atomic_ref_count.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/memory/scoped_refptr.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base {
 namespace subtle {
 
-class BASE_EXPORT RefCountedThreadSafeBase {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) RefCountedThreadSafeBase {
  public:
   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
diff --git a/base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h b/base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h
index 971a92e5..32849ff 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h
@@ -8,7 +8,6 @@
 #include <cstdint>
 #include <string>
 
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_MAC)
diff --git a/base/allocator/partition_allocator/partition_alloc_base/native_library.h b/base/allocator/partition_allocator/partition_alloc_base/native_library.h
index 1a71e40f..6e2f48b 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/native_library.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/native_library.h
@@ -10,9 +10,9 @@
 
 #include <string>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/files/file_path.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -46,7 +46,7 @@
 using NativeLibrary = void*;
 #endif  // OS_*
 
-struct BASE_EXPORT NativeLibraryLoadError {
+struct PA_COMPONENT_EXPORT(PARTITION_ALLOC) NativeLibraryLoadError {
 #if BUILDFLAG(IS_WIN)
   NativeLibraryLoadError() : code(0) {}
 #endif  // BUILDFLAG(IS_WIN)
@@ -61,7 +61,7 @@
 #endif  // BUILDFLAG(IS_WIN)
 };
 
-struct BASE_EXPORT NativeLibraryOptions {
+struct PA_COMPONENT_EXPORT(PARTITION_ALLOC) NativeLibraryOptions {
   NativeLibraryOptions() = default;
   NativeLibraryOptions(const NativeLibraryOptions& options) = default;
 
@@ -76,20 +76,22 @@
 // Loads a native library from disk.  Release it with UnloadNativeLibrary when
 // you're done.  Returns NULL on failure.
 // If |error| is not NULL, it may be filled in on load error.
-BASE_EXPORT NativeLibrary LoadNativeLibrary(const FilePath& library_path,
-                                            NativeLibraryLoadError* error);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                NativeLibraryLoadError* error);
 
 // Loads a native library from disk.  Release it with UnloadNativeLibrary when
 // you're done.  Returns NULL on failure.
 // If |error| is not NULL, it may be filled in on load error.
-BASE_EXPORT NativeLibrary
-LoadNativeLibraryWithOptions(const FilePath& library_path,
-                             const NativeLibraryOptions& options,
-                             NativeLibraryLoadError* error);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
+                                           const NativeLibraryOptions& options,
+                                           NativeLibraryLoadError* error);
 
 // Gets a function pointer from a native library.
-BASE_EXPORT void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
-                                                      const std::string& name);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const std::string& name);
 
 }  // namespace partition_alloc::internal::base
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/posix/safe_strerror.h b/base/allocator/partition_allocator/partition_alloc_base/posix/safe_strerror.h
index 4ccf2a8..57874837 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/posix/safe_strerror.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/posix/safe_strerror.h
@@ -9,8 +9,8 @@
 
 #include <string>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 
 namespace partition_alloc::internal::base {
 
@@ -30,7 +30,8 @@
 // result is always null-terminated. The value of errno is never changed.
 //
 // Use this instead of strerror_r().
-BASE_EXPORT void safe_strerror_r(int err, char* buf, size_t len);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void safe_strerror_r(int err, char* buf, size_t len);
 
 // Calls safe_strerror_r with a buffer of suitable size and returns the result
 // in a C++ string.
@@ -38,7 +39,7 @@
 // Use this instead of strerror(). Note though that safe_strerror_r will be
 // more robust in the case of heap corruption errors, since it doesn't need to
 // allocate a string.
-BASE_EXPORT std::string safe_strerror(int err);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) std::string safe_strerror(int err);
 
 }  // namespace partition_alloc::internal::base
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/rand_util.h b/base/allocator/partition_allocator/partition_alloc_base/rand_util.h
index 90fe77d..861bddc 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/rand_util.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/rand_util.h
@@ -8,9 +8,9 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/gtest_prod_util.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -20,17 +20,18 @@
 namespace partition_alloc::internal::base {
 
 // Returns a random number in range [0, UINT64_MAX]. Thread-safe.
-BASE_EXPORT uint64_t RandUint64();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) uint64_t RandUint64();
 
 // Returns a random number in range [0, range).  Thread-safe.
-BASE_EXPORT uint64_t RandGenerator(uint64_t range);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) uint64_t RandGenerator(uint64_t range);
 
 // Fills |output_length| bytes of |output| with random data. Thread-safe.
 //
 // Although implementations are required to use a cryptographically secure
 // random number source, code outside of base/ that relies on this should use
 // crypto::RandBytes instead to ensure the requirement is easily discoverable.
-BASE_EXPORT void RandBytes(void* output, size_t output_length);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void RandBytes(void* output, size_t output_length);
 
 // Fast, insecure pseudo-random number generator.
 //
@@ -58,7 +59,7 @@
 // re-seeded during use.
 //
 // Uses the XorShift128+ generator under the hood.
-class BASE_EXPORT InsecureRandomGenerator {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) InsecureRandomGenerator {
  public:
   // Never use outside testing, not enough entropy.
   void ReseedForTesting(uint64_t seed);
diff --git a/base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h b/base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h
index 7de6f01..3aab62a4 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h
@@ -7,8 +7,8 @@
 
 #include <errno.h>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base {
@@ -20,7 +20,7 @@
 
 // Common implementation of ScopedClearLastError for all platforms. Use
 // ScopedClearLastError instead.
-class BASE_EXPORT ScopedClearLastErrorBase {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ScopedClearLastErrorBase {
  public:
   ScopedClearLastErrorBase() : last_errno_(errno) { errno = 0; }
   ScopedClearLastErrorBase(const ScopedClearLastErrorBase&) = delete;
@@ -34,7 +34,8 @@
 #if BUILDFLAG(IS_WIN)
 
 // Windows specific implementation of ScopedClearLastError.
-class BASE_EXPORT ScopedClearLastError : public ScopedClearLastErrorBase {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ScopedClearLastError
+    : public ScopedClearLastErrorBase {
  public:
   ScopedClearLastError();
   ScopedClearLastError(const ScopedClearLastError&) = delete;
diff --git a/base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h b/base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h
index 56717a5..3802794 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h
@@ -10,7 +10,7 @@
 #include <string>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base {
@@ -21,9 +21,8 @@
 static constexpr size_t kMaxLengthOfTruncatingStringPrintfResult = 255U;
 
 // Return a C++ string given printf-like input.
-[[nodiscard]] BASE_EXPORT std::string TruncatingStringPrintf(const char* format,
-                                                             ...)
-    PA_PRINTF_FORMAT(1, 2);
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) std::string
+    TruncatingStringPrintf(const char* format, ...) PA_PRINTF_FORMAT(1, 2);
 
 }  // namespace partition_alloc::internal::base
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h
index 62a4dec..72a49fe 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h
@@ -13,10 +13,10 @@
 
 #include <iosfwd>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_ref.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -73,7 +73,7 @@
 typedef void (*SetThreadNameProc)(const std::string&);
 
 // A namespace for low-level thread functions.
-class BASE_EXPORT PlatformThread {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PlatformThread {
  public:
   PlatformThread() = delete;
   PlatformThread(const PlatformThread&) = delete;
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h
index 6693ce0..f1db740 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h
@@ -5,7 +5,7 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base::internal {
@@ -16,7 +16,7 @@
 // after going through clone() syscall which does not call pthread_atfork()
 // handlers).
 // This can only be called when the process is single-threaded.
-BASE_EXPORT void InvalidateTidCache();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void InvalidateTidCache();
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace partition_alloc::internal::base::internal
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_ref.h b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_ref.h
index c775edf..2f236d4 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_ref.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_ref.h
@@ -12,8 +12,8 @@
 
 #include <iosfwd>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
diff --git a/base/allocator/partition_allocator/partition_alloc_base/time/time.h b/base/allocator/partition_allocator/partition_alloc_base/time/time.h
index e596d99..0f5cd71 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/time/time.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/time/time.h
@@ -68,10 +68,10 @@
 #include <iosfwd>
 #include <limits>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/numerics/clamped_math.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 
@@ -120,7 +120,7 @@
 
 // TimeDelta ------------------------------------------------------------------
 
-class BASE_EXPORT TimeDelta {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) TimeDelta {
  public:
   constexpr TimeDelta() = default;
 
@@ -490,11 +490,11 @@
 // incrementing counter.
 #else
 // Returns true if the CPU support constant rate TSC.
-[[nodiscard]] BASE_EXPORT bool HasConstantRateTSC();
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) bool HasConstantRateTSC();
 
 // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
 // been measured yet. Needs to be guarded with a call to HasConstantRateTSC().
-[[nodiscard]] BASE_EXPORT double TSCTicksPerSecond();
+[[nodiscard]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) double TSCTicksPerSecond();
 #endif
 #endif  // BUILDFLAG(IS_WIN)
 
@@ -510,7 +510,8 @@
 // Represents a wall clock time in UTC. Values are not guaranteed to be
 // monotonically non-decreasing and are subject to large amounts of skew.
 // Time is stored internally as microseconds since the Windows epoch (1601).
-class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) Time
+    : public time_internal::TimeBase<Time> {
  public:
   // Offset of UNIX epoch (1970-01-01 00:00:00 UTC) from Windows FILETIME epoch
   // (1601-01-01 00:00:00 UTC), in microseconds. This value is derived from the
@@ -831,7 +832,8 @@
 // TimeTicks ------------------------------------------------------------------
 
 // Represents monotonically non-decreasing clock time.
-class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) TimeTicks
+    : public time_internal::TimeBase<TimeTicks> {
  public:
   // The underlying clock used to generate new TimeTicks.
   enum class Clock {
@@ -969,7 +971,8 @@
 
 // Represents a clock, specific to a particular thread, than runs only while the
 // thread is running.
-class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadTicks
+    : public time_internal::TimeBase<ThreadTicks> {
  public:
   constexpr ThreadTicks() : TimeBase(0) {}
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/time/time_override.h b/base/allocator/partition_allocator/partition_alloc_base/time/time_override.h
index 2823ea1e..d14e2fa1 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/time/time_override.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/time/time_override.h
@@ -7,8 +7,8 @@
 
 #include <atomic>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal::base {
@@ -31,7 +31,7 @@
 // time update isn't surprising. Instantiating a ScopedTimeClockOverrides while
 // other threads are running might break their expectation that TimeTicks and
 // ThreadTicks increase monotonically. Nested overrides are not allowed.
-class BASE_EXPORT ScopedTimeClockOverrides {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ScopedTimeClockOverrides {
  public:
   // Pass |nullptr| for any override if it shouldn't be overriden.
   ScopedTimeClockOverrides(TimeNowFunction time_override,
@@ -55,10 +55,12 @@
 // should only be used in places where emulated time should be disregarded. For
 // example, they can be used to implement test timeouts for tests that may
 // override time.
-BASE_EXPORT Time TimeNowIgnoringOverride();
-BASE_EXPORT Time TimeNowFromSystemTimeIgnoringOverride();
-BASE_EXPORT TimeTicks TimeTicksNowIgnoringOverride();
-BASE_EXPORT ThreadTicks ThreadTicksNowIgnoringOverride();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) Time TimeNowIgnoringOverride();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+Time TimeNowFromSystemTimeIgnoringOverride();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) TimeTicks TimeTicksNowIgnoringOverride();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+ThreadTicks ThreadTicksNowIgnoringOverride();
 
 }  // namespace subtle
 
diff --git a/base/allocator/partition_allocator/partition_alloc_forward.h b/base/allocator/partition_allocator/partition_alloc_forward.h
index 119ea87..b0c8f4e 100644
--- a/base/allocator/partition_allocator/partition_alloc_forward.h
+++ b/base/allocator/partition_allocator/partition_alloc_forward.h
@@ -10,7 +10,7 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 namespace partition_alloc {
 
@@ -46,7 +46,8 @@
 #if (BUILDFLAG(PA_DCHECK_IS_ON) ||                    \
      BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)) && \
     BUILDFLAG(USE_BACKUP_REF_PTR)
-BASE_EXPORT void CheckThatSlotOffsetIsZero(uintptr_t address);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void CheckThatSlotOffsetIsZero(uintptr_t address);
 #endif
 
 }  // namespace internal
diff --git a/base/allocator/partition_allocator/partition_alloc_hooks.h b/base/allocator/partition_allocator/partition_alloc_hooks.h
index ab153c74..48b08d7 100644
--- a/base/allocator/partition_allocator/partition_alloc_hooks.h
+++ b/base/allocator/partition_allocator/partition_alloc_hooks.h
@@ -8,13 +8,13 @@
 #include <atomic>
 #include <cstddef>
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 namespace partition_alloc {
 
 // PartitionAlloc supports setting hooks to observe allocations/frees as they
 // occur as well as 'override' hooks that allow overriding those operations.
-class BASE_EXPORT PartitionAllocHooks {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAllocHooks {
  public:
   // Log allocation and free events.
   typedef void AllocationObserverHook(void* address,
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 3f462186..8107f5d 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -17,6 +17,7 @@
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
@@ -1108,8 +1109,9 @@
   }
 }
 
-BASE_EXPORT bool CompareSlotSpans(SlotSpanMetadata<ThreadSafe>* a,
-                                  SlotSpanMetadata<ThreadSafe>* b) {
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+bool CompareSlotSpans(SlotSpanMetadata<ThreadSafe>* a,
+                      SlotSpanMetadata<ThreadSafe>* b) {
   auto criteria_tuple = [](SlotSpanMetadata<ThreadSafe> const* a) {
     size_t freelist_length = a->GetFreelistLength();
     // The criteria are, in order (hence the lexicographic comparison below):
diff --git a/base/allocator/partition_allocator/partition_bucket.h b/base/allocator/partition_allocator/partition_bucket.h
index 8a3fe95..d35ad9f 100644
--- a/base/allocator/partition_allocator/partition_bucket.h
+++ b/base/allocator/partition_allocator/partition_bucket.h
@@ -9,23 +9,25 @@
 #include <cstdint>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
-#include "base/base_export.h"
 
 namespace partition_alloc::internal {
 
 constexpr inline int kPartitionNumSystemPagesPerSlotSpanBits = 8;
 
 // Visible for testing.
-BASE_EXPORT uint8_t
-ComputeSystemPagesPerSlotSpan(size_t slot_size, bool prefer_smaller_slot_spans);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+uint8_t ComputeSystemPagesPerSlotSpan(size_t slot_size,
+                                      bool prefer_smaller_slot_spans);
 
 // Visible for testing.
-BASE_EXPORT bool CompareSlotSpans(SlotSpanMetadata<ThreadSafe>* a,
-                                  SlotSpanMetadata<ThreadSafe>* b);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+bool CompareSlotSpans(SlotSpanMetadata<ThreadSafe>* a,
+                      SlotSpanMetadata<ThreadSafe>* b);
 
 template <bool thread_safe>
 struct PartitionBucket {
@@ -61,7 +63,7 @@
   static constexpr size_t kMaxSlotSpansToSort = 200;
 
   // Public API.
-  BASE_EXPORT void Init(uint32_t new_slot_size);
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC) void Init(uint32_t new_slot_size);
 
   // Sets |is_already_zeroed| to true if the allocation was satisfied by
   // requesting (a) new page(s) from the operating system, or false otherwise.
@@ -71,12 +73,13 @@
   // |PartitionRoot::AllocFromBucket|.)
   //
   // Note the matching Free() functions are in SlotSpanMetadata.
-  BASE_EXPORT PA_NOINLINE uintptr_t SlowPathAlloc(
-      PartitionRoot<thread_safe>* root,
-      unsigned int flags,
-      size_t raw_size,
-      size_t slot_span_alignment,
-      bool* is_already_zeroed) PA_EXCLUSIVE_LOCKS_REQUIRED(root->lock_);
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+  PA_NOINLINE uintptr_t SlowPathAlloc(PartitionRoot<thread_safe>* root,
+                                      unsigned int flags,
+                                      size_t raw_size,
+                                      size_t slot_span_alignment,
+                                      bool* is_already_zeroed)
+      PA_EXCLUSIVE_LOCKS_REQUIRED(root->lock_);
 
   PA_ALWAYS_INLINE bool CanStoreRawSize() const {
     // For direct-map as well as single-slot slot spans (recognized by checking
@@ -137,7 +140,7 @@
   // Walks the entire active slot span list, and perform regular maintenance,
   // where empty, decommitted and full slot spans are moved to their
   // steady-state place.
-  BASE_EXPORT void MaintainActiveList();
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC) void MaintainActiveList();
 
   // Returns a slot number starting from the beginning of the slot span.
   PA_ALWAYS_INLINE size_t GetSlotNumber(size_t offset_in_slot_span) const {
@@ -155,7 +158,7 @@
   // Sort the freelists of all slot spans.
   void SortSlotSpanFreelists();
   // Sort the active slot span list in ascending freelist length.
-  BASE_EXPORT void SortActiveSlotSpans();
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC) void SortActiveSlotSpans();
 
  private:
   // Allocates a new slot span with size |num_partition_pages| from the
diff --git a/base/allocator/partition_allocator/partition_oom.h b/base/allocator/partition_allocator/partition_oom.h
index 5ecf0d5..56f4cf4f 100644
--- a/base/allocator/partition_allocator/partition_oom.h
+++ b/base/allocator/partition_allocator/partition_oom.h
@@ -11,7 +11,7 @@
 #include <stddef.h>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -23,8 +23,8 @@
 // g_oom_handling_function is invoked when PartitionAlloc hits OutOfMemory.
 extern OomFunction g_oom_handling_function;
 
-[[noreturn]] BASE_EXPORT PA_NOINLINE void PartitionExcessiveAllocationSize(
-    size_t size);
+[[noreturn]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) PA_NOINLINE
+    void PartitionExcessiveAllocationSize(size_t size);
 
 #if !defined(ARCH_CPU_64_BITS)
 [[noreturn]] PA_NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 9f6cdba5..59fe1129 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -16,6 +16,7 @@
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
@@ -26,7 +27,6 @@
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
@@ -172,11 +172,13 @@
   // in PartitionPage which has 2B worth of fields and must fit in 32B.
 
  public:
-  BASE_EXPORT explicit SlotSpanMetadata(PartitionBucket<thread_safe>* bucket);
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+  explicit SlotSpanMetadata(PartitionBucket<thread_safe>* bucket);
 
   // Public API
   // Note the matching Alloc() functions are in PartitionPage.
-  BASE_EXPORT PA_NOINLINE void FreeSlowPath(size_t number_of_freed);
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+  PA_NOINLINE void FreeSlowPath(size_t number_of_freed);
   PA_ALWAYS_INLINE PartitionFreelistEntry* PopForAlloc(size_t size);
   PA_ALWAYS_INLINE void Free(uintptr_t ptr);
   // Appends the passed freelist to the slot-span's freelist. Please note that
@@ -280,7 +282,8 @@
   PA_ALWAYS_INLINE void Reset();
 
   // TODO(ajwong): Can this be made private?  https://crbug.com/787153
-  BASE_EXPORT static SlotSpanMetadata* get_sentinel_slot_span();
+  PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+  static SlotSpanMetadata* get_sentinel_slot_span();
 
   // Slot span state getters.
   PA_ALWAYS_INLINE bool is_active() const;
diff --git a/base/allocator/partition_allocator/partition_ref_count.h b/base/allocator/partition_allocator/partition_ref_count.h
index 73288a36..bb0f7e3 100644
--- a/base/allocator/partition_allocator/partition_ref_count.h
+++ b/base/allocator/partition_allocator/partition_ref_count.h
@@ -10,13 +10,13 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
@@ -48,7 +48,7 @@
 //
 // This protects against double-free's, as we check whether the reference count
 // is odd in |ReleaseFromAllocator()|, and if not we have a double-free.
-class BASE_EXPORT PartitionRefCount {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRefCount {
  public:
   // This class holds an atomic bit field: `count_`. It holds up to 4 values:
   //
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index c9a0c51..2127867 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -13,6 +13,7 @@
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
@@ -1316,7 +1317,8 @@
   sort_active_slot_spans_ = true;
 }
 
-template struct BASE_EXPORT PartitionRoot<internal::ThreadSafe>;
+template struct PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    PartitionRoot<internal::ThreadSafe>;
 
 static_assert(offsetof(PartitionRoot<internal::ThreadSafe>, sentinel_bucket) ==
                   offsetof(PartitionRoot<internal::ThreadSafe>, buckets) +
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 0f9173d..00af320 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -44,6 +44,7 @@
 #include "base/allocator/partition_allocator/partition_alloc-inl.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
@@ -66,7 +67,6 @@
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
 #include "base/allocator/partition_allocator/tagging.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
-#include "base/base_export.h"
 #include "base/debug/debugging_buildflags.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
@@ -106,7 +106,8 @@
 // Avoid including partition_address_space.h from this .h file, by moving the
 // call to IsManagedByPartitionAllocBRPPool into the .cc file.
 #if BUILDFLAG(PA_DCHECK_IS_ON)
-BASE_EXPORT void DCheckIfManagedByPartitionAllocBRPPool(uintptr_t address);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void DCheckIfManagedByPartitionAllocBRPPool(uintptr_t address);
 #else
 PA_ALWAYS_INLINE void DCheckIfManagedByPartitionAllocBRPPool(
     uintptr_t address) {}
@@ -200,7 +201,7 @@
 // Never instantiate a PartitionRoot directly, instead use
 // PartitionAllocator.
 template <bool thread_safe>
-struct PA_ALIGNAS(64) BASE_EXPORT PartitionRoot {
+struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
   using SlotSpan = internal::SlotSpanMetadata<thread_safe>;
   using Page = internal::PartitionPage<thread_safe>;
   using Bucket = internal::PartitionBucket<thread_safe>;
diff --git a/base/allocator/partition_allocator/partition_stats.h b/base/allocator/partition_allocator/partition_stats.h
index 22dbc5b..cb51e53 100644
--- a/base/allocator/partition_allocator/partition_stats.h
+++ b/base/allocator/partition_allocator/partition_stats.h
@@ -8,9 +8,9 @@
 #include <cstddef>
 #include <cstdint>
 
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "base/base_export.h"
 
 namespace partition_alloc {
 
@@ -97,7 +97,7 @@
 
 // Interface that is passed to PartitionDumpStats and
 // PartitionDumpStats for using the memory statistics.
-class BASE_EXPORT PartitionStatsDumper {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionStatsDumper {
  public:
   // Called to dump total memory used by partition, once per partition.
   virtual void PartitionDumpTotals(const char* partition_name,
@@ -110,7 +110,8 @@
 
 // Simple version of PartitionStatsDumper, storing the returned stats in stats_.
 // Does not handle per-bucket stats.
-class BASE_EXPORT SimplePartitionStatsDumper : public PartitionStatsDumper {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) SimplePartitionStatsDumper
+    : public PartitionStatsDumper {
  public:
   SimplePartitionStatsDumper();
 
diff --git a/base/allocator/partition_allocator/partition_tls.h b/base/allocator/partition_allocator/partition_tls.h
index 4f8c699..5444a32 100644
--- a/base/allocator/partition_allocator/partition_tls.h
+++ b/base/allocator/partition_allocator/partition_tls.h
@@ -6,9 +6,9 @@
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TLS_H_
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_POSIX)
@@ -85,8 +85,8 @@
 // be lifted.
 using PartitionTlsKey = unsigned long;
 
-BASE_EXPORT bool PartitionTlsCreate(PartitionTlsKey* key,
-                                    void (*destructor)(void*));
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+bool PartitionTlsCreate(PartitionTlsKey* key, void (*destructor)(void*));
 
 PA_ALWAYS_INLINE void* PartitionTlsGet(PartitionTlsKey key) {
   // Accessing TLS resets the last error, which then makes |GetLastError()|
diff --git a/base/allocator/partition_allocator/random.h b/base/allocator/partition_allocator/random.h
index be7dec5..e724f24 100644
--- a/base/allocator/partition_allocator/random.h
+++ b/base/allocator/partition_allocator/random.h
@@ -7,7 +7,7 @@
 
 #include <stdint.h>
 
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 namespace partition_alloc {
 
@@ -17,14 +17,14 @@
 // `base::RandUint64` which is very unpredictable, but which is expensive due to
 // the need to call into the kernel. Therefore this generator uses a fast,
 // entirely user-space function after initialization.
-BASE_EXPORT uint32_t RandomValue();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) uint32_t RandomValue();
 
 }  // namespace internal
 
 // Sets the seed for the random number generator to a known value, to cause the
 // RNG to generate a predictable sequence of outputs. May be called multiple
 // times.
-BASE_EXPORT void SetMmapSeedForTesting(uint64_t seed);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void SetMmapSeedForTesting(uint64_t seed);
 
 }  // namespace partition_alloc
 
diff --git a/base/allocator/partition_allocator/reservation_offset_table.h b/base/allocator/partition_allocator/reservation_offset_table.h
index 0aee5f2..43804ba 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.h
+++ b/base/allocator/partition_allocator/reservation_offset_table.h
@@ -14,10 +14,10 @@
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc::internal {
@@ -62,7 +62,7 @@
 //    further determine which part of the supe page is used by PartitionAlloc.
 //    This isn't a problem in 64-bit mode, where allocation granularity is
 //    kSuperPageSize.
-class BASE_EXPORT ReservationOffsetTable {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ReservationOffsetTable {
  public:
 #if defined(PA_HAS_64_BITS_POINTERS)
   // There is one reservation offset table per Pool in 64-bit mode.
diff --git a/base/allocator/partition_allocator/spinning_mutex.h b/base/allocator/partition_allocator/spinning_mutex.h
index 480ec02b..5c922e6 100644
--- a/base/allocator/partition_allocator/spinning_mutex.h
+++ b/base/allocator/partition_allocator/spinning_mutex.h
@@ -10,11 +10,11 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/yield_processor.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -65,7 +65,7 @@
 // any awareness of other threads' behavior. One exception: x86 macOS uses
 // os_unfair_lock() if available, which is the case for macOS >= 10.12, that is
 // most clients.
-class PA_LOCKABLE BASE_EXPORT SpinningMutex {
+class PA_LOCKABLE PA_COMPONENT_EXPORT(PARTITION_ALLOC) SpinningMutex {
  public:
   inline constexpr SpinningMutex();
   PA_ALWAYS_INLINE void Acquire() PA_EXCLUSIVE_LOCK_FUNCTION();
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h
index 4da5c1f..13a0c3f 100644
--- a/base/allocator/partition_allocator/starscan/pcscan.h
+++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -9,12 +9,12 @@
 
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_direct_map_extent.h"
 #include "base/allocator/partition_allocator/partition_page.h"
 #include "base/allocator/partition_allocator/starscan/pcscan_scheduling.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/base_export.h"
 
 // Double free detection comes with expensive cmpxchg (with the loop around it).
 // We currently disable it to improve the runtime.
@@ -26,8 +26,8 @@
 
 namespace internal {
 
-[[noreturn]] BASE_EXPORT PA_NOINLINE PA_NOT_TAIL_CALLED void
-DoubleFreeAttempt();
+[[noreturn]] PA_COMPONENT_EXPORT(PARTITION_ALLOC) PA_NOINLINE PA_NOT_TAIL_CALLED
+    void DoubleFreeAttempt();
 
 // PCScan (Probabilistic Conservative Scanning) is the algorithm that eliminates
 // use-after-free bugs by verifying that there are no pointers in memory which
@@ -40,7 +40,7 @@
 // unreachable and therefore can be safely reclaimed.
 //
 // The driver class encapsulates the entire PCScan infrastructure.
-class BASE_EXPORT PCScan final {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PCScan final {
  public:
   using Root = PartitionRoot<ThreadSafe>;
   using SlotSpan = SlotSpanMetadata<ThreadSafe>;
diff --git a/base/allocator/partition_allocator/starscan/pcscan_scheduling.h b/base/allocator/partition_allocator/starscan/pcscan_scheduling.h
index 34d9ed9..b0b259c 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_scheduling.h
+++ b/base/allocator/partition_allocator/starscan/pcscan_scheduling.h
@@ -9,10 +9,10 @@
 #include <cstdint>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
-#include "base/base_export.h"
 
 namespace partition_alloc::internal {
 
@@ -33,7 +33,7 @@
   std::atomic<size_t> epoch{0u};
 };
 
-class BASE_EXPORT PCScanSchedulingBackend {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PCScanSchedulingBackend {
  public:
   explicit inline constexpr PCScanSchedulingBackend(PCScanScheduler&);
   // No virtual destructor to allow constant initialization of PCScan as
@@ -77,7 +77,8 @@
 };
 
 // Scheduling backend that just considers a single hard limit.
-class BASE_EXPORT LimitBackend final : public PCScanSchedulingBackend {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LimitBackend final
+    : public PCScanSchedulingBackend {
  public:
   static constexpr double kQuarantineSizeFraction = 0.1;
 
@@ -97,7 +98,7 @@
 // workload.
 //
 // See constants below for trigger mechanisms.
-class BASE_EXPORT MUAwareTaskBasedBackend final
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) MUAwareTaskBasedBackend final
     : public PCScanSchedulingBackend {
  public:
   using ScheduleDelayedScanFunc = void (*)(int64_t delay_in_microseconds);
@@ -139,7 +140,7 @@
 // path for freeing objects. The scheduler holds data needed to invoke a
 // `PCScanSchedulingBackend` upon hitting a limit. The backend implements
 // the actual scheduling strategy and is in charge of maintaining limits.
-class BASE_EXPORT PCScanScheduler final {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PCScanScheduler final {
  public:
   inline constexpr PCScanScheduler();
 
diff --git a/base/allocator/partition_allocator/starscan/stack/stack.h b/base/allocator/partition_allocator/starscan/stack/stack.h
index b4de003..89fe5cc 100644
--- a/base/allocator/partition_allocator/starscan/stack/stack.h
+++ b/base/allocator/partition_allocator/starscan/stack/stack.h
@@ -8,15 +8,15 @@
 #include <cstdint>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
-#include "base/base_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 
 namespace partition_alloc::internal {
 
 // Returns the current stack pointer.
 // TODO(bikineev,1202644): Remove this once base/stack_util.h lands.
-BASE_EXPORT PA_NOINLINE uintptr_t* GetStackPointer();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) PA_NOINLINE uintptr_t* GetStackPointer();
 // Returns the top of the stack using system API.
-BASE_EXPORT void* GetStackTop();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void* GetStackTop();
 
 // Interface for stack visitation.
 class StackVisitor {
@@ -27,7 +27,7 @@
 // Abstraction over the stack. Supports handling of:
 // - native stack;
 // - SafeStack: https://releases.llvm.org/10.0.0/tools/clang/docs/SafeStack.html
-class BASE_EXPORT Stack final {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) Stack final {
  public:
   // Sets start of the stack.
   explicit Stack(void* stack_top);
diff --git a/base/allocator/partition_allocator/tagging.h b/base/allocator/partition_allocator/tagging.h
index b9db910..b1135af 100644
--- a/base/allocator/partition_allocator/tagging.h
+++ b/base/allocator/partition_allocator/tagging.h
@@ -12,8 +12,8 @@
 #include <cstdint>
 
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -32,8 +32,8 @@
 };
 
 // Changes the memory tagging mode for the calling thread.
-BASE_EXPORT void ChangeMemoryTaggingModeForCurrentThread(
-    TagViolationReportingMode);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void ChangeMemoryTaggingModeForCurrentThread(TagViolationReportingMode);
 
 namespace internal {
 
@@ -46,17 +46,18 @@
 
 #if BUILDFLAG(IS_ANDROID)
 // Changes the memory tagging mode for all threads in the current process.
-BASE_EXPORT void ChangeMemoryTaggingModeForAllThreadsPerProcess(
-    TagViolationReportingMode);
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+void ChangeMemoryTaggingModeForAllThreadsPerProcess(TagViolationReportingMode);
 #endif
 
 // Gets the memory tagging mode for the calling thread.
-BASE_EXPORT TagViolationReportingMode GetMemoryTaggingModeForCurrentThread();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+TagViolationReportingMode GetMemoryTaggingModeForCurrentThread();
 
 // Called by the partition allocator after initial startup, this detects MTE
 // support in the current CPU and replaces the active tagging intrinsics with
 // MTE versions if needed.
-BASE_EXPORT void InitializeMTESupportIfNeeded();
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) void InitializeMTESupportIfNeeded();
 
 // These global function pointers hold the implementations of the tagging
 // intrinsics (TagMemoryRangeRandomly, TagMemoryRangeIncrement, RemaskPtr).
@@ -74,11 +75,12 @@
 using TagMemoryRangeRandomlyInternalFn = void*(void* ptr,
                                                size_t size,
                                                uint64_t mask);
-extern BASE_EXPORT TagMemoryRangeRandomlyInternalFn*
-    global_tag_memory_range_randomly_fn;
-extern BASE_EXPORT TagMemoryRangeIncrementInternalFn*
-    global_tag_memory_range_increment_fn;
-extern BASE_EXPORT RemaskPtrInternalFn* global_remask_void_ptr_fn;
+extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    TagMemoryRangeRandomlyInternalFn* global_tag_memory_range_randomly_fn;
+extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    TagMemoryRangeIncrementInternalFn* global_tag_memory_range_increment_fn;
+extern PA_COMPONENT_EXPORT(PARTITION_ALLOC)
+    RemaskPtrInternalFn* global_remask_void_ptr_fn;
 
 // Increments the tag of the memory range ptr. Useful for provable revocations
 // (e.g. free). Returns the pointer with the new tag. Ensures that the entire
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
index 8d0625d5..a927c42 100644
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -11,13 +11,13 @@
 #include <cstdint>
 
 #include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/cxx17_backports.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_root.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 namespace partition_alloc {
@@ -39,9 +39,9 @@
 
 namespace internal {
 
-BASE_EXPORT PartitionTlsKey g_thread_cache_key;
+PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionTlsKey g_thread_cache_key;
 #if defined(PA_THREAD_CACHE_FAST_TLS)
-BASE_EXPORT
+PA_COMPONENT_EXPORT(PARTITION_ALLOC)
 thread_local ThreadCache* g_thread_cache;
 #endif
 
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
index e7393fd6..ca8daba5 100644
--- a/base/allocator/partition_allocator/thread_cache.h
+++ b/base/allocator/partition_allocator/thread_cache.h
@@ -12,6 +12,7 @@
 
 #include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/gtest_prod_util.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
@@ -22,7 +23,6 @@
 #include "base/allocator/partition_allocator/partition_lock.h"
 #include "base/allocator/partition_allocator/partition_stats.h"
 #include "base/allocator/partition_allocator/partition_tls.h"
-#include "base/base_export.h"
 #include "build/build_config.h"
 
 #if defined(ARCH_CPU_X86_64) && defined(PA_HAS_64_BITS_POINTERS)
@@ -67,7 +67,7 @@
 
 namespace internal {
 
-extern BASE_EXPORT PartitionTlsKey g_thread_cache_key;
+extern PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionTlsKey g_thread_cache_key;
 // On Android, we have to go through emutls, since this is always a shared
 // library, so don't bother.
 #if defined(PA_THREAD_LOCAL_TLS) && !BUILDFLAG(IS_ANDROID)
@@ -75,7 +75,8 @@
 #endif
 
 #if defined(PA_THREAD_CACHE_FAST_TLS)
-extern BASE_EXPORT thread_local ThreadCache* g_thread_cache;
+extern PA_COMPONENT_EXPORT(
+    PARTITION_ALLOC) thread_local ThreadCache* g_thread_cache;
 #endif
 
 }  // namespace internal
@@ -96,7 +97,7 @@
 // This class cannot allocate in the (Un)registerThreadCache() functions, as
 // they are called from ThreadCache constructor, which is from within the
 // allocator. However the other members can allocate.
-class BASE_EXPORT ThreadCacheRegistry {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCacheRegistry {
  public:
   static ThreadCacheRegistry& Instance();
   // Do not instantiate.
@@ -220,7 +221,7 @@
 // manipulated, as it is a thread_local member. As such, any
 // |ThreadCache::instance->*()| call will necessarily be done from a single
 // thread.
-class BASE_EXPORT ThreadCache {
+class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
  public:
   // Initializes the thread cache for |root|. May allocate, so should be called
   // with the thread cache disabled on the partition side, and without the
diff --git a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
index 66f0f40..f1dc2c5 100644
--- a/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
+++ b/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
@@ -527,9 +527,14 @@
 }
 
 void PooledSingleThreadTaskRunnerManager::Start(
+    scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner,
     WorkerThreadObserver* worker_thread_observer) {
   DCHECK(!worker_thread_observer_);
   worker_thread_observer_ = worker_thread_observer;
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+  DCHECK(io_thread_task_runner);
+  io_thread_task_runner_ = std::move(io_thread_task_runner);
+#endif
 
   decltype(workers_) workers_to_start;
   {
@@ -544,7 +549,7 @@
   // unnecessary to call WakeUp() for each worker (in fact, an extraneous
   // WakeUp() would be racy and wrong - see https://crbug.com/862582).
   for (scoped_refptr<WorkerThread> worker : workers_to_start) {
-    worker->Start(worker_thread_observer_);
+    worker->Start(io_thread_task_runner_, worker_thread_observer_);
   }
 }
 
@@ -634,7 +639,7 @@
   }
 
   if (new_worker && started)
-    worker->Start(worker_thread_observer_);
+    worker->Start(io_thread_task_runner_, worker_thread_observer_);
 
   return MakeRefCounted<PooledSingleThreadTaskRunner>(this, traits, worker,
                                                       thread_mode);
diff --git a/base/task/thread_pool/pooled_single_thread_task_runner_manager.h b/base/task/thread_pool/pooled_single_thread_task_runner_manager.h
index 96e476e5..c217e00c 100644
--- a/base/task/thread_pool/pooled_single_thread_task_runner_manager.h
+++ b/base/task/thread_pool/pooled_single_thread_task_runner_manager.h
@@ -59,11 +59,15 @@
   ~PooledSingleThreadTaskRunnerManager();
 
   // Starts threads for existing SingleThreadTaskRunners and allows threads to
-  // be started when SingleThreadTaskRunners are created in the future. If
-  // specified, |worker_thread_observer| will be notified when a worker
-  // enters and exits its main function. It must not be destroyed before
-  // JoinForTesting() has returned (must never be destroyed in production).
-  void Start(WorkerThreadObserver* worker_thread_observer = nullptr);
+  // be started when SingleThreadTaskRunners are created in the future.
+  // `io_thread_task_runner` is used to setup FileDescriptorWatcher on worker
+  // threads. `io_thread_task_runner` must refer to a Thread with
+  // MessgaePumpType::IO. If specified, |worker_thread_observer| will be
+  // notified when a worker enters and exits its main function. It must not be
+  // destroyed before JoinForTesting() has returned (must never be destroyed in
+  // production).
+  void Start(scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner,
+             WorkerThreadObserver* worker_thread_observer = nullptr);
 
   // Wakes up workers as appropriate for the new CanRunPolicy policy. Must be
   // called after an update to CanRunPolicy in TaskTracker.
@@ -128,6 +132,8 @@
   const TrackedRef<TaskTracker> task_tracker_;
   const raw_ptr<DelayedTaskManager> delayed_task_manager_;
 
+  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
+
   // Optional observer notified when a worker enters and exits its main
   // function. Set in Start() and never modified afterwards.
   raw_ptr<WorkerThreadObserver> worker_thread_observer_ = nullptr;
diff --git a/base/task/thread_pool/pooled_single_thread_task_runner_manager_unittest.cc b/base/task/thread_pool/pooled_single_thread_task_runner_manager_unittest.cc
index e4889d9..266133c 100644
--- a/base/task/thread_pool/pooled_single_thread_task_runner_manager_unittest.cc
+++ b/base/task/thread_pool/pooled_single_thread_task_runner_manager_unittest.cc
@@ -65,7 +65,7 @@
   }
 
   virtual void StartSingleThreadTaskRunnerManagerFromSetUp() {
-    single_thread_task_runner_manager_->Start();
+    single_thread_task_runner_manager_->Start(service_thread_.task_runner());
   }
 
   virtual void TearDownSingleThreadTaskRunnerManager() {
@@ -688,7 +688,7 @@
   // flaky if the tested code allows that to happen.
   PlatformThread::Sleep(TestTimeouts::tiny_timeout());
   manager_started.Set();
-  single_thread_task_runner_manager_->Start();
+  single_thread_task_runner_manager_->Start(service_thread_.task_runner());
 
   // Wait for the task to complete to keep |manager_started| alive.
   task_finished.Wait();
diff --git a/base/task/thread_pool/task_tracker_posix.cc b/base/task/thread_pool/task_tracker_posix.cc
deleted file mode 100644
index 6da063aa..0000000
--- a/base/task/thread_pool/task_tracker_posix.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 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 "base/task/thread_pool/task_tracker_posix.h"
-
-#include <utility>
-
-#include "base/files/file_descriptor_watcher_posix.h"
-
-namespace base {
-namespace internal {
-
-TaskTrackerPosix::TaskTrackerPosix() = default;
-TaskTrackerPosix::~TaskTrackerPosix() = default;
-
-void TaskTrackerPosix::RunTask(Task task,
-                               TaskSource* task_source,
-                               const TaskTraits& traits) {
-  DCHECK(io_thread_task_runner_);
-  FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
-  TaskTracker::RunTask(std::move(task), task_source, traits);
-}
-
-}  // namespace internal
-}  // namespace base
diff --git a/base/task/thread_pool/task_tracker_posix.h b/base/task/thread_pool/task_tracker_posix.h
deleted file mode 100644
index 856b336..0000000
--- a/base/task/thread_pool/task_tracker_posix.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 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 BASE_TASK_THREAD_POOL_TASK_TRACKER_POSIX_H_
-#define BASE_TASK_THREAD_POOL_TASK_TRACKER_POSIX_H_
-
-#include <memory>
-#include <utility>
-
-#include "base/base_export.h"
-#include "base/message_loop/message_pump_type.h"
-#include "base/task/thread_pool/task_tracker.h"
-#include "base/threading/platform_thread.h"
-
-namespace base {
-namespace internal {
-
-struct Task;
-
-// A TaskTracker that instantiates a FileDescriptorWatcher in the scope in which
-// a task runs. Used on all POSIX platforms except NaCl SFI.
-// set_io_thread_task_runner() must be called before the
-// TaskTracker can run tasks.
-class BASE_EXPORT TaskTrackerPosix : public TaskTracker {
- public:
-  TaskTrackerPosix();
-  TaskTrackerPosix(const TaskTrackerPosix&) = delete;
-  TaskTrackerPosix& operator=(const TaskTrackerPosix&) = delete;
-  ~TaskTrackerPosix() override;
-
-  // Sets the task runner with which to setup FileDescriptorWatcher in
-  // the scope in which tasks run. |io_thread_task_runner| must refer to
-  // a Thread with MessagePumpType::IO.
-  // Must be called before starting to run tasks.
-  // External synchronization is required between a call to this and a call to
-  // RunTask().
-  void set_io_thread_task_runner(
-      scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner) {
-    io_thread_task_runner_ = std::move(io_thread_task_runner);
-  }
-
- protected:
-  // TaskTracker:
-  void RunTask(Task task,
-               TaskSource* task_source,
-               const TaskTraits& traits) override;
-
- private:
-  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
-};
-
-}  // namespace internal
-}  // namespace base
-
-#endif  // BASE_TASK_THREAD_POOL_TASK_TRACKER_POSIX_H_
diff --git a/base/task/thread_pool/task_tracker_posix_unittest.cc b/base/task/thread_pool/task_tracker_posix_unittest.cc
deleted file mode 100644
index 316a8a2..0000000
--- a/base/task/thread_pool/task_tracker_posix_unittest.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2016 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 "base/task/thread_pool/task_tracker_posix.h"
-
-#include <unistd.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_descriptor_watcher_posix.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_pump_type.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/run_loop.h"
-#include "base/sequence_token.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool/task.h"
-#include "base/task/thread_pool/test_utils.h"
-#include "base/test/null_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace internal {
-
-namespace {
-
-class ThreadPoolTaskTrackerPosixTest : public testing::Test {
- public:
-  ThreadPoolTaskTrackerPosixTest() : service_thread_("ServiceThread") {
-    Thread::Options service_thread_options;
-    service_thread_options.message_pump_type = MessagePumpType::IO;
-    service_thread_.StartWithOptions(std::move(service_thread_options));
-    tracker_.set_io_thread_task_runner(service_thread_.task_runner());
-  }
-  ThreadPoolTaskTrackerPosixTest(const ThreadPoolTaskTrackerPosixTest&) =
-      delete;
-  ThreadPoolTaskTrackerPosixTest& operator=(
-      const ThreadPoolTaskTrackerPosixTest&) = delete;
-
- protected:
-  Thread service_thread_;
-  TaskTrackerPosix tracker_;
-};
-
-}  // namespace
-
-// Verify that TaskTrackerPosix runs a Task it receives.
-TEST_F(ThreadPoolTaskTrackerPosixTest, RunTask) {
-  bool did_run = false;
-  Task task(
-      FROM_HERE,
-      BindOnce([](bool* did_run) { *did_run = true; }, Unretained(&did_run)),
-      TimeTicks::Now(), TimeDelta());
-  constexpr TaskTraits default_traits;
-
-  EXPECT_TRUE(tracker_.WillPostTask(&task, default_traits.shutdown_behavior()));
-
-  auto sequence = test::CreateSequenceWithTask(std::move(task), default_traits);
-  // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after
-  // popping a task from it.
-  EXPECT_FALSE(test::QueueAndRunTaskSource(&tracker_, std::move(sequence)));
-
-  EXPECT_TRUE(did_run);
-}
-
-// Verify that FileDescriptorWatcher::WatchReadable() can be called from a task
-// running in TaskTrackerPosix without a crash.
-TEST_F(ThreadPoolTaskTrackerPosixTest, FileDescriptorWatcher) {
-  int fds[2];
-  ASSERT_EQ(0, pipe(fds));
-  Task task(FROM_HERE,
-            BindOnce(IgnoreResult(&FileDescriptorWatcher::WatchReadable),
-                     fds[0], DoNothing()),
-            TimeTicks::Now(), TimeDelta());
-  constexpr TaskTraits default_traits;
-
-  EXPECT_TRUE(tracker_.WillPostTask(&task, default_traits.shutdown_behavior()));
-
-  // FileDescriptorWatcher::WatchReadable needs a SequencedTaskRunnerHandle.
-  auto sequence = test::CreateSequenceWithTask(
-      std::move(task), default_traits, MakeRefCounted<NullTaskRunner>(),
-      TaskSourceExecutionMode::kSequenced);
-
-  // Expect RunAndPopNextTask to return nullptr since |sequence| is empty after
-  // popping a task from it.
-  EXPECT_FALSE(test::QueueAndRunTaskSource(&tracker_, std::move(sequence)));
-
-  // Join the service thread to make sure that the read watch is registered and
-  // unregistered before file descriptors are closed.
-  service_thread_.Stop();
-
-  EXPECT_EQ(0, IGNORE_EINTR(close(fds[0])));
-  EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
-}
-
-}  // namespace internal
-}  // namespace base
diff --git a/base/task/thread_pool/thread_group_impl.cc b/base/task/thread_pool/thread_group_impl.cc
index 55e654f..e010855 100644
--- a/base/task/thread_pool/thread_group_impl.cc
+++ b/base/task/thread_pool/thread_group_impl.cc
@@ -183,7 +183,8 @@
     // enters its main function, is descheduled because it wasn't woken up yet,
     // and is woken up immediately after.
     workers_to_start_.ForEachWorker([&](WorkerThread* worker) {
-      worker->Start(outer_->after_start().worker_thread_observer);
+      worker->Start(outer_->after_start().service_thread_task_runner,
+                    outer_->after_start().worker_thread_observer);
       if (outer_->worker_started_for_testing_)
         outer_->worker_started_for_testing_->Wait();
     });
@@ -389,7 +390,7 @@
     int max_tasks,
     int max_best_effort_tasks,
     TimeDelta suggested_reclaim_time,
-    scoped_refptr<SequencedTaskRunner> service_thread_task_runner,
+    scoped_refptr<SingleThreadTaskRunner> service_thread_task_runner,
     WorkerThreadObserver* worker_thread_observer,
     WorkerEnvironment worker_environment,
     bool synchronous_thread_start_for_testing,
diff --git a/base/task/thread_pool/thread_group_impl.h b/base/task/thread_pool/thread_group_impl.h
index 844373d9..0952b0ca 100644
--- a/base/task/thread_pool/thread_group_impl.h
+++ b/base/task/thread_pool/thread_group_impl.h
@@ -63,23 +63,25 @@
                   TrackedRef<Delegate> delegate);
 
   // Creates threads, allowing existing and future tasks to run. The thread
-  // group runs at most |max_tasks| / |max_best_effort_tasks| unblocked task
+  // group runs at most |max_tasks| / `max_best_effort_tasks` unblocked task
   // with any / BEST_EFFORT priority concurrently. It reclaims unused threads
-  // after |suggested_reclaim_time|. It uses |service_thread_task_runner| to
-  // monitor for blocked tasks. If specified, it notifies
-  // |worker_thread_observer| when a worker enters and exits its main function
-  // (the observer must not be destroyed before JoinForTesting() has returned).
-  // |worker_environment| specifies the environment in which tasks are executed.
+  // after `suggested_reclaim_time`. It uses `service_thread_task_runner` to
+  // monitor for blocked tasks, `service_thread_task_runner` is used to setup
+  // FileDescriptorWatcher on worker threads. It must refer to a Thread with
+  // MessagePumpType::IO. If specified, it notifies |worker_thread_observer|
+  // when a worker enters and exits its main function (the observer must not be
+  // destroyed before JoinForTesting() has returned). |worker_environment|
+  // specifies the environment in which tasks are executed.
   // |may_block_threshold| is the timeout after which a task in a MAY_BLOCK
   // ScopedBlockingCall is considered blocked (the thread group will choose an
   // appropriate value if none is specified).
-  // |synchronous_thread_start_for_testing| is true if this ThreadGroupImpl
+  // `synchronous_thread_start_for_testing` is true if this ThreadGroupImpl
   // should synchronously wait for OnMainEntry() after starting each worker. Can
   // only be called once. CHECKs on failure.
   void Start(int max_tasks,
              int max_best_effort_tasks,
              TimeDelta suggested_reclaim_time,
-             scoped_refptr<SequencedTaskRunner> service_thread_task_runner,
+             scoped_refptr<SingleThreadTaskRunner> service_thread_task_runner,
              WorkerThreadObserver* worker_thread_observer,
              WorkerEnvironment worker_environment,
              bool synchronous_thread_start_for_testing = false,
@@ -246,7 +248,7 @@
     // Environment to be initialized per worker.
     WorkerEnvironment worker_environment = WorkerEnvironment::NONE;
 
-    scoped_refptr<SequencedTaskRunner> service_thread_task_runner;
+    scoped_refptr<SingleThreadTaskRunner> service_thread_task_runner;
 
     // Optional observer notified when a worker enters and exits its main.
     raw_ptr<WorkerThreadObserver> worker_thread_observer = nullptr;
diff --git a/base/task/thread_pool/thread_group_native_mac.h b/base/task/thread_pool/thread_group_native_mac.h
index 4c8365dd..d0465f5b 100644
--- a/base/task/thread_pool/thread_group_native_mac.h
+++ b/base/task/thread_pool/thread_group_native_mac.h
@@ -25,10 +25,15 @@
 // https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
 class BASE_EXPORT ThreadGroupNativeMac : public ThreadGroupNative {
  public:
-  ThreadGroupNativeMac(ThreadPriority priority_hint,
-                       TrackedRef<TaskTracker> task_tracker,
-                       TrackedRef<Delegate> delegate,
-                       ThreadGroup* predecessor_thread_group = nullptr);
+  // `io_thread_task_runner` is used to setup FileDescriptorWatcher on worker
+  // threads. `io_thread_task_runner` must refer to a Thread with
+  // MessgaePumpType::IO
+  ThreadGroupNativeMac(
+      ThreadPriority priority_hint,
+      scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner,
+      TrackedRef<TaskTracker> task_tracker,
+      TrackedRef<Delegate> delegate,
+      ThreadGroup* predecessor_thread_group = nullptr);
 
   ThreadGroupNativeMac(const ThreadGroupNativeMac&) = delete;
   ThreadGroupNativeMac& operator=(const ThreadGroupNativeMac&) = delete;
@@ -48,6 +53,9 @@
 
   // Dispatch group to enable synchronization.
   ScopedDispatchObject<dispatch_group_t> group_;
+
+  // Service thread task runner.
+  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
 };
 
 using ThreadGroupNativeImpl = ThreadGroupNativeMac;
diff --git a/base/task/thread_pool/thread_group_native_mac.mm b/base/task/thread_pool/thread_group_native_mac.mm
index b2c5157..ca4b40c3 100644
--- a/base/task/thread_pool/thread_group_native_mac.mm
+++ b/base/task/thread_pool/thread_group_native_mac.mm
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/task/thread_pool/thread_group_native_mac.h"
+#include "base/files/file_descriptor_watcher_posix.h"
 
 #include "base/check.h"
 #include "base/task/thread_pool/task_tracker.h"
@@ -12,16 +13,19 @@
 
 ThreadGroupNativeMac::ThreadGroupNativeMac(
     ThreadPriority priority_hint,
+    scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner,
     TrackedRef<TaskTracker> task_tracker,
     TrackedRef<Delegate> delegate,
     ThreadGroup* predecessor_thread_group)
     : ThreadGroupNative(std::move(task_tracker),
                         std::move(delegate),
                         predecessor_thread_group),
-      priority_hint_(priority_hint) {
+      priority_hint_(priority_hint),
+      io_thread_task_runner_(std::move(io_thread_task_runner)) {
   // The thread group only support NORMAL or BACKGROUND priority.
   DCHECK(priority_hint_ == ThreadPriority::NORMAL ||
          priority_hint_ == ThreadPriority::BACKGROUND);
+  DCHECK(io_thread_task_runner_);
 }
 
 ThreadGroupNativeMac::~ThreadGroupNativeMac() {}
@@ -43,6 +47,7 @@
 
 void ThreadGroupNativeMac::SubmitWork() {
   dispatch_group_async(group_, queue_, ^{
+    FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
     RunNextTaskSourceImpl();
   });
 }
diff --git a/base/task/thread_pool/thread_group_unittest.cc b/base/task/thread_pool/thread_group_unittest.cc
index c22fad80..47ddd473 100644
--- a/base/task/thread_pool/thread_group_unittest.cc
+++ b/base/task/thread_pool/thread_group_unittest.cc
@@ -132,7 +132,7 @@
       case test::GroupType::NATIVE:
         thread_group_ = std::make_unique<ThreadGroupNativeType>(
 #if BUILDFLAG(IS_APPLE)
-            ThreadPriority::NORMAL,
+            ThreadPriority::NORMAL, service_thread_.task_runner(),
 #endif
             task_tracker_.GetTrackedRef(),
             tracked_ref_factory_.GetTrackedRef());
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc
index 2265dc2..8925596 100644
--- a/base/task/thread_pool/thread_pool_impl.cc
+++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -137,34 +137,6 @@
   const int max_best_effort_tasks =
       std::min(kMaxBestEffortTasks, init_params.max_num_foreground_threads);
 
-#if HAS_NATIVE_THREAD_POOL()
-  if (FeatureList::IsEnabled(kUseNativeThreadPool)) {
-    std::unique_ptr<ThreadGroup> old_group =
-        std::move(foreground_thread_group_);
-    foreground_thread_group_ = std::make_unique<ThreadGroupNativeImpl>(
-#if BUILDFLAG(IS_APPLE)
-        ThreadPriority::NORMAL,
-#endif
-        task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef(),
-        old_group.get());
-    old_group->InvalidateAndHandoffAllTaskSourcesToOtherThreadGroup(
-        foreground_thread_group_.get());
-  }
-
-  if (FeatureList::IsEnabled(kUseBackgroundNativeThreadPool)) {
-    std::unique_ptr<ThreadGroup> old_group =
-        std::move(background_thread_group_);
-    background_thread_group_ = std::make_unique<ThreadGroupNativeImpl>(
-#if BUILDFLAG(IS_APPLE)
-        ThreadPriority::BACKGROUND,
-#endif
-        task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef(),
-        old_group.get());
-    old_group->InvalidateAndHandoffAllTaskSourcesToOtherThreadGroup(
-        background_thread_group_.get());
-  }
-#endif
-
   // Start the service thread. On platforms that support it (POSIX except NaCL
   // SFI), the service thread runs a MessageLoopForIO which is used to support
   // FileDescriptorWatcher in the scope in which tasks run.
@@ -180,11 +152,33 @@
   if (g_synchronous_thread_start_for_testing)
     service_thread_.WaitUntilThreadStarted();
 
-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
-  // Needs to happen after starting the service thread to get its
-  // task_runner().
-  task_tracker_->set_io_thread_task_runner(service_thread_.task_runner());
-#endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+#if HAS_NATIVE_THREAD_POOL()
+  if (FeatureList::IsEnabled(kUseNativeThreadPool)) {
+    std::unique_ptr<ThreadGroup> old_group =
+        std::move(foreground_thread_group_);
+    foreground_thread_group_ = std::make_unique<ThreadGroupNativeImpl>(
+#if BUILDFLAG(IS_APPLE)
+        ThreadPriority::NORMAL, service_thread_.task_runner(),
+#endif
+        task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef(),
+        old_group.get());
+    old_group->InvalidateAndHandoffAllTaskSourcesToOtherThreadGroup(
+        foreground_thread_group_.get());
+  }
+
+  if (FeatureList::IsEnabled(kUseBackgroundNativeThreadPool)) {
+    std::unique_ptr<ThreadGroup> old_group =
+        std::move(background_thread_group_);
+    background_thread_group_ = std::make_unique<ThreadGroupNativeImpl>(
+#if BUILDFLAG(IS_APPLE)
+        ThreadPriority::BACKGROUND, service_thread_.task_runner(),
+#endif
+        task_tracker_->GetTrackedRef(), tracked_ref_factory_.GetTrackedRef(),
+        old_group.get());
+    old_group->InvalidateAndHandoffAllTaskSourcesToOtherThreadGroup(
+        background_thread_group_.get());
+  }
+#endif
 
   // Update the CanRunPolicy based on |has_disable_best_effort_switch_|.
   UpdateCanRunPolicy();
@@ -193,7 +187,8 @@
   auto service_thread_task_runner = service_thread_.task_runner();
   delayed_task_manager_.Start(service_thread_task_runner);
 
-  single_thread_task_runner_manager_.Start(worker_thread_observer);
+  single_thread_task_runner_manager_.Start(service_thread_task_runner,
+                                           worker_thread_observer);
 
   ThreadGroup::WorkerEnvironment worker_environment;
   switch (init_params.common_thread_pool_environment) {
diff --git a/base/task/thread_pool/thread_pool_impl.h b/base/task/thread_pool/thread_pool_impl.h
index 1a86782..b8d679c 100644
--- a/base/task/thread_pool/thread_pool_impl.h
+++ b/base/task/thread_pool/thread_pool_impl.h
@@ -29,11 +29,7 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/task/updateable_sequenced_task_runner.h"
 #include "build/build_config.h"
-
-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
-#include "base/task/thread_pool/task_tracker_posix.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#endif
 
 #if BUILDFLAG(IS_WIN)
 #include "base/win/com_init_check_hook.h"
@@ -49,12 +45,7 @@
                                    public ThreadGroup::Delegate,
                                    public PooledTaskRunnerDelegate {
  public:
-  using TaskTrackerImpl =
-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
-      TaskTrackerPosix;
-#else
-      TaskTracker;
-#endif
+  using TaskTrackerImpl = TaskTracker;
 
   // Creates a ThreadPoolImpl with a production TaskTracker. |histogram_label|
   // is used to label histograms. No histograms are recorded if it is empty.
diff --git a/base/task/thread_pool/thread_pool_impl_unittest.cc b/base/task/thread_pool/thread_pool_impl_unittest.cc
index b1bfb9c..5a127a6 100644
--- a/base/task/thread_pool/thread_pool_impl_unittest.cc
+++ b/base/task/thread_pool/thread_pool_impl_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/containers/span.h"
 #include "base/debug/stack_trace.h"
 #include "base/memory/raw_ptr.h"
+#include "base/message_loop/message_pump_type.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/system/sys_info.h"
@@ -287,7 +288,12 @@
 class ThreadPoolImplTestBase : public testing::Test {
  public:
   ThreadPoolImplTestBase()
-      : thread_pool_(std::make_unique<ThreadPoolImpl>("Test")) {}
+      : thread_pool_(std::make_unique<ThreadPoolImpl>("Test")),
+        service_thread_("ServiceThread") {
+    Thread::Options service_thread_options;
+    service_thread_options.message_pump_type = MessagePumpType::IO;
+    service_thread_.StartWithOptions(std::move(service_thread_options));
+  }
 
   ThreadPoolImplTestBase(const ThreadPoolImplTestBase&) = delete;
   ThreadPoolImplTestBase& operator=(const ThreadPoolImplTestBase&) = delete;
@@ -322,6 +328,7 @@
   virtual GroupTypes GetGroupTypes() const = 0;
 
   std::unique_ptr<ThreadPoolImpl> thread_pool_;
+  Thread service_thread_;
 
  private:
   void SetupFeatures() {
@@ -959,6 +966,31 @@
 }
 #endif  // BUILDFLAG(IS_POSIX)
 
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+
+// Verify that FileDescriptorWatcher::WatchReadable() can be called from task
+// running on a task_runner with GetExecutionMode() without a crash.
+TEST_P(ThreadPoolImplTest_CoverAllSchedulingOptions, FileDescriptorWatcher) {
+  StartThreadPool();
+
+  int fds[2];
+  ASSERT_EQ(0, pipe(fds));
+
+  auto task_runner = CreateTaskRunnerAndExecutionMode(
+      thread_pool_.get(), GetTraits(), GetExecutionMode());
+
+  EXPECT_TRUE(task_runner->PostTask(
+      FROM_HERE, BindOnce(IgnoreResult(&FileDescriptorWatcher::WatchReadable),
+                          fds[0], DoNothing())));
+
+  thread_pool_->FlushForTesting();
+
+  EXPECT_EQ(0, IGNORE_EINTR(close(fds[0])));
+  EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
+}
+
+#endif
+
 // Verify that tasks posted on the same sequence access the same values on
 // SequenceLocalStorage, and tasks on different sequences see different values.
 TEST_P(ThreadPoolImplTest, SequenceLocalStorage) {
diff --git a/base/task/thread_pool/worker_thread.cc b/base/task/thread_pool/worker_thread.cc
index 489f6b99..c206142 100644
--- a/base/task/thread_pool/worker_thread.cc
+++ b/base/task/thread_pool/worker_thread.cc
@@ -25,6 +25,10 @@
 #include "build/build_config.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+#include "base/files/file_descriptor_watcher_posix.h"
+#endif
+
 #if BUILDFLAG(IS_APPLE)
 #include "base/mac/scoped_nsautorelease_pool.h"
 #endif
@@ -94,11 +98,18 @@
   wake_up_event_.declare_only_used_while_idle();
 }
 
-bool WorkerThread::Start(WorkerThreadObserver* worker_thread_observer) {
+bool WorkerThread::Start(
+    scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner,
+    WorkerThreadObserver* worker_thread_observer) {
   CheckedLock::AssertNoLockHeldOnCurrentThread();
   CheckedAutoLock auto_lock(thread_lock_);
   DCHECK(thread_handle_.is_null());
 
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+  DCHECK(io_thread_task_runner);
+  io_thread_task_runner_ = std::move(io_thread_task_runner);
+#endif
+
   if (should_exit_.IsSet() || join_called_for_testing_.IsSet())
     return true;
 
@@ -221,6 +232,11 @@
 }
 
 void WorkerThread::ThreadMain() {
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
+  DCHECK(io_thread_task_runner_);
+  FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
+#endif
+
   if (priority_hint_ == ThreadPriority::BACKGROUND) {
     switch (delegate_->GetThreadLabel()) {
       case ThreadLabel::POOLED:
diff --git a/base/task/thread_pool/worker_thread.h b/base/task/thread_pool/worker_thread.h
index dcf73bda..3fedb5c9 100644
--- a/base/task/thread_pool/worker_thread.h
+++ b/base/task/thread_pool/worker_thread.h
@@ -115,11 +115,14 @@
 
   // Creates a thread to back the WorkerThread. The thread will be in a wait
   // state pending a WakeUp() call. No thread will be created if Cleanup() was
-  // called. If specified, |worker_thread_observer| will be notified when the
-  // worker enters and exits its main function. It must not be destroyed before
-  // JoinForTesting() has returned (must never be destroyed in production).
-  // Returns true on success.
-  bool Start(WorkerThreadObserver* worker_thread_observer = nullptr);
+  // called. `io_thread_task_runner` is used to setup FileDescriptorWatcher on
+  // worker threads. `io_thread_task_runner` must refer to a Thread with
+  // MessgaePumpType::IO. If specified, |worker_thread_observer| will be
+  // notified when the worker enters and exits its main function. It must not be
+  // destroyed before JoinForTesting() has returned (must never be destroyed in
+  // production). Returns true on success.
+  bool Start(scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_,
+             WorkerThreadObserver* worker_thread_observer = nullptr);
 
   // Wakes up this WorkerThread if it wasn't already awake. After this is
   // called, this WorkerThread will run Tasks from TaskSources returned by
@@ -244,6 +247,9 @@
 
   // Set once JoinForTesting() has been called.
   AtomicFlag join_called_for_testing_;
+
+  // Service thread task runner.
+  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
 };
 
 }  // namespace internal
diff --git a/base/task/thread_pool/worker_thread_unittest.cc b/base/task/thread_pool/worker_thread_unittest.cc
index 521c8d80..463902f 100644
--- a/base/task/thread_pool/worker_thread_unittest.cc
+++ b/base/task/thread_pool/worker_thread_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/message_loop/message_pump_type.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/task/common/checked_lock.h"
 #include "base/task/thread_pool/environment_config.h"
@@ -33,6 +34,7 @@
 #include "base/test/test_waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/simple_thread.h"
+#include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -83,7 +85,11 @@
   ThreadPoolWorkerTest& operator=(const ThreadPoolWorkerTest&) = delete;
 
  protected:
-  ThreadPoolWorkerTest() : num_get_work_cv_(lock_.CreateConditionVariable()) {}
+  ThreadPoolWorkerTest() : num_get_work_cv_(lock_.CreateConditionVariable()) {
+    Thread::Options service_thread_options;
+    service_thread_options.message_pump_type = MessagePumpType::IO;
+    service_thread_.StartWithOptions(std::move(service_thread_options));
+  }
 
   void SetUp() override {
     worker_ = MakeRefCounted<WorkerThread>(
@@ -91,7 +97,7 @@
         std::make_unique<TestWorkerThreadDelegate>(this),
         task_tracker_.GetTrackedRef());
     ASSERT_TRUE(worker_);
-    worker_->Start();
+    worker_->Start(service_thread_.task_runner());
     worker_set_.Signal();
     main_entry_called_.Wait();
   }
@@ -139,6 +145,7 @@
   }
 
   scoped_refptr<WorkerThread> worker_;
+  Thread service_thread_ = Thread("ServiceThread");
 
  private:
   class TestWorkerThreadDelegate : public WorkerThreadDefaultDelegate {
@@ -534,6 +541,10 @@
 // Verify that calling WorkerThread::Cleanup() from GetWork() causes
 // the WorkerThread's thread to exit.
 TEST(ThreadPoolWorkerTest, WorkerCleanupFromGetWork) {
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   // Will be owned by WorkerThread.
   MockedControllableCleanupDelegate* delegate =
@@ -545,7 +556,7 @@
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, WrapUnique(delegate),
                                    task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
   worker->WakeUp();
   controls->WaitForWorkToRun();
   Mock::VerifyAndClear(delegate);
@@ -555,6 +566,10 @@
 }
 
 TEST(ThreadPoolWorkerTest, WorkerCleanupDuringWork) {
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   // Will be owned by WorkerThread.
   // No mock here as that's reasonably covered by other tests and the delegate
@@ -569,7 +584,7 @@
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, std::move(delegate),
                                    task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
   worker->WakeUp();
 
   controls->WaitForWorkToRun();
@@ -580,6 +595,10 @@
 }
 
 TEST(ThreadPoolWorkerTest, WorkerCleanupDuringWait) {
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   // Will be owned by WorkerThread.
   // No mock here as that's reasonably covered by other tests and the delegate
@@ -592,7 +611,7 @@
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, std::move(delegate),
                                    task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
   worker->WakeUp();
 
   controls->WaitForCleanupRequest();
@@ -603,6 +622,10 @@
 
 TEST(ThreadPoolWorkerTest, WorkerCleanupDuringShutdown) {
   TaskTracker task_tracker;
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   // Will be owned by WorkerThread.
   // No mock here as that's reasonably covered by other tests and the delegate
   // may destroy on a different thread. Mocks aren't designed with that in mind.
@@ -616,7 +639,7 @@
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, std::move(delegate),
                                    task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
   worker->WakeUp();
 
   controls->WaitForWorkToRun();
@@ -629,6 +652,10 @@
 
 // Verify that Start() is a no-op after Cleanup().
 TEST(ThreadPoolWorkerTest, CleanupBeforeStart) {
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   // Will be owned by WorkerThread.
   // No mock here as that's reasonably covered by other tests and the delegate
@@ -644,7 +671,7 @@
                                    task_tracker.GetTrackedRef());
 
   worker->Cleanup();
-  worker->Start();
+  worker->Start(service_thread.task_runner());
 
   EXPECT_FALSE(worker->ThreadAliveForTesting());
 }
@@ -677,6 +704,10 @@
 }  // namespace
 
 TEST(ThreadPoolWorkerTest, WorkerCleanupDuringJoin) {
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   // Will be owned by WorkerThread.
   // No mock here as that's reasonably covered by other tests and the
@@ -692,7 +723,7 @@
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, std::move(delegate),
                                    task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
   worker->WakeUp();
 
   controls->WaitForWorkToRun();
@@ -763,6 +794,10 @@
     return;
 
   TaskTracker task_tracker;
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
 
   // Block shutdown to ensure that the worker doesn't exit when StartShutdown()
   // is called.
@@ -779,7 +814,7 @@
   auto worker = MakeRefCounted<WorkerThread>(ThreadPriority::BACKGROUND,
                                              std::move(delegate),
                                              task_tracker.GetTrackedRef());
-  worker->Start();
+  worker->Start(service_thread.task_runner());
 
   // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread
   // priority can't be increased).
@@ -826,12 +861,16 @@
 TEST(ThreadPoolWorkerTest, WorkerThreadObserver) {
   StrictMock<test::MockWorkerThreadObserver> observer;
   TaskTracker task_tracker;
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   auto delegate = std::make_unique<VerifyCallsToObserverDelegate>(&observer);
   auto worker =
       MakeRefCounted<WorkerThread>(ThreadPriority::NORMAL, std::move(delegate),
                                    task_tracker.GetTrackedRef());
   EXPECT_CALL(observer, OnWorkerThreadMainEntry());
-  worker->Start(&observer);
+  worker->Start(service_thread.task_runner(), &observer);
   worker->Cleanup();
   // Join the worker to avoid leaks.
   worker->JoinForTesting();
@@ -884,6 +923,10 @@
   base::internal::PartitionAllocMalloc::Allocator()
       ->EnableThreadCacheIfSupported();
 
+  Thread service_thread = Thread("ServiceThread");
+  Thread::Options service_thread_options;
+  service_thread_options.message_pump_type = MessagePumpType::IO;
+  service_thread.StartWithOptions(std::move(service_thread_options));
   TaskTracker task_tracker;
   auto delegate = std::make_unique<WorkerThreadThreadCacheDelegate>();
   auto* delegate_raw = delegate.get();
@@ -892,7 +935,7 @@
                                    task_tracker.GetTrackedRef());
   // Wake up before the thread is started to make sure the first sleep is short.
   worker->WakeUp();
-  worker->Start(nullptr);
+  worker->Start(service_thread.task_runner(), nullptr);
 
   while (delegate_raw->first_wakeup_done_.load(std::memory_order_acquire)) {
   }
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index c5621c3..f8f30cdad 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -175,10 +175,11 @@
     trace_event_internal::AddMetadataEvent
 
 // Defines atomic operations used internally by the tracing system.
+// Acquire/release barriers are important here: crbug.com/1330114#c8.
 #define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
-#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var))
+#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::Acquire_Load(&(var))
 #define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
-    base::subtle::NoBarrier_Store(&(var), (value))
+  base::subtle::Release_Store(&(var), (value))
 
 // Defines visibility for classes in trace_event.h
 #define TRACE_EVENT_API_CLASS_EXPORT BASE_EXPORT
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index ad16a8a..6fd132f 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -464,10 +464,6 @@
         'com.google.common.flogger.backend.google.GooglePlatform',
         'com.google.common.flogger.backend.system.DefaultPlatform',
 
-        # trichrome_webview_google_bundle contains this missing reference.
-        # TODO(crbug.com/1142530): Fix this missing reference properly.
-        'org.chromium.build.NativeLibraries',
-
         # TODO(agrieve): Exclude these only when use_jacoco_coverage=true.
         'java.lang.instrument.ClassFileTransformer',
         'java.lang.instrument.IllegalClassFormatException',
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 1a9b3736..6c119948 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2133,6 +2133,7 @@
   #     uncompressed in the APK. Must be unset or true if load_library_from_apk
   #     is set to true.
   #   uncompress_dex: Store final .dex files uncompressed in the apk.
+  #   omit_dex: If true, do not build or include classes.dex.
   #   strip_resource_names: True if resource names should be stripped from the
   #     resources.arsc file in the apk or module.
   #   strip_unused_resources: True if unused resources should be stripped from
@@ -2215,6 +2216,7 @@
           defined(invoker.is_base_module) && invoker.is_base_module
     }
 
+    _omit_dex = defined(invoker.omit_dex) && invoker.omit_dex
     _enable_multidex =
         !defined(invoker.enable_multidex) || invoker.enable_multidex
 
@@ -2358,12 +2360,13 @@
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
     assert(_rebased_build_config != "")  # Mark as used.
 
-    _generate_buildconfig_java = !defined(invoker.apk_under_test)
+    _generate_buildconfig_java = !defined(invoker.apk_under_test) && !_omit_dex
     if (defined(invoker.generate_buildconfig_java)) {
       _generate_buildconfig_java = invoker.generate_buildconfig_java
     }
 
-    _generate_productconfig_java = defined(invoker.product_config_java_packages)
+    _generate_productconfig_java =
+        defined(invoker.product_config_java_packages) && !_omit_dex
 
     # JNI generation usually goes hand-in-hand with buildconfig generation.
     _generate_final_jni = _generate_buildconfig_java
@@ -2427,7 +2430,7 @@
       _incremental_apk_path = "${_final_apk_path_no_ext}_incremental.apk"
     }
 
-    if (!_incremental_apk) {
+    if (!_incremental_apk && !_omit_dex) {
       # Bundle modules don't build the dex here, but need to write this path
       # to their .build_config.json file.
       if (_proguard_enabled) {
@@ -2684,8 +2687,9 @@
     } else {
       _generate_native_libraries_java =
           (!_is_bundle_module || _is_base_module) &&
-          (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) &&
-          !_uses_static_library_synchronized_proguard
+          (_native_libs_deps != [] || _secondary_abi_native_libs_deps != [] ||
+           defined(invoker.static_library_provider)) &&
+          !_uses_static_library_synchronized_proguard && !_omit_dex
     }
     if (_generate_native_libraries_java) {
       write_native_libraries_java("${_template_name}__native_libraries") {
@@ -2694,7 +2698,17 @@
         # Do not add a dep on the generated_file target in order to avoid having
         # to build the native libraries before this target. The dependency is
         # instead captured via a depfile.
-        if (_native_libs_deps != []) {
+        if (_uses_static_library) {
+          _prefix = get_label_info(invoker.static_library_provider,
+                                   "target_gen_dir") + "/" +
+                    get_label_info(invoker.static_library_provider, "name")
+          if (defined(invoker.static_library_provider_use_secondary_abi) &&
+              invoker.static_library_provider_use_secondary_abi) {
+            native_libraries_list_file = "${_prefix}.secondary_abi_native_libs"
+          } else {
+            native_libraries_list_file = "${_prefix}.native_libs"
+          }
+        } else if (_native_libs_deps != []) {
           native_libraries_list_file = _shared_library_list_file
         } else {
           native_libraries_list_file = _secondary_abi_shared_library_list_file
@@ -2790,14 +2804,15 @@
                  ])
     }
 
-    _java_target = "${_template_name}__java"
-
     if (_is_bundle_module) {
       _add_view_trace_events =
           defined(invoker.add_view_trace_events) &&
           invoker.add_view_trace_events && enable_trace_event_bytecode_rewriting
     }
 
+    # We cannot skip this target when omit_dex = true because it writes the
+    # build_config.json.
+    _java_target = "${_template_name}__java"
     java_library_impl(_java_target) {
       forward_variables_from(invoker,
                              [
@@ -2929,7 +2944,7 @@
 
     if (_uses_static_library_synchronized_proguard) {
       _final_dex_target_dep = "${invoker.static_library_provider}__dexsplitter"
-    } else if (_is_bundle_module && _proguard_enabled) {
+    } else if ((_is_bundle_module && _proguard_enabled) || _omit_dex) {
       _final_deps += [ ":$_java_target" ]
     } else if (_incremental_apk) {
       if (defined(invoker.enable_proguard_checks)) {
@@ -3205,7 +3220,7 @@
         deps = _deps + [ ":$_build_config_target" ]
 
         if ((!_proguard_enabled || _incremental_apk) &&
-            enable_jdk_library_desugaring) {
+            enable_jdk_library_desugaring && !_omit_dex) {
           _all_jdk_libs = "//build/android:all_jdk_libs"
           deps += [ _all_jdk_libs ]
           jdk_libs_dex = get_label_info(_all_jdk_libs, "target_out_dir") +
@@ -3485,6 +3500,7 @@
                                "expected_libs_and_assets_base",
                                "generate_buildconfig_java",
                                "generate_final_jni",
+                               "generate_native_libraries_java",
                                "include_size_info",
                                "input_jars_paths",
                                "use_modern_linker",
@@ -3509,6 +3525,7 @@
                                "native_lib_placeholders",
                                "never_incremental",
                                "no_xml_namespaces",
+                               "omit_dex",
                                "png_to_webp",
                                "post_process_package_resources_script",
                                "processor_args_javac",
@@ -3533,6 +3550,7 @@
                                "srcjar_deps",
                                "static_library_dependent_targets",
                                "static_library_provider",
+                               "static_library_provider_use_secondary_abi",
                                "static_library_synchronized_proguard",
                                "target_sdk_version",
                                "testonly",
@@ -3632,6 +3650,7 @@
                                "load_library_from_apk",
                                "loadable_modules",
                                "product_config_java_packages",
+                               "main_component_library",
                                "manifest_package",
                                "max_sdk_version",
                                "min_sdk_version",
@@ -3660,6 +3679,7 @@
                                "short_resource_paths",
                                "srcjar_deps",
                                "static_library_provider",
+                               "static_library_provider_use_secondary_abi",
                                "static_library_synchronized_proguard",
                                "strip_resource_names",
                                "strip_unused_resources",
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index cead68a..5421b86 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1233,19 +1233,24 @@
   testonly = true
 
   sources = [
+    "javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java",
     "javatests/src/org/chromium/chrome/browser/homepage/HomepageTestRule.java",
     "javatests/src/org/chromium/chrome/browser/tabmodel/TestTabModelDirectory.java",
   ]
 
   deps = [
     "//base:base_java",
+    "//chrome/android:chrome_java",
     "//chrome/browser/preferences:java",
+    "//chrome/browser/profiles/android:java",
+    "//components/offline_items_collection/core:core_java",
     "//components/policy/android:policy_java",
     "//components/policy/android:policy_java_test_support",
     "//content/public/test/android:content_java_test_support",
     "//third_party/android_support_test_runner:runner_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/junit:junit",
+    "//url:gurl_java",
   ]
 }
 
@@ -1275,6 +1280,7 @@
     "//chrome/android:chrome_java",
     "//chrome/browser/android/browserservices/intents:java",
     "//chrome/browser/flags:java",
+    "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/test/android:chrome_java_test_support",
@@ -1304,6 +1310,8 @@
   resources_package = "org.chromium.chrome.test"
   sources = [
     "javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java",
+    "javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java",
+    "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java",
     "javatests/src/org/chromium/chrome/browser/tab/WebContentsStateBridgeTest.java",
     "javatests/src/org/chromium/chrome/browser/tabmodel/AsyncTabCreationParamsManagerTest.java",
     "javatests/src/org/chromium/chrome/browser/tabmodel/RestoreMigrateTest.java",
@@ -1328,10 +1336,12 @@
     "//chrome/browser/ui/android/omnibox:java",
     "//chrome/browser/ui/android/toolbar:java",
     "//chrome/test/android:chrome_java_test_support",
+    "//components/browser_ui/notifications/android:java",
     "//components/browser_ui/settings/android:java",
     "//components/embedder_support/android:context_menu_java",
     "//components/embedder_support/android:util_java",
     "//components/externalauth/android:java",
+    "//components/offline_items_collection/core:core_java",
     "//components/prefs/android:java",
     "//components/search_engines/android:java",
     "//components/security_state/content/android:java",
@@ -1339,6 +1349,7 @@
     "//content/public/android:content_full_java",
     "//content/public/test/android:content_java_test_support",
     "//third_party/android_deps:espresso_java",
+    "//third_party/android_sdk:android_test_base_java",
     "//third_party/android_support_test_runner:runner_java",
     "//third_party/androidx:androidx_test_runner_java",
     "//third_party/blink/public:blink_headers_java",
@@ -2924,12 +2935,6 @@
   }
 }
 
-# TODO(agrieve): Remove this once we switch to using bundle targets to
-# generate APK stubs.
-android_resources("trichrome_dummy_resources") {
-  sources = [ "trichrome/res_dummy/values/strings.xml" ]
-}
-
 chrome_public_unit_test_apk_manifest =
     "$root_gen_dir/chrome_public_unit_test_apk_manifest/AndroidManifest.xml"
 chrome_public_test_apk_manifest =
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 6fb71709..87220dc 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -235,6 +235,19 @@
       use_chromium_linker = chromium_linker_supported
     }
 
+    if (_is_trichrome) {
+      static_library_provider_use_secondary_abi = _is_secondary_abi_primary
+
+      # http://crbug.com/1042107.
+      if (is_component_build) {
+        if (android_64bit_target_cpu && _is_64_bit_browser) {
+          main_component_library = "libmonochrome_64.cr.so"
+        } else {
+          main_component_library = "libmonochrome.cr.so"
+        }
+      }
+    }
+
     if (!_is_monochrome && !_is_trichrome) {
       deps += [
         "//chrome/android:chrome_public_v8_assets",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index d9f8908..747c7d2 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -189,15 +189,12 @@
   "javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java",
   "javatests/src/org/chromium/chrome/browser/download/AutoDownloadsTest.java",
   "javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java",
-  "javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadLocationChangeEnd2EndTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java",
-  "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadSettingsTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java",
-  "javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java",
   "javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/download/ServicificationDownloadTest.java",
   "javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java",
diff --git a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
index fd2f714..cb6d641c 100644
--- a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
@@ -10,6 +10,7 @@
   <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31"/>
   <application
       android:extractNativeLibs="false"
+      android:hasCode="false"
       android:icon="@drawable/icon_webview"
       android:label="Trichrome Library"
       android:multiArch="true"
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 97e9ddd..070efc3 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -18,6 +18,7 @@
 
     <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
     <application
+        android:hasCode="false"
         android:label="{{ application_label|default('Trichrome Library') }}"
         android:icon="@drawable/icon_webview"
         android:multiArch="true"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 7c106d4d..1fefc6f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -34,6 +34,7 @@
     static final String RELATED_SEARCHES_NEEDS_CONTENT_PARAM_NAME = "needs_content";
     // A comma-separated list of lower-case ISO 639 language codes.
     static final String RELATED_SEARCHES_LANGUAGE_ALLOWLIST_PARAM_NAME = "language_allowlist";
+    static final String RELATED_SEARCHES_LANGUAGE_DEFAULT_ALLOWLIST = "en";
     private static final String RELATED_SEARCHES_CONFIG_STAMP_PARAM_NAME = "stamp";
 
     static final String RELATED_SEARCHES_SHOW_DEFAULT_QUERY_CHIP_PARAM_NAME = "default_query_chip";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStamp.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStamp.java
index dcccf2e..0b9996c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStamp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStamp.java
@@ -8,6 +8,7 @@
 import android.text.TextUtils;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 
@@ -41,6 +42,7 @@
             + RELATED_SEARCHES_EXPERIMENT_RECIPE_STAGE + RELATED_SEARCHES_NO_EXPERIMENT;
 
     private final ContextualSearchPolicy mPolicy;
+    private boolean mDisableDefaultAllowedLanguagesForTesting;
 
     /**
      * Verbosity param used to control requested results.
@@ -114,9 +116,7 @@
     String getRelatedSearchesStamp(String basePageLanguage) {
         if (!isRelatedSearchesQualifiedAndEnabled(basePageLanguage)) return "";
 
-        boolean isLanguageRestricted =
-                !TextUtils.isEmpty(ContextualSearchFieldTrial.getRelatedSearchesParam(
-                        ContextualSearchFieldTrial.RELATED_SEARCHES_LANGUAGE_ALLOWLIST_PARAM_NAME));
+        boolean isLanguageRestricted = !TextUtils.isEmpty(getAllowedLanguages());
         return buildRelatedSearchesStamp(isLanguageRestricted);
     }
 
@@ -168,8 +168,7 @@
      * @return whether the supplied parameter satisfies the current language requirement.
      */
     private boolean isLanguageQualified(String basePageLanguage) {
-        String allowedLanguages = ContextualSearchFieldTrial.getRelatedSearchesParam(
-                ContextualSearchFieldTrial.RELATED_SEARCHES_LANGUAGE_ALLOWLIST_PARAM_NAME);
+        String allowedLanguages = getAllowedLanguages();
         return TextUtils.isEmpty(allowedLanguages) || allowedLanguages.contains(basePageLanguage);
     }
 
@@ -245,4 +244,20 @@
         if (resultsToReturnCode.length() > 0) stampBuilder.append(resultsToReturnCode);
         return stampBuilder.toString();
     }
+
+    private String getAllowedLanguages() {
+        String allowedLanguages = ContextualSearchFieldTrial.getRelatedSearchesParam(
+                ContextualSearchFieldTrial.RELATED_SEARCHES_LANGUAGE_ALLOWLIST_PARAM_NAME);
+        // If there is no language found, we use default language list.
+        if (TextUtils.isEmpty(allowedLanguages) && !mDisableDefaultAllowedLanguagesForTesting) {
+            allowedLanguages =
+                    ContextualSearchFieldTrial.RELATED_SEARCHES_LANGUAGE_DEFAULT_ALLOWLIST;
+        }
+        return allowedLanguages;
+    }
+
+    @VisibleForTesting
+    void disableDefaultAllowedLanguagesForTesting(boolean disableDefaultAllowedLanguages) {
+        mDisableDefaultAllowedLanguagesForTesting = disableDefaultAllowedLanguages;
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStampTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStampTest.java
index e2df6c7..5597d0c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStampTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesStampTest.java
@@ -162,6 +162,7 @@
         resetShadows();
         mPolicy = new ContextualSearchPolicy(null, null);
         mStamp = new RelatedSearchesStamp(mPolicy);
+        mStamp.disableDefaultAllowedLanguagesForTesting(true);
     }
 
     //====================================================================================
diff --git a/chrome/android/proguard/trichrome.flags b/chrome/android/proguard/trichrome.flags
deleted file mode 100644
index 68fb39a..0000000
--- a/chrome/android/proguard/trichrome.flags
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(agrieve): Once this -keep is removed, add a @CheckDiscard to LibraryLoaderConfig.java.
-# Currently the Trichrome library just contains NativeLibraries, which we keep.
-# https://crbug.com/901465
--keep class org.chromium.build.NativeLibraries { *; }
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index c509e883..1765693 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -115,7 +115,7 @@
       product_version_resources_dep =
           "//chrome/android:product_version_resources"
     } else {
-      generate_buildconfig_java = false
+      omit_dex = true
     }
 
     # TODO(torne): using icon_resources just to get a temporary icon
@@ -195,37 +195,6 @@
         }
       }
     }
-
-    # http://crbug.com/1042107.
-    if (is_component_build) {
-      if (android_64bit_target_cpu && invoker.is_64_bit_browser) {
-        main_component_library = "libmonochrome_64.cr.so"
-      } else {
-        main_component_library = "libmonochrome.cr.so"
-      }
-    }
-
-    if (!is_java_debug) {
-      proguard_enabled = true
-      proguard_configs = [
-        "//base/android/proguard/chromium_apk.flags",
-        "//base/android/proguard/chromium_code.flags",
-        "//chrome/android/proguard/trichrome.flags",
-      ]
-      if (trichrome_synchronized_proguard) {
-        proguard_configs += [
-          "//chrome/android/proguard/static_library_dex_reference_workarounds.flags",
-          "//base/android/proguard/enable_obfuscation.flags",
-        ]
-      } else {
-        # Disabling all obfuscation for the Trichrome library as a temporary
-        # workaround for crbug.com/1012842. There were naming conflicts between
-        # Library and Chrome, since each Proguard run doesn't know about the
-        # other, and thus handed out the first names (a, b, c) to both.
-        proguard_enable_obfuscation = false
-      }
-    }
-    deps += [ "//chrome/android:trichrome_dummy_resources" ]
   }
 }
 
diff --git a/chrome/android/trichrome/res_dummy/values/strings.xml b/chrome/android/trichrome/res_dummy/values/strings.xml
deleted file mode 100644
index a0d71c24..0000000
--- a/chrome/android/trichrome/res_dummy/values/strings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<!-- DO NOT ADD MORE RESOURCES HERE -->
-<resources>
-    <string name="dummy"></string>
-</resources>
\ No newline at end of file
diff --git a/chrome/android/trichrome/static_library_shared_java_code.md b/chrome/android/trichrome/static_library_shared_java_code.md
deleted file mode 100644
index a288902..0000000
--- a/chrome/android/trichrome/static_library_shared_java_code.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Static Library Java code
-
-[TOC]
-
-## Overview
-
-This document describes how static library targets can be used to share common
-Java code between multiple APKs. More detail can be found at
-[go/proguarding-trichrome](goto.google.com/proguarding-trichrome).
-
-## TrichromeLibrary
-
-Currently (Jan 2020) trichrome library is the only target to make use of static
-shared library APKs and is used to share common code used by both Chrome and
-Webview.
-
-## Status
-
-Java code sharing is mostly implemented at this point but there is one remaining
-blocker related to how
-[native method resolution works in Webview](crbug.com/1025009).
-
-## How it works
-
-### Build variables
-
-For `android_apk_or_module` base templates:
-
-`static_library_provider`: Specifies that this target depends on a static shared
-library APK. When synchronized proguard is turned on, the
-`static_library_provider` becomes the target that provides the final dex file.
-
-`static_library_dependent_targets`: If set, generates final dex files for
-itself and for all targets in the `static_library_dependent_targets` list.
-
-`static_library_synchronized_proguard`: Turns on synchronized proguard for
-targets that also set `static_library_provider`.
-
-### .build_config
-
-`write_build_config.py` is responsible for figuring out where code and related
-artifacts for the `static_library_provider` and
-`static_library_dependent_targets` belongs. The main difference from regular
-`.build_configs` is the mapping recording which input jars belong to each final
-dex file. Ex:
-
-```
-"deps_info": {
-  ...
-  "static_library_dependent_classpath_configs": {
-      "gen/android_webview/trichrome_webview_apk.build_config.json": [
-        "obj/android_webview/trichrome_webview_apk/trichrome_webview_apk.jar",
-        ...
-      ],
-      "gen/chrome/android/trichrome_chrome_bundle.build_config.json": [
-        "lib.java/chrome/android/app_hooks_java.jar",
-        ...
-      "gen/chrome/android/trichrome_library_apk.build_config.json": [
-        "lib.java/base/base_java.jar",
-        ...
-      ]
-      ...
-  }
-}
-```
-
-### Synchronized ProGuard
-
-TrichromeChromeBundle (base module) and TrichromeWebview do not have a final
-`dex` or `proguard` step. Instead the library APK creates a "fat" dex from the
-`.build_config.json:deps_info:java_runtime_classpath`.
-
-Then, the mapping of `.build_config.json` -> owned input jars stored in the
-`.build_config.json` is used by `dexsplitter` to generate final .dex files for
-TrichromeLibrary, TrichromeChrome, and TrichromeWebview.
-
-### Resources
-
-For Java code to be shared between Chrome and Webview in [Trichrome][trichrome],
-we ensure that Chrome and Webview use the same resource IDs. This requires a
-few adjustments to how resources are created.
-
-1. Webview's resources are compiled first without any changes.
-2. Chrome's resources are compiled second, but use the same resource IDs as
-   Webview when possible.
-3. When synchronized proguarding is turned on, the `R.java` files generated in
-   the previous step are discarded. The shared static library APK target
-   (trichrome library) takes the output `R.txt` files from the previous steps
-   and includes those resources in its own `R.java` generation.
-
-[trichrome]: /chrome/android/trichrome/static_library_shared_java_code.md
-
-### Usage
-
-* Building trichrome_chrome_bundle or trichrome_webview_apk (and various arch
-  variants) will ensure the correct library target is also built.
-* Using the generated wrapper script from the main APK is sufficient (no need
-  to explicitly install the library).
-  * `bin/trichrome_chrome_bundle run` will ensure TrichromeChromeBundle and
-    TrichromeLibrary are installed before launching Chrome.
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 6ca1b7d..b5a7c2f 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -576,7 +576,12 @@
 ChromeMainDelegate::~ChromeMainDelegate() {
 }
 
-void ChromeMainDelegate::PostEarlyInitialization(bool is_running_tests) {
+void ChromeMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
+  if (invoked_in == InvokedIn::kChildProcess) {
+    CommonEarlyInitialization();
+    return;
+  }
+
 #if BUILDFLAG(IS_WIN)
   // Initialize the cleaner of left-behind tmp files now that the main thread
   // has its SequencedTaskRunner; see https://crbug.com/1075917.
@@ -584,7 +589,7 @@
 
   // For now, do not enable delay load failure hooks for browser process except
   // in tests, where failures really shouldn't happen.
-  if (!is_running_tests)
+  if (invoked_in != InvokedIn::kBrowserProcessUnderTest)
     chrome::DisableDelayLoadFailureHooksForCurrentModule();
 #endif
 
@@ -647,11 +652,12 @@
       chrome_content_browser_client_->startup_data()
           ->chrome_feature_list_creator();
   chrome_feature_list_creator->CreateFeatureList();
-  PostFieldTrialInitialization();
+  CommonEarlyInitialization();
 
   // Initializes the resource bundle and determines the locale.
   std::string actual_locale =
-      LoadLocalState(chrome_feature_list_creator, is_running_tests);
+      LoadLocalState(chrome_feature_list_creator,
+                     invoked_in == InvokedIn::kBrowserProcessUnderTest);
   chrome_feature_list_creator->SetApplicationLocale(actual_locale);
   chrome_feature_list_creator->OverrideCachedUIStrings();
 
@@ -692,12 +698,13 @@
 #endif
 }
 
-bool ChromeMainDelegate::ShouldCreateFeatureList() {
-  // Chrome creates the FeatureList, so content should not.
-  return false;
+bool ChromeMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
+  // In the browser process Chrome creates the FeatureList, so content should
+  // not.
+  return invoked_in == InvokedIn::kChildProcess;
 }
 
-void ChromeMainDelegate::PostFieldTrialInitialization() {
+void ChromeMainDelegate::CommonEarlyInitialization() {
   std::string process_type =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kProcessType);
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h
index f2ddebbc0..ceade561 100644
--- a/chrome/app/chrome_main_delegate.h
+++ b/chrome/app/chrome_main_delegate.h
@@ -63,9 +63,8 @@
   void ZygoteForked() override;
 #endif
   void PreBrowserMain() override;
-  void PostEarlyInitialization(bool is_running_tests) override;
-  bool ShouldCreateFeatureList() override;
-  void PostFieldTrialInitialization() override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
+  bool ShouldCreateFeatureList(InvokedIn invoked_in) override;
 #if BUILDFLAG(IS_WIN)
   bool ShouldHandleConsoleControlEvents() override;
 #endif
@@ -76,6 +75,9 @@
   content::ContentRendererClient* CreateContentRendererClient() override;
   content::ContentUtilityClient* CreateContentUtilityClient() override;
 
+  // Initialization that happens in all process types.
+  void CommonEarlyInitialization();
+
 #if BUILDFLAG(IS_MAC)
   void InitMacCrashReporter(const base::CommandLine& command_line,
                             const std::string& process_type);
diff --git a/chrome/app_shim/app_shim_controller.h b/chrome/app_shim/app_shim_controller.h
index 6a638d1..53f1f42 100644
--- a/chrome/app_shim/app_shim_controller.h
+++ b/chrome/app_shim/app_shim_controller.h
@@ -24,6 +24,10 @@
 class MachBootstrapAcceptorTest;
 }
 
+namespace display {
+class ScopedNativeScreen;
+}
+
 @class AppShimDelegate;
 @class ProfileMenuTarget;
 @class ApplicationDockMenuTarget;
@@ -189,6 +193,9 @@
   base::scoped_nsobject<ApplicationDockMenuTarget>
       application_dock_menu_target_;
 
+  // The screen object used in the app sim.
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
+
   // The items in the profile menu.
   std::vector<chrome::mojom::ProfileMenuItemPtr> profile_menu_items_;
 
diff --git a/chrome/app_shim/app_shim_controller.mm b/chrome/app_shim/app_shim_controller.mm
index 9fb0eab..50b8ab3 100644
--- a/chrome/app_shim/app_shim_controller.mm
+++ b/chrome/app_shim/app_shim_controller.mm
@@ -41,6 +41,7 @@
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/image/image.h"
 
 // The ProfileMenuTarget bridges between Objective C (as the target for the
@@ -128,6 +129,7 @@
       profile_menu_target_([[ProfileMenuTarget alloc] initWithController:this]),
       application_dock_menu_target_(
           [[ApplicationDockMenuTarget alloc] initWithController:this]) {
+  screen_ = std::make_unique<display::ScopedNativeScreen>();
   // Since AppShimController is created before the main message loop starts,
   // NSApp will not be set, so use sharedApplication.
   NSApplication* sharedApplication = [NSApplication sharedApplication];
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index cd79435..c064308 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -5454,6 +5454,7 @@
     deps += [
       ":dlp_policy_event_proto",
       "//chrome/browser/chromeos/extensions/login_screen",
+      "//chrome/browser/chromeos/extensions/vpn_provider",
       "//chrome/common/chromeos/extensions",
       "//chromeos/crosapi/cpp",
       "//chromeos/crosapi/cpp:crosapi_constants",
@@ -5902,6 +5903,8 @@
       "mac/auth_session_request.mm",
       "mac/bluetooth_utility.h",
       "mac/bluetooth_utility.mm",
+      "mac/chrome_browser_main_extra_parts_mac.h",
+      "mac/chrome_browser_main_extra_parts_mac.mm",
       "mac/dock.h",
       "mac/dock.mm",
       "mac/exception_processor.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f7c4434c..4eecf4c0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6658,6 +6658,12 @@
      flag_descriptions::kWebBundlesDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kWebBundles)},
 
+#if !BUILDFLAG(IS_ANDROID)
+    {"hidpi-capture", flag_descriptions::kWebContentsCaptureHiDpiName,
+     flag_descriptions::kWebContentsCaptureHiDpiDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(media::kWebContentsCaptureHiDpi)},
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_ANDROID)
     {"web-otp-backend", flag_descriptions::kWebOtpBackendName,
      flag_descriptions::kWebOtpBackendDescription, kOsAndroid,
diff --git a/chrome/browser/after_startup_task_utils.cc b/chrome/browser/after_startup_task_utils.cc
index 8f927477..5194b88 100644
--- a/chrome/browser/after_startup_task_utils.cc
+++ b/chrome/browser/after_startup_task_utils.cc
@@ -141,6 +141,11 @@
   StartupObserver() = default;
 
   void OnStartupComplete() {
+    if (!performance_manager::PerformanceManagerImpl::IsAvailable()) {
+      // Already shutting down before startup finished. Do not notify.
+      return;
+    }
+
     // This should only be called once.
     if (!startup_complete_) {
       startup_complete_ = true;
diff --git a/chrome/browser/apps/app_service/intent_util.cc b/chrome/browser/apps/app_service/intent_util.cc
index 090e1b7..ce885d2 100644
--- a/chrome/browser/apps/app_service/intent_util.cc
+++ b/chrome/browser/apps/app_service/intent_util.cc
@@ -47,6 +47,7 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/intent_helper/intent_constants.h"
 #include "components/arc/intent_helper/intent_filter.h"
+#include "net/base/filename_util.h"
 #include "storage/browser/file_system/file_system_url.h"
 #endif
 
@@ -936,12 +937,19 @@
   if (app_service_intent->files.has_value() && profile) {
     std::vector<crosapi::mojom::IntentFilePtr> crosapi_files;
     for (const auto& file : app_service_intent->files.value()) {
-      auto file_system_url = apps::GetFileSystemURL(profile, file->url);
-      if (file_system_url.is_valid()) {
+      if (file->url.SchemeIsFile()) {
         auto crosapi_file = crosapi::mojom::IntentFile::New();
-        crosapi_file->file_path = file_system_url.path();
+        net::FileURLToFilePath(file->url, &crosapi_file->file_path);
         crosapi_file->mime_type = file->mime_type;
         crosapi_files.push_back(std::move(crosapi_file));
+      } else if (file->url.SchemeIsFileSystem()) {
+        auto file_system_url = apps::GetFileSystemURL(profile, file->url);
+        if (file_system_url.is_valid()) {
+          auto crosapi_file = crosapi::mojom::IntentFile::New();
+          crosapi_file->file_path = file_system_url.path();
+          crosapi_file->mime_type = file->mime_type;
+          crosapi_files.push_back(std::move(crosapi_file));
+        }
       }
     }
     crosapi_intent->files = std::move(crosapi_files);
diff --git a/chrome/browser/apps/app_service/intent_util_unittest.cc b/chrome/browser/apps/app_service/intent_util_unittest.cc
index 2fd2eef5..9c5f682f 100644
--- a/chrome/browser/apps/app_service/intent_util_unittest.cc
+++ b/chrome/browser/apps/app_service/intent_util_unittest.cc
@@ -41,6 +41,7 @@
 #include "chromeos/crosapi/mojom/app_service_types.mojom.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/extension.h"
+#include "net/base/filename_util.h"
 #include "storage/browser/file_system/external_mount_points.h"
 #include "storage/common/file_system/file_system_mount_option.h"
 #include "storage/common/file_system/file_system_types.h"
@@ -987,13 +988,14 @@
   TestingProfile* profile_;
 };
 
-TEST_F(IntentUtilsFileTest, AppServiceIntentToCrosapi) {
+TEST_F(IntentUtilsFileTest, ConvertFileSystemScheme) {
   auto app_service_intent = apps::mojom::Intent::New();
   app_service_intent->action = "action";
   app_service_intent->mime_type = "*/*";
   const std::string path = "Documents/foo.txt";
   const std::string mime_type = "text/plain";
   auto url = ToGURL(base::FilePath(storage::kTestDir), path);
+  EXPECT_TRUE(url.SchemeIsFileSystem());
   app_service_intent->files = std::vector<apps::mojom::IntentFilePtr>{};
   auto file = apps::mojom::IntentFile::New();
   file->url = url;
@@ -1009,6 +1011,29 @@
   EXPECT_EQ(crosapi_intent->files.value()[0]->mime_type, mime_type);
 }
 
+TEST_F(IntentUtilsFileTest, ConvertFileScheme) {
+  auto app_service_intent = apps::mojom::Intent::New();
+  app_service_intent->action = "action";
+  app_service_intent->mime_type = "*/*";
+  base::FilePath path("/path/to/document.txt");
+  const std::string mime_type = "text/plain";
+  auto url = net::FilePathToFileURL(path);
+  EXPECT_TRUE(url.SchemeIsFile());
+  app_service_intent->files = std::vector<apps::mojom::IntentFilePtr>{};
+  auto file = apps::mojom::IntentFile::New();
+  file->url = url;
+  file->mime_type = mime_type;
+  app_service_intent->files->push_back(std::move(file));
+  auto crosapi_intent = apps_util::ConvertAppServiceToCrosapiIntent(
+      app_service_intent, GetProfile());
+  EXPECT_EQ(app_service_intent->action, crosapi_intent->action);
+  EXPECT_EQ(app_service_intent->mime_type, crosapi_intent->mime_type);
+  ASSERT_TRUE(crosapi_intent->files.has_value());
+  ASSERT_EQ(crosapi_intent->files.value().size(), 1U);
+  EXPECT_EQ(crosapi_intent->files.value()[0]->file_path, path);
+  EXPECT_EQ(crosapi_intent->files.value()[0]->mime_type, mime_type);
+}
+
 TEST_F(IntentUtilsFileTest, CrosapiIntentToAppService) {
   const std::string path = "Documents/foo.txt";
   auto file_path = base::FilePath(fs_root_).Append(path);
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc
index fd6635c..1fa9cb5 100644
--- a/chrome/browser/ash/accessibility/dictation_browsertest.cc
+++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -44,6 +44,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/fake_speech_recognition_manager.h"
+#include "extensions/browser/browsertest_util.h"
 #include "extensions/browser/extension_host_test_helper.h"
 #include "media/mojo/mojom/speech_recognition_service.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -318,7 +319,13 @@
   }
 
   // Routers to SpeechRecognitionTestHelper methods.
-  void WaitForRecognitionStarted() { test_helper_.WaitForRecognitionStarted(); }
+  void WaitForRecognitionStarted() {
+    test_helper_.WaitForRecognitionStarted();
+    // Dictation initializes FocusHandler when speech recognition starts.
+    // Several tests require FocusHandler logic, so wait for it to initialize
+    // before proceeding.
+    WaitForFocusHandler();
+  }
 
   void WaitForRecognitionStopped() { test_helper_.WaitForRecognitionStopped(); }
 
@@ -390,6 +397,29 @@
         .Wait();
   }
 
+  void WaitForFocusHandler() {
+    std::string error_message = "Still waiting for FocusHandler";
+    std::string script = R"(
+      if (accessibilityCommon.dictation_.focusHandler_.isReadyForTesting()) {
+        window.domAutomationController.send("ready");
+      } else {
+        window.domAutomationController.send("not ready");
+      }
+    )";
+    SuccessWaiter(
+        base::BindLambdaForTesting([&]() {
+          std::string result =
+              extensions::browsertest_util::ExecuteScriptInBackgroundPage(
+                  /*context=*/browser()->profile(),
+                  /*extension_id=*/
+                  extension_misc::kAccessibilityCommonExtensionId,
+                  /*script=*/script);
+          return result == "ready";
+        }),
+        error_message)
+        .Wait();
+  }
+
   void ToggleDictationWithKeystroke() {
     ASSERT_NO_FATAL_FAILURE(ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
         nullptr, ui::KeyboardCode::VKEY_D, false, false, false, true)));
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular_unittest.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular_unittest.cc
index 49fcffb..fddcae6 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular_unittest.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular_unittest.cc
@@ -243,6 +243,7 @@
     easy_unlock_service_regular_->Shutdown();
     PowerManagerClient::Shutdown();
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
+    display::Screen::SetScreenInstance(nullptr);
   }
 
   // Most tests will want to pass `should_initialize_all_dependencies` == true,
diff --git a/chrome/browser/ash/login/ui/simple_web_view_dialog.cc b/chrome/browser/ash/login/ui/simple_web_view_dialog.cc
index 4296834c..063d2f05 100644
--- a/chrome/browser/ash/login/ui/simple_web_view_dialog.cc
+++ b/chrome/browser/ash/login/ui/simple_web_view_dialog.cc
@@ -221,12 +221,10 @@
 
   location_bar_->Init();
   UpdateReload(web_view_->web_contents()->IsLoading(), true);
-}
 
-gfx::Size SimpleWebViewDialog::GetMinimumSize() const {
   gfx::Rect screen_bounds = CalculateScreenBounds(gfx::Size());
   screen_bounds.Inset(kExternalMargin);
-  return screen_bounds.size();
+  SetPreferredSize(screen_bounds.size());
 }
 
 content::WebContents* SimpleWebViewDialog::OpenURL(
diff --git a/chrome/browser/ash/login/ui/simple_web_view_dialog.h b/chrome/browser/ash/login/ui/simple_web_view_dialog.h
index 51710d9..00331b0 100644
--- a/chrome/browser/ash/login/ui/simple_web_view_dialog.h
+++ b/chrome/browser/ash/login/ui/simple_web_view_dialog.h
@@ -60,9 +60,6 @@
   // Inits view. Should be attached to a Widget before call.
   void Init();
 
-  // views::View:
-  gfx::Size GetMinimumSize() const override;
-
   // Implements content::PageNavigator:
   content::WebContents* OpenURL(const content::OpenURLParams& params) override;
 
diff --git a/chrome/browser/ash/network_change_manager_client_browsertest.cc b/chrome/browser/ash/network_change_manager_client_browsertest.cc
index d6bd5ab..4f5ceaf 100644
--- a/chrome/browser/ash/network_change_manager_client_browsertest.cc
+++ b/chrome/browser/ash/network_change_manager_client_browsertest.cc
@@ -120,9 +120,8 @@
 
 // Tests that network changes from shill are received by both the
 // NetworkChangeNotifier and NetworkConnectionTracker.
-// Flaky: https://crbug.com/1291300
 IN_PROC_BROWSER_TEST_F(NetworkChangeManagerClientBrowserTest,
-                       DISABLED_ReceiveNotifications) {
+                       ReceiveNotifications) {
   NetObserver net_observer;
   NetworkServiceObserver network_service_observer;
 
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 0cb701b8..341458a 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -56,8 +56,7 @@
                                                      StartupData* startup_data)
     : ChromeBrowserMainPartsPosix(is_integration_test, startup_data) {}
 
-ChromeBrowserMainPartsMac::~ChromeBrowserMainPartsMac() {
-}
+ChromeBrowserMainPartsMac::~ChromeBrowserMainPartsMac() = default;
 
 int ChromeBrowserMainPartsMac::PreEarlyInitialization() {
   if (base::mac::WasLaunchedAsLoginItemRestoreState()) {
@@ -69,7 +68,6 @@
         base::CommandLine::ForCurrentProcess();
     singleton_command_line->AppendSwitch(switches::kNoStartupWindow);
   }
-
   return ChromeBrowserMainPartsPosix::PreEarlyInitialization();
 }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f050626..04d5d56d 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -338,6 +338,7 @@
 #include "chrome/browser/browser_process_platform_part_mac.h"
 #include "chrome/browser/chrome_browser_main_mac.h"
 #include "chrome/browser/mac/auth_session_request.h"
+#include "chrome/browser/mac/chrome_browser_main_extra_parts_mac.h"
 #include "components/soda/constants.h"
 #include "sandbox/mac/seatbelt_exec.h"
 #include "sandbox/policy/mac/params.h"
@@ -1370,7 +1371,8 @@
   registry->RegisterBooleanPref(prefs::kOriginAgentClusterDefaultEnabled, true);
   registry->RegisterIntegerPref(
       prefs::kForceMajorVersionToMinorPositionInUserAgent,
-      embedder_support::ForceMajorVersionToMinorPosition::kDefault);
+      static_cast<int>(
+          embedder_support::ForceMajorVersionToMinorPosition::kDefault));
   registry->RegisterBooleanPref(
       policy::policy_prefs::kIsolatedAppsDeveloperModeAllowed, true);
 }
@@ -1452,6 +1454,10 @@
 #endif
 #endif
 
+#if BUILDFLAG(IS_MAC)
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsMac>());
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // TODO(jamescook): Combine with `ChromeBrowserMainPartsAsh`.
   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsAsh>());
@@ -5447,14 +5453,10 @@
   return network_contexts_parent_directory_;
 }
 
-base::DictionaryValue ChromeContentBrowserClient::GetNetLogConstants() {
-  auto platform_dict = net_log::GetPlatformConstantsForNetLog(
+base::Value::Dict ChromeContentBrowserClient::GetNetLogConstants() {
+  return net_log::GetPlatformConstantsForNetLog(
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
       chrome::GetChannelName(chrome::WithExtendedStable(true)));
-  if (platform_dict)
-    return std::move(*platform_dict);
-  else
-    return base::DictionaryValue();
 }
 
 bool ChromeContentBrowserClient::AllowRenderingMhtmlOverHttp(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 7744e68b..0ca7726 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -573,7 +573,7 @@
       cert_verifier::mojom::CertVerifierCreationParams*
           cert_verifier_creation_params) override;
   std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
-  base::DictionaryValue GetNetLogConstants() override;
+  base::Value::Dict GetNetLogConstants() override;
   bool AllowRenderingMhtmlOverHttp(
       content::NavigationUIData* navigation_ui_data) override;
   bool ShouldForceDownloadResource(const GURL& url,
@@ -890,9 +890,6 @@
   UserAgentReductionEnterprisePolicyState
   GetUserAgentReductionEnterprisePolicyState(content::BrowserContext* context);
 
-  embedder_support::ForceMajorVersionToMinorPosition
-  GetForceMajorVersionToMinorPosition(content::BrowserContext* context);
-
   // Vector of additional ChromeContentBrowserClientParts.
   // Parts are deleted in the reverse order they are added.
   std::vector<ChromeContentBrowserClientParts*> extra_parts_;
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
index 853f633..208a601 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
+#include "chrome/common/extensions/api/vpn_provider.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/pepper_vpn_provider_resource_host_proxy.h"
 #include "content/public/browser/vpn_service_proxy.h"
@@ -16,6 +17,7 @@
 #include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/unloaded_extension_reason.h"
+#include "extensions/common/permissions/permissions_data.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -35,6 +37,16 @@
 
 namespace api_vpn = extensions::api::vpn_provider;
 
+// All events that our EventRouter::Observer should be listening to.
+// api_vpn::OnConfigCreated is intentionally omitted -- it was never
+// implemented.
+const char* const kEventNames[] = {
+    api_vpn::OnUIEvent::kEventName,
+    api_vpn::OnConfigRemoved::kEventName,
+    api_vpn::OnPlatformMessage::kEventName,
+    api_vpn::OnPacketReceived::kEventName,
+};
+
 void RunSuccessCallback(chromeos::VpnService::SuccessCallback success) {
   std::move(success).Run();
 }
@@ -69,6 +81,11 @@
       std::move(success), std::move(failure));
 }
 
+bool IsVpnProvider(const extensions::Extension* extension) {
+  return extension->permissions_data()->HasAPIPermission(
+      extensions::mojom::APIPermissionID::kVpnProvider);
+}
+
 }  // namespace
 
 class VpnService::VpnServiceProxyImpl : public content::VpnServiceProxy {
@@ -199,8 +216,13 @@
 
 VpnService::VpnService(content::BrowserContext* browser_context)
     : browser_context_(browser_context) {
-  extension_registry_observer_.Observe(
-      extensions::ExtensionRegistry::Get(browser_context));
+  auto* registry = extensions::ExtensionRegistry::Get(browser_context);
+  extension_registry_observer_.Observe(registry);
+
+  auto* event_router = extensions::EventRouter::Get(browser_context);
+  for (const char* event_name : kEventNames) {
+    event_router->RegisterObserver(this, event_name);
+  }
 }
 
 VpnService::~VpnService() = default;
@@ -268,9 +290,19 @@
   return std::make_unique<VpnServiceProxyImpl>(weak_factory_.GetWeakPtr());
 }
 
+void VpnService::Shutdown() {
+  extensions::EventRouter::Get(browser_context_)->UnregisterObserver(this);
+}
+
 void VpnService::OnExtensionUninstalled(content::BrowserContext*,
                                         const extensions::Extension* extension,
                                         extensions::UninstallReason) {
+  // Extension should have a vpnProvider permission in order to use the API;
+  // therefore we can safely ignore all other extensions (because otherwise
+  // we'll just make an unnecessary mojo call).
+  if (!IsVpnProvider(extension)) {
+    return;
+  }
   GetVpnService()->MaybeFailActiveConnectionAndDestroyConfigurations(
       extension->id(), /*destroy_configurations=*/true);
   extension_id_to_service_.erase(extension->id());
@@ -280,6 +312,12 @@
     content::BrowserContext*,
     const extensions::Extension* extension,
     extensions::UnloadedExtensionReason reason) {
+  // Extension should have a vpnProvider permission in order to use the API;
+  // therefore we can safely ignore all other extensions (because otherwise
+  // we'll just make an unnecessary mojo call).
+  if (!IsVpnProvider(extension)) {
+    return;
+  }
   bool destroy_configurations =
       reason == extensions::UnloadedExtensionReason::DISABLE ||
       reason == extensions::UnloadedExtensionReason::BLOCKLIST;
@@ -290,10 +328,20 @@
   }
 }
 
+void VpnService::OnListenerAdded(const extensions::EventListenerInfo& details) {
+  // Ensures that the service is created for the extension, so that incoming VPN
+  // events can be dispatched to the extension.
+  GetVpnServiceForExtension(details.extension_id);
+}
+
 // static
 crosapi::mojom::VpnService* VpnService::GetVpnService() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  DCHECK(crosapi::CrosapiManager::IsInitialized());
+  // CrosapiManager may not be initialized.
+  // TODO(crbug.com/1326801): Assert it's only happening in tests.
+  if (!crosapi::CrosapiManager::IsInitialized()) {
+    return nullptr;
+  }
   return crosapi::CrosapiManager::Get()->crosapi_ash()->vpn_service_ash();
 #else
   auto* service = chromeos::LacrosService::Get();
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
index b9658ae..17fd5ce 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
@@ -21,6 +21,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/browser/unloaded_extension_reason.h"
+#include "extensions/common/extension.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
@@ -74,7 +75,8 @@
 
 // The class manages the VPN configurations.
 class VpnService : public extensions::api::VpnServiceInterface,
-                   public extensions::ExtensionRegistryObserver {
+                   public extensions::ExtensionRegistryObserver,
+                   public extensions::EventRouter::Observer {
  public:
   explicit VpnService(content::BrowserContext*);
   ~VpnService() override;
@@ -108,6 +110,7 @@
                                     SuccessCallback,
                                     FailureCallback) override;
   std::unique_ptr<content::VpnServiceProxy> GetVpnServiceProxy() override;
+  void Shutdown() override;
 
   // ExtensionRegistryObserver:
   void OnExtensionUninstalled(content::BrowserContext*,
@@ -117,6 +120,9 @@
                            const extensions::Extension*,
                            extensions::UnloadedExtensionReason) override;
 
+  // EventRouter::Observer:
+  void OnListenerAdded(const extensions::EventListenerInfo&) override;
+
  private:
   class VpnServiceProxyImpl;
   class PepperVpnProxyAdapter;
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.cc b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.cc
index 5149b72..bd6e346 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.cc
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_context.h"
+#include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extensions_browser_client.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -57,7 +58,9 @@
 VpnServiceFactory::VpnServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "VpnService",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(extensions::EventRouterFactory::GetInstance());
+}
 
 VpnServiceFactory::~VpnServiceFactory() = default;
 
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_interface.h b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_interface.h
index c06a8ff..71d68f2 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_interface.h
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service_interface.h
@@ -10,7 +10,6 @@
 
 #include "base/callback_forward.h"
 #include "base/values.h"
-#include "chrome/common/extensions/api/vpn_provider.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 namespace content {
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
index 8ec15ca..44dc19fa 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
@@ -128,14 +128,7 @@
   RunTest(base::StringPrintf(kTest, kAssertions));
 }
 
-#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
-// https://crbug.com/1222670
-#define MAYBE_GetPersistentSecret DISABLED_GetPersistentSecret
-#else
-#define MAYBE_GetPersistentSecret GetPersistentSecret
-#endif
-IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
-                       MAYBE_GetPersistentSecret) {
+IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetPersistentSecret) {
   constexpr char kAssertions[] =
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
       "chrome.test.assertNoLastError();"
@@ -143,11 +136,13 @@
 #else
       "chrome.test.assertLastError('Access to extension API denied.');";
 #endif
+  // Pass `true` as recreate on error to ensure that any keychain ACLs are fixed
+  // by this call instead of failing the test (makes the test more robust).
   constexpr char kTest[] = R"(
       chrome.test.assertEq(
         'function',
         typeof chrome.enterprise.reportingPrivate.getPersistentSecret);
-      chrome.enterprise.reportingPrivate.getPersistentSecret((secret) => {
+      chrome.enterprise.reportingPrivate.getPersistentSecret(true, (secret) => {
         %s
         chrome.test.notifyPass();
       });
diff --git a/chrome/browser/extensions/api/search/search_api_unittest.cc b/chrome/browser/extensions/api/search/search_api_unittest.cc
index baeaee9..3e69925 100644
--- a/chrome/browser/extensions/api/search/search_api_unittest.cc
+++ b/chrome/browser/extensions/api/search/search_api_unittest.cc
@@ -15,8 +15,6 @@
 #include "content/public/test/web_contents_tester.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/common/extension_builder.h"
-#include "ui/display/test/scoped_screen_override.h"
-#include "ui/display/test/test_screen.h"
 
 namespace extensions {
 
@@ -74,8 +72,6 @@
   std::unique_ptr<TestBrowserWindow> browser_window_;
   std::unique_ptr<Browser> browser_;
 
-  display::test::TestScreen test_screen_;
-  std::unique_ptr<display::test::ScopedScreenOverride> scoped_screen_override_;
   scoped_refptr<extensions::SearchQueryFunction> function_;
 };
 
@@ -91,8 +87,6 @@
   params.type = Browser::TYPE_NORMAL;
   params.window = browser_window_.get();
   browser_ = std::unique_ptr<Browser>(Browser::Create(params));
-  scoped_screen_override_ =
-      std::make_unique<display::test::ScopedScreenOverride>(&test_screen_);
 
   // Mock TemplateURLService.
   auto* template_url_service = static_cast<TemplateURLService*>(
diff --git a/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc b/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
index a42a5749..837d0bd 100644
--- a/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
+++ b/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
@@ -15,16 +15,11 @@
 #include "extensions/browser/api/system_display/system_display_api.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/mock_display_info_provider.h"
-#include "extensions/browser/mock_screen.h"
 #include "extensions/common/api/system_display.h"
 #include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/display/test/scoped_screen_override.h"
 
 namespace extensions {
 
-using display::Screen;
-using display::test::ScopedScreenOverride;
 using ContextType = ExtensionBrowserTest::ContextType;
 
 class SystemDisplayExtensionApiTest
@@ -39,27 +34,19 @@
 
   void SetUpOnMainThread() override {
     ExtensionApiTest::SetUpOnMainThread();
-    ANNOTATE_LEAKING_OBJECT_PTR(Screen::GetScreen());
-    scoped_screen_override_ =
-        std::make_unique<ScopedScreenOverride>(screen_.get());
     DisplayInfoProvider::InitializeForTesting(provider_.get());
   }
 
   void TearDownOnMainThread() override {
     ExtensionApiTest::TearDownOnMainThread();
-    scoped_screen_override_.reset();
   }
 
  protected:
   std::unique_ptr<MockDisplayInfoProvider> provider_ =
       std::make_unique<MockDisplayInfoProvider>();
-
- private:
-  std::unique_ptr<Screen> screen_ = std::make_unique<MockScreen>();
-  std::unique_ptr<ScopedScreenOverride> scoped_screen_override_;
 };
 
-// TODO(crbug.com/1231357): MockScreen causes random failures on Windows.
+// TODO(crbug.com/1231357): Revisit this after screen creation refactoring.
 #if !BUILDFLAG(IS_WIN)
 
 INSTANTIATE_TEST_SUITE_P(PersistentBackground,
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 005577b..7154cba7 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -33,8 +33,6 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_builder.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/display/test/scoped_screen_override.h"
-#include "ui/display/test/test_screen.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/test/ash_test_helper.h"
@@ -48,8 +46,6 @@
 
 namespace extensions {
 
-using display::test::ScopedScreenOverride;
-
 namespace {
 
 std::unique_ptr<base::ListValue> RunTabsQueryFunction(
@@ -127,13 +123,15 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   ash::AshTestHelper test_helper_;
-#else
-  display::test::TestScreen test_screen_;
-  std::unique_ptr<ScopedScreenOverride> scoped_screen_override_;
 #endif
 };
 
 void TabsApiUnitTest::SetUp() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  ash::AshTestHelper::InitParams ash_params;
+  ash_params.start_session = true;
+  test_helper_.SetUp(std::move(ash_params));
+#endif
   // Force TabManager/TabLifecycleUnitSource creation.
   g_browser_process->GetTabManager();
 
@@ -145,14 +143,6 @@
   params.type = Browser::TYPE_NORMAL;
   params.window = browser_window_.get();
   browser_.reset(Browser::Create(params));
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  ash::AshTestHelper::InitParams ash_params;
-  ash_params.start_session = true;
-  test_helper_.SetUp(std::move(ash_params));
-#else
-  scoped_screen_override_ =
-      std::make_unique<ScopedScreenOverride>(&test_screen_);
-#endif
 }
 
 void TabsApiUnitTest::TearDown() {
diff --git a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
index d8b5f53..1c2051a 100644
--- a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
+++ b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
@@ -14,6 +14,8 @@
 #include "chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/extensions/api/vpn_provider.h"
+#include "chromeos/crosapi/mojom/vpn_service.mojom-test-utils.h"
 #include "chromeos/network/shill_property_handler.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/pepper_vpn_provider_resource_host_proxy.h"
@@ -154,6 +156,8 @@
     return chromeos::VpnServiceFactory::GetForBrowserContext(profile());
   }
 
+  virtual crosapi::mojom::VpnService* service_remote() const = 0;
+
   virtual void OnPlatformMessage(const std::string& configuration_name,
                                  api_vpn::PlatformMessage) = 0;
   virtual void OnPacketReceived(const std::string& configuration_name,
@@ -178,6 +182,11 @@
     UnloadExtension(extension_id());
     VpnProviderApiTestBase::TearDownOnMainThread();
   }
+  crosapi::mojom::VpnService* service_remote() const override {
+    return chromeos::LacrosService::Get()
+        ->GetRemote<crosapi::mojom::VpnService>()
+        .get();
+  }
   void OnPlatformMessage(const std::string& configuration_name,
                          api_vpn::PlatformMessage message) override {
     controller_->OnPlatformMessage(extension_id(), configuration_name, message);
@@ -221,6 +230,9 @@
     VpnProviderApiTestBase::SetUpOnMainThread();
     AddNetworkProfileForUser();
   }
+  crosapi::mojom::VpnService* service_remote() const override {
+    return GetVpnServiceAsh();
+  }
   void OnPlatformMessage(const std::string& configuration_name,
                          api_vpn::PlatformMessage message) override {
     test_client_->OnPlatformMessage(
@@ -604,4 +616,51 @@
   ASSERT_TRUE(unbind.Wait());
 }
 
+class TestEventObserverForExtension
+    : public crosapi::mojom::EventObserverForExtension {
+ public:
+  // crosapi::mojom::EventObserverForExtension:
+  void OnAddDialog() override {}
+  void OnConfigureDialog(const std::string& configuration_name) override {}
+  void OnConfigRemoved(const std::string& configuration_name) override {}
+  void OnPlatformMessage(const std::string& configuration_name,
+                         int32_t platform_message,
+                         const absl::optional<std::string>& error) override {}
+  void OnPacketReceived(const std::vector<uint8_t>& data) override {}
+};
+
+// Tests that the per-extension crosapi connection between ash and browser
+// is initialized by the moment ash decides to send a platform message to the
+// browser.
+IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, PlatformMessage) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  if (!InitTestShillController()) {
+    GTEST_SKIP() << "Unsupported ash version.";
+  }
+#endif
+
+  auto test_observer = std::make_unique<TestEventObserverForExtension>();
+  mojo::Remote<crosapi::mojom::VpnServiceForExtension> remote;
+  mojo::Receiver<crosapi::mojom::EventObserverForExtension> receiver{
+      test_observer.get()};
+  service_remote()->RegisterVpnServiceForExtension(
+      extension_id(), remote.BindNewPipeAndPassReceiver(),
+      receiver.BindNewPipeAndPassRemote());
+
+  crosapi::mojom::VpnServiceForExtensionAsyncWaiter waiter{remote.get()};
+  crosapi::mojom::VpnErrorResponsePtr error;
+  waiter.CreateConfiguration(kTestConfig, &error);
+  ASSERT_FALSE(error) << "CreateConfiguration failed with |message| = "
+                      << error->message.value_or(std::string{});
+
+  extensions::ResultCatcher catcher;
+  EXPECT_TRUE(RunTest("platformMessage"));
+  ASSERT_TRUE(catcher.GetNextResult());
+
+  OnPlatformMessage(kTestConfig, api_vpn::PLATFORM_MESSAGE_CONNECTED);
+  ASSERT_TRUE(catcher.GetNextResult());
+  OnPlatformMessage(kTestConfig, api_vpn::PLATFORM_MESSAGE_DISCONNECTED);
+  ASSERT_TRUE(catcher.GetNextResult());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index a36372cf..f4880724 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/chromeos/extensions/vpn_provider/vpn_service_factory.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
 #include "chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h"
@@ -144,6 +145,9 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   extensions::VerifyTrustAPI::GetFactoryInstance();
 #endif
+#if BUILDFLAG(IS_CHROMEOS)
+  chromeos::VpnServiceFactory::GetInstance();
+#endif
   extensions::WarningBadgeServiceFactory::GetInstance();
   extensions::WebAuthenticationProxyAPI::GetFactoryInstance();
   extensions::WebNavigationAPI::GetFactoryInstance();
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index adb8ae61..a252b15 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3552,6 +3552,11 @@
     "expiry_milestone": 94
   },
   {
+    "name": "hidpi-capture",
+    "owners": [ "//content/browser/media/capture/OWNERS" ],
+    "expiry_milestone": 112
+  },
+  {
     "name": "history-journeys",
     "owners": [ "tommycli", "chrome-journeys@google.com" ],
     "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 7c72b3a..2f78937a 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2821,6 +2821,12 @@
     "Enables experimental supports for Web Bundles (Bundled HTTP Exchanges) "
     "navigation.";
 
+const char kWebContentsCaptureHiDpiName[] = "HiDPI Tab Capture";
+const char kWebContentsCaptureHiDpiDescription[] =
+    "Enables HiDPI rendering for tab capture if the displayed content's "
+    "resolution is low compared to the capture size. This improves "
+    "legibility for viewers with higher-resolution screens.";
+
 const char kWebMidiName[] = "Web MIDI";
 const char kWebMidiDescription[] =
     "Enables the implementation of the Web MIDI API. When disabled the "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f668bee..5b78268 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1581,6 +1581,9 @@
 extern const char kWebBundlesName[];
 extern const char kWebBundlesDescription[];
 
+extern const char kWebContentsCaptureHiDpiName[];
+extern const char kWebContentsCaptureHiDpiDescription[];
+
 extern const char kWebMidiName[];
 extern const char kWebMidiDescription[];
 
diff --git a/chrome/browser/mac/chrome_browser_main_extra_parts_mac.h b/chrome/browser/mac/chrome_browser_main_extra_parts_mac.h
new file mode 100644
index 0000000..6f2faad
--- /dev/null
+++ b/chrome/browser/mac/chrome_browser_main_extra_parts_mac.h
@@ -0,0 +1,32 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MAC_CHROME_BROWSER_MAIN_EXTRA_PARTS_MAC_H_
+#define CHROME_BROWSER_MAC_CHROME_BROWSER_MAIN_EXTRA_PARTS_MAC_H_
+
+#include <memory>
+
+#include "chrome/browser/chrome_browser_main_extra_parts.h"
+
+namespace display {
+class ScopedNativeScreen;
+}
+
+class ChromeBrowserMainExtraPartsMac : public ChromeBrowserMainExtraParts {
+ public:
+  ChromeBrowserMainExtraPartsMac();
+  ChromeBrowserMainExtraPartsMac(const ChromeBrowserMainExtraPartsMac&) =
+      delete;
+  ChromeBrowserMainExtraPartsMac& operator=(
+      const ChromeBrowserMainExtraPartsMac&) = delete;
+  ~ChromeBrowserMainExtraPartsMac() override;
+
+  // ChromeBrowserMainExtraParts:
+  void PreEarlyInitialization() override;
+
+ private:
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
+};
+
+#endif  // CHROME_BROWSER_MAC_CHROME_BROWSER_MAIN_EXTRA_PARTS_MAC_H_
diff --git a/chrome/browser/mac/chrome_browser_main_extra_parts_mac.mm b/chrome/browser/mac/chrome_browser_main_extra_parts_mac.mm
new file mode 100644
index 0000000..3094e1f
--- /dev/null
+++ b/chrome/browser/mac/chrome_browser_main_extra_parts_mac.mm
@@ -0,0 +1,14 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/mac/chrome_browser_main_extra_parts_mac.h"
+
+#include "ui/display/screen.h"
+
+ChromeBrowserMainExtraPartsMac::ChromeBrowserMainExtraPartsMac() = default;
+ChromeBrowserMainExtraPartsMac::~ChromeBrowserMainExtraPartsMac() = default;
+
+void ChromeBrowserMainExtraPartsMac::PreEarlyInitialization() {
+  screen_ = std::make_unique<display::ScopedNativeScreen>();
+}
diff --git a/chrome/browser/media/history/media_history_browsertest.cc b/chrome/browser/media/history/media_history_browsertest.cc
index 7102302..8b65b71 100644
--- a/chrome/browser/media/history/media_history_browsertest.cc
+++ b/chrome/browser/media/history/media_history_browsertest.cc
@@ -733,16 +733,8 @@
               GetPlaybackSessionsSync(GetOTRMediaHistoryService(browser), 2));
   }
 }
-
-// TODO(crbug.com/1176025): Flaking on Linux.
-#if BUILDFLAG(IS_LINUX)
-#define MAYBE_SaveImagesWithDifferentSessions \
-  DISABLED_SaveImagesWithDifferentSessions
-#else
-#define MAYBE_SaveImagesWithDifferentSessions SaveImagesWithDifferentSessions
-#endif
 IN_PROC_BROWSER_TEST_P(MediaHistoryBrowserTest,
-                       MAYBE_SaveImagesWithDifferentSessions) {
+                       DISABLED_SaveImagesWithDifferentSessions) {
   auto* browser = CreateBrowserFromParam();
   auto expected_metadata = GetExpectedMetadata();
   auto expected_artwork = GetExpectedArtwork();
diff --git a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_unittest.cc b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_unittest.cc
index 310c743..dcb59b0 100644
--- a/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_unittest.cc
+++ b/chrome/browser/metrics/usage_scenario/tab_usage_scenario_tracker_unittest.cc
@@ -40,17 +40,16 @@
       delete;
 
   void SetUp() override {
+    display::Screen::SetScreenInstance(&screen_);
     ChromeRenderViewHostTestHarness::SetUp();
-    previous_screen_ = display::Screen::SetScreenInstance(&screen_);
     tab_usage_scenario_tracker_ =
         std::make_unique<TabUsageScenarioTracker>(&usage_scenario_data_store_);
   }
 
   void TearDown() override {
     tab_usage_scenario_tracker_.reset();
-    display::Screen::SetScreenInstance(previous_screen_);
-    previous_screen_ = nullptr;
     ChromeRenderViewHostTestHarness::TearDown();
+    display::Screen::SetScreenInstance(nullptr);
   }
 
   std::unique_ptr<content::WebContents> CreateWebContents() {
@@ -83,7 +82,6 @@
 
  protected:
   display::test::TestScreen screen_;
-  raw_ptr<display::Screen> previous_screen_;
   UsageScenarioDataStoreImpl usage_scenario_data_store_;
   std::unique_ptr<TabUsageScenarioTracker> tab_usage_scenario_tracker_;
   ukm::TestAutoSetUkmRecorder ukm_recorder_;
diff --git a/chrome/browser/page_load_metrics/integration_tests/first_input_delay_browsertest.cc b/chrome/browser/page_load_metrics/integration_tests/first_input_delay_browsertest.cc
index d46b97f..ec1710f 100644
--- a/chrome/browser/page_load_metrics/integration_tests/first_input_delay_browsertest.cc
+++ b/chrome/browser/page_load_metrics/integration_tests/first_input_delay_browsertest.cc
@@ -6,6 +6,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/page_load_metrics/integration_tests/metric_integration_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/hit_test_region_observer.h"
@@ -14,6 +15,10 @@
 using ukm::builders::PageLoad;
 
 IN_PROC_BROWSER_TEST_F(MetricIntegrationTest, FirstInputDelay) {
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents());
+  waiter->AddPageExpectation(page_load_metrics::PageLoadMetricsTestWaiter::
+                                 TimingField::kFirstInputDelay);
   LoadHTML(R"HTML(
     <p>Sample website</p>
     <script>
@@ -53,6 +58,8 @@
   double expected_fid = EvalJs(web_contents(), "runtest()").ExtractDouble();
   EXPECT_GT(expected_fid, 0.0);
 
+  waiter->Wait();
+
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
 
   // Check UKM. We compare the webexposed value to the UKM value. The webexposed
diff --git a/chrome/browser/page_load_metrics/integration_tests/first_scroll_delay_browsertest.cc b/chrome/browser/page_load_metrics/integration_tests/first_scroll_delay_browsertest.cc
index dc5eb14..c7ce649 100644
--- a/chrome/browser/page_load_metrics/integration_tests/first_scroll_delay_browsertest.cc
+++ b/chrome/browser/page_load_metrics/integration_tests/first_scroll_delay_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/hit_test_region_observer.h"
@@ -14,6 +15,10 @@
 using ukm::builders::PageLoad;
 
 IN_PROC_BROWSER_TEST_F(MetricIntegrationTest, FirstScrollDelay) {
+  auto waiter = std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
+      web_contents());
+  waiter->AddPageExpectation(page_load_metrics::PageLoadMetricsTestWaiter::
+                                 TimingField::kFirstScrollDelay);
   LoadHTML(R"HTML(
     <div id="content">
       <p>This is some text</p>
@@ -53,6 +58,8 @@
   frame_observer.WaitForScrollOffset(
       gfx::PointF(0, scroll_distance * device_scale_factor));
 
+  waiter->Wait();
+
   // Navigate away.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
 
diff --git a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
index 2776cb11..827cb57c 100644
--- a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
+++ b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
@@ -86,7 +86,8 @@
 constexpr char kMachineName[] = "foo";
 constexpr char kClientID[] = "fake_client_id";
 constexpr char kDMToken[] = "fake_dm_token";
-const char kInvalidDMToken[] = "invalid_dm_token";
+constexpr char kInvalidDMToken[] = "invalid_dm_token";
+constexpr char kDeletionDMToken[] = "deletion_dm_token";
 constexpr char kEnrollmentResultMetrics[] =
     "Enterprise.MachineLevelUserCloudPolicyEnrollment.Result";
 const char kUnenrollmentSuccessMetrics[] =
@@ -226,9 +227,18 @@
 
   void OnCoreDisconnecting(CloudPolicyCore* core) override {
     // This is called when policy fetching fails and is used in
-    // ChromeBrowserCloudManagementController to unenroll the browser. The
-    // status must be DM_STATUS_SERVICE_DEVICE_NOT_FOUND for this to happen.
-    EXPECT_EQ(core->client()->status(), DM_STATUS_SERVICE_DEVICE_NOT_FOUND);
+    // ChromeBrowserCloudManagementController to unenroll the browser.
+#if BUILDFLAG(IS_CHROMEOS)
+    // The status must be `DM_STATUS_SERVICE_DEVICE_NOT_FOUND` since DMToken
+    // deletion is not supported in ChromeOS.
+    EXPECT_EQ(DM_STATUS_SERVICE_DEVICE_NOT_FOUND, core->client()->status());
+#else   // BUILDFLAG(IS_CHROMEOS)
+    // The status must be either `DM_STATUS_SERVICE_DEVICE_NOT_FOUND` or
+    // `DM_STATUS_SERVICE_DEVICE_NEEDS_RESET` for this to happen.
+    EXPECT_THAT((std::array{DM_STATUS_SERVICE_DEVICE_NOT_FOUND,
+                            DM_STATUS_SERVICE_DEVICE_NEEDS_RESET}),
+                testing::Contains(core->client()->status()));
+#endif  // BUILDFLAG(IS_CHROMEOS)
     std::move(quit_closure_).Run();
   }
 
@@ -695,6 +705,11 @@
   void SetUpTestServer() {
     test_server_ = std::make_unique<EmbeddedPolicyTestServer>();
     UpdatePolicyStorage(test_server_->policy_storage());
+    // Configure the policy server to signal that DMToken deletion has been
+    // requested via the DMServer response.
+    if (dm_token() == kDeletionDMToken)
+      test_server_->policy_storage()->set_error_detail(
+          em::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN);
     test_server_->client_storage()->RegisterClient(CreateTestClientInfo());
   }
 
@@ -735,7 +750,7 @@
     // unenrollment.
     std::unique_ptr<PolicyFetchCoreObserver> core_observer;
     std::unique_ptr<PolicyFetchStoreObserver> store_observer;
-    if (dm_token() == kInvalidDMToken) {
+    if (dm_token() == kInvalidDMToken || dm_token() == kDeletionDMToken) {
       if (storage_enabled()) {
         // |run_loop|'s QuitClosure will be called after the core is
         // disconnected following unenrollment.
@@ -760,14 +775,33 @@
       manager->IsInitializationComplete(PolicyDomain::POLICY_DOMAIN_CHROME));
 
   const PolicyMap& policy_map = manager->store()->policy_map();
-  if (dm_token() != kInvalidDMToken) {
+  DMToken token = retrieve_dm_token();
+
+  if (dm_token() == kInvalidDMToken) {
+    EXPECT_EQ(0u, policy_map.size());
+    // The token in storage should be invalid.
+    EXPECT_TRUE(token.is_invalid());
+    histogram_tester_.ExpectUniqueSample(kUnenrollmentSuccessMetrics,
+                                         storage_enabled(), 1);
+  } else if (dm_token() == kDeletionDMToken) {
+    EXPECT_EQ(0u, policy_map.size());
+#if BUILDFLAG(IS_CHROMEOS)
+    // The token in storage should be invalid since DMToken deletion is not
+    // supported in ChromeOS.
+    EXPECT_TRUE(token.is_invalid());
+#else   // BUILDFLAG(IS_CHROMEOS)
+    // The token in storage should be empty.
+    EXPECT_TRUE(token.is_empty());
+#endif  // BUILDFLAG(IS_CHROMEOS)
+    histogram_tester_.ExpectUniqueSample(kUnenrollmentSuccessMetrics,
+                                         storage_enabled(), 1);
+  } else {
     EXPECT_EQ(1u, policy_map.size());
     EXPECT_EQ(base::Value(true),
               *(policy_map.Get(key::kSavingBrowserHistoryDisabled)
                     ->value(base::Value::Type::BOOLEAN)));
 
     // The token in storage should be valid.
-    DMToken token = retrieve_dm_token();
     EXPECT_TRUE(token.is_valid());
 
     // The test server will register with kFakeDeviceToken if
@@ -778,15 +812,6 @@
       EXPECT_EQ(token.value(), kDMToken);
 
     histogram_tester_.ExpectTotalCount(kUnenrollmentSuccessMetrics, 0);
-  } else {
-    EXPECT_EQ(0u, policy_map.size());
-
-    // The token in storage should be invalid.
-    DMToken token = retrieve_dm_token();
-    EXPECT_TRUE(token.is_invalid());
-
-    histogram_tester_.ExpectUniqueSample(kUnenrollmentSuccessMetrics,
-                                         storage_enabled(), 1);
   }
 }
 
@@ -798,11 +823,13 @@
 //  get an error. There should be no more cloud policy applied.
 //  3) Start Chrome without DM token. Chrome will register itself and fetch
 //  policy after it.
-INSTANTIATE_TEST_SUITE_P(
-    MachineLevelUserCloudPolicyPolicyFetchTest,
-    MachineLevelUserCloudPolicyPolicyFetchTest,
-    ::testing::Combine(::testing::Values(kDMToken, kInvalidDMToken, ""),
-                       ::testing::Bool()));
+INSTANTIATE_TEST_SUITE_P(MachineLevelUserCloudPolicyPolicyFetchTest,
+                         MachineLevelUserCloudPolicyPolicyFetchTest,
+                         ::testing::Combine(::testing::Values(kDMToken,
+                                                              kInvalidDMToken,
+                                                              kDeletionDMToken,
+                                                              ""),
+                                            ::testing::Bool()));
 
 #if !BUILDFLAG(IS_ANDROID)
 class MachineLevelUserCloudPolicyRobotAuthTest : public PlatformBrowserTest {
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index b0f08f2..ad149502 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -292,7 +292,7 @@
 
   base::WeakPtr<PdfConverterImpl> weak_this = weak_ptr_factory_.GetWeakPtr();
   data.callback().Run(data.page_number(), scale_factor, std::move(metafile));
-  // WARNING: the callback might have deleted |this|!
+  // WARNING: the callback might have deleted `this`!
   if (!weak_this)
     return;
   get_page_callbacks_.pop();
@@ -312,7 +312,7 @@
   if (!start_callback_.is_null()) {
     std::move(start_callback_).Run(/*page_count=*/0);
     if (!weak_this)
-      return;  // Protect against the |start_callback_| deleting |this|.
+      return;  // Protect against the `start_callback_` deleting `this`.
   }
 
   while (!get_page_callbacks_.empty()) {
diff --git a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
index 898d495..395b491 100644
--- a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
@@ -59,7 +59,7 @@
   std::move(quit_closure).Run();
 }
 
-// |page_number| is 0-based. Returned result has 1-based page number.
+// `page_number` is 0-based. Returned result has 1-based page number.
 std::string GetFileNameForPageNumber(const std::string& name, int page_number) {
   std::string ret = name;
   ret += std::to_string(page_number + 1);
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index e9c7565..69579f4 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -319,7 +319,7 @@
       preview_dialog_ = preview_dialog;
 
       if (wait_for_loaded_) {
-        // Instantiate |queue| to listen for messages in |preview_dialog_|.
+        // Instantiate `queue_` to listen for messages in `preview_dialog_`.
         queue_.emplace(preview_dialog_);
         content::ExecuteScriptAsync(
             preview_dialog_.get(),
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index c51adeb..c8bb972 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -67,7 +67,7 @@
   // post-constructor initialization must be done with Initialize().
   // If PrintJob is created on Chrome OS, call SetSource() to set which
   // component initiated this print job.
-  // |print_job_manager| must outlive this object.
+  // `print_job_manager` must outlive this object.
   explicit PrintJob(PrintJobManager* print_job_manager);
 
   PrintJob(const PrintJob&) = delete;
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index d656cca..44cc090 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -228,7 +228,7 @@
     WebContents* initiator) {
   DCHECK(initiator);
 
-  // Get the print preview dialog for |initiator|.
+  // Get the print preview dialog for `initiator`.
   WebContents* preview_dialog = GetPrintPreviewForContents(initiator);
   if (!preview_dialog)
     return CreatePrintPreviewDialog(initiator);
@@ -240,13 +240,13 @@
 
 WebContents* PrintPreviewDialogController::GetPrintPreviewForContents(
     WebContents* contents) const {
-  // |preview_dialog_map_| is keyed by the preview dialog, so if
-  // base::Contains() succeeds, then |contents| is the preview dialog.
+  // `preview_dialog_map_` is keyed by the preview dialog, so if
+  // base::Contains() succeeds, then `contents` is the preview dialog.
   if (base::Contains(preview_dialog_map_, contents))
     return contents;
 
   for (const auto& it : preview_dialog_map_) {
-    // If |contents| is an initiator.
+    // If `contents` is an initiator.
     if (contents == it.second) {
       // Return the associated preview dialog.
       return it.first;
@@ -297,7 +297,7 @@
   content::RenderProcessHost* rph = web_contents->GetMainFrame()->GetProcess();
 
   // Store contents in a vector and deal with them after iterating through
-  // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|.
+  // `preview_dialog_map_` because RemoveFoo() can change `preview_dialog_map_`.
   std::vector<WebContents*> closed_initiators;
   std::vector<WebContents*> closed_preview_dialogs;
   for (auto& it : preview_dialog_map_) {
@@ -371,7 +371,7 @@
     const content::LoadCommittedDetails& details) {
   ui::PageTransition type = details.entry->GetTransitionType();
 
-  // New |preview_dialog| is created. Don't update/erase map entry.
+  // New `preview_dialog` is created. Don't update/erase map entry.
   if (details.previous_main_frame_url.is_empty() && details.entry &&
       IsPrintPreviewURL(details.entry->GetURL()) &&
       ui::PageTransitionCoreTypeIs(type, ui::PAGE_TRANSITION_AUTO_TOPLEVEL) &&
diff --git a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
index c96d4a8..c264aab 100644
--- a/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller_unittest.cc
@@ -124,7 +124,7 @@
       PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(dialog_controller);
 
-  // Create preview dialog for |web_contents_1|
+  // Create preview dialog for `web_contents_1`
   PrintViewManager::FromWebContents(web_contents_1)
       ->PrintPreviewNow(web_contents_1->GetMainFrame(), false);
   WebContents* preview_dialog_1 =
@@ -133,7 +133,7 @@
   EXPECT_NE(web_contents_1, preview_dialog_1);
   EXPECT_EQ(2, tab_strip_model->count());
 
-  // Create preview dialog for |web_contents_2|
+  // Create preview dialog for `web_contents_2`
   PrintViewManager::FromWebContents(web_contents_2)
       ->PrintPreviewNow(web_contents_2->GetMainFrame(), false);
   WebContents* preview_dialog_2 =
@@ -156,12 +156,12 @@
   EXPECT_EQ(-1, preview_dialog_1_index);
   EXPECT_EQ(-1, preview_dialog_2_index);
 
-  // Since |preview_dialog_2_index| was the most recently created dialog, its
+  // Since `preview_dialog_2_index` was the most recently created dialog, its
   // initiator should have focus.
   EXPECT_EQ(tab_2_index, tab_strip_model->active_index());
 
-  // When we get the preview dialog for |web_contents_1|,
-  // |preview_dialog_1| is activated and focused.
+  // When we get the preview dialog for `web_contents_1`,
+  // `preview_dialog_1` is activated and focused.
   dialog_controller->GetOrCreatePreviewDialog(web_contents_1);
   EXPECT_EQ(tab_1_index, tab_strip_model->active_index());
 }
@@ -254,7 +254,7 @@
   EXPECT_EQ(tiger_barb, web_contents->GetLastCommittedURL());
 
   // Print preview now should return true as the navigation should have closed
-  // |tiger_preview_dialog| and the previous dialog should have closed.
+  // `tiger_preview_dialog` and the previous dialog should have closed.
   EXPECT_TRUE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false));
   WebContents* tiger_barb_preview_dialog =
       dialog_controller->GetOrCreatePreviewDialog(web_contents);
@@ -268,7 +268,7 @@
   content::WebContentsDestroyedWatcher tiger_barb_destroyed(
       tiger_barb_preview_dialog);
 
-  // Now this returns false as |tiger_barb_preview_dialog| is open.
+  // Now this returns false as `tiger_barb_preview_dialog` is open.
   EXPECT_FALSE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false));
 
   // Navigate with back button or ALT+LEFT ARROW to a similar page.
@@ -367,7 +367,7 @@
   ASSERT_TRUE(tab_strip_model);
   EXPECT_EQ(0, tab_strip_model->count());
 
-  // Create a new tab with contents |web_contents_1|
+  // Create a new tab with contents `web_contents_1`
   chrome::NewTab(browser());
   WebContents* web_contents_1 = tab_strip_model->GetActiveWebContents();
   ASSERT_TRUE(web_contents_1);
@@ -376,7 +376,7 @@
       PrintPreviewDialogController::GetInstance();
   ASSERT_TRUE(dialog_controller);
 
-  // Create preview dialog for |web_contents_1|. Should not create a new tab.
+  // Create preview dialog for `web_contents_1`. Should not create a new tab.
   PrintViewManager::FromWebContents(web_contents_1)
       ->PrintPreviewNow(web_contents_1->GetMainFrame(), false);
   WebContents* preview_dialog_1 =
@@ -384,13 +384,13 @@
   EXPECT_NE(web_contents_1, preview_dialog_1);
   EXPECT_EQ(1, tab_strip_model->count());
 
-  // Create a new tab with contents |web_contents_2|
+  // Create a new tab with contents `web_contents_2`
   chrome::NewTab(browser());
   WebContents* web_contents_2 = tab_strip_model->GetActiveWebContents();
   ASSERT_TRUE(web_contents_2);
   EXPECT_EQ(2, tab_strip_model->count());
 
-  // Create preview dialog for |web_contents_2|
+  // Create preview dialog for `web_contents_2`
   PrintViewManager::FromWebContents(web_contents_2)
       ->PrintPreviewNow(web_contents_2->GetMainFrame(), false);
   WebContents* preview_dialog_2 =
@@ -402,12 +402,12 @@
   // dialogs are constrained in their respective initiators.
   EXPECT_EQ(2, tab_strip_model->count());
 
-  // Close |web_contents_1|'s tab
+  // Close `web_contents_1`'s tab
   int tab_1_index = tab_strip_model->GetIndexOfWebContents(web_contents_1);
   tab_strip_model->CloseWebContentsAt(tab_1_index, 0);
   EXPECT_EQ(1, tab_strip_model->count());
 
-  // Simulate a crash of the render process host for |web_contents_2|. Print
+  // Simulate a crash of the render process host for `web_contents_2`. Print
   // preview controller should exit cleanly and not crash.
   content::MockRenderProcessHost* rph =
       static_cast<content::MockRenderProcessHost*>(
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index e74a2d0..88a2f2b 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -879,7 +879,7 @@
   // pages in an hurry if a print_job_ is still pending. No need to wait for it
   // to actually spool the pages, only to have the renderer generate them. Run
   // a message loop until we get our signal that the print job is satisfied.
-  // |quit_inner_loop_| will be called as soon as
+  // `quit_inner_loop_` will be called as soon as
   // print_job_->document()->IsComplete() is true in DidPrintDocument(). The
   // check is done in ShouldQuitFromInnerMessageLoop().
   // BLOCKS until all the pages are received. (Need to enable recursive task)
@@ -910,7 +910,7 @@
   DCHECK(!quit_inner_loop_);
   DCHECK(query);
 
-  // Disconnect the current |print_job_|.
+  // Disconnect the current `print_job_`.
   auto weak_this = weak_ptr_factory_.GetWeakPtr();
   DisconnectFromCurrentPrintJob();
   if (!weak_this)
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc
index 97a786c..f4e6d3be 100644
--- a/chrome/browser/printing/printer_query.cc
+++ b/chrome/browser/printing/printer_query.cc
@@ -83,7 +83,7 @@
     absl::optional<bool> maybe_is_modifiable,
     std::unique_ptr<PrintSettings> new_settings,
     mojom::ResultCode result) {
-  // |this| is owned by |callback|, so |base::Unretained()| is safe.
+  // `this` is owned by `callback`, so `base::Unretained()` is safe.
   content::GetIOThreadTaskRunner({})->PostTask(
       FROM_HERE,
       base::BindOnce(&PrinterQuery::GetSettingsDone, base::Unretained(this),
@@ -161,7 +161,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   StartWorker();
-  // |this| is owned by |callback|, so |base::Unretained()| is safe.
+  // `this` is owned by `callback`, so `base::Unretained()` is safe.
   worker_->PostTask(
       FROM_HERE,
       base::BindOnce(&PrintJobWorker::SetSettings,
@@ -178,7 +178,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   StartWorker();
-  // |this| is owned by |callback|, so |base::Unretained()| is safe.
+  // `this` is owned by `callback`, so `base::Unretained()` is safe.
   worker_->PostTask(
       FROM_HERE,
       base::BindOnce(&PrintJobWorker::SetSettingsFromPOD,
diff --git a/chrome/browser/printing/pwg_raster_converter.cc b/chrome/browser/printing/pwg_raster_converter.cc
index 5df786d..adc149f 100644
--- a/chrome/browser/printing/pwg_raster_converter.cc
+++ b/chrome/browser/printing/pwg_raster_converter.cc
@@ -96,7 +96,7 @@
     return;
   }
 
-  // TODO(thestig): Write |data| into shared memory in the first place, to avoid
+  // TODO(thestig): Write `data` into shared memory in the first place, to avoid
   // this memcpy().
   memcpy(memory.mapping.memory(), data->front(), data->size());
   pdf_to_pwg_raster_converter_remote_->Convert(
@@ -209,11 +209,11 @@
   if (duplex_item.LoadFrom(ticket))
     duplex_value = duplex_item.value();
 
-  // This assumes |ticket| contains a color ticket item. In case it does not, or
-  // the color is invalid, |color_value| will default to AUTO_COLOR, which works
+  // This assumes `ticket` contains a color ticket item. In case it does not, or
+  // the color is invalid, `color_value` will default to AUTO_COLOR, which works
   // just fine. With AUTO_COLOR, it may be possible to better determine the
-  // value for |use_color| based on |printer_capabilities|, rather than just
-  // defaulting to the safe value of true. Parsing |printer_capabilities|
+  // value for `use_color` based on `printer_capabilities`, rather than just
+  // defaulting to the safe value of true. Parsing `printer_capabilities`
   // requires work, which this method is avoiding on purpose.
   cloud_devices::printer::Color color_value;
   cloud_devices::printer::ColorTicketItem color_item;
@@ -235,12 +235,12 @@
 
     default:
       NOTREACHED();
-      use_color = true;  // Still need to initialize |color| or MSVC will warn.
+      use_color = true;  // Still need to initialize `color` or MSVC will warn.
       break;
   }
 
   cloud_devices::printer::PwgRasterConfigCapability raster_capability;
-  // If the raster capability fails to load, |raster_capability| will contain
+  // If the raster capability fails to load, `raster_capability` will contain
   // the default value.
   raster_capability.LoadFrom(printer_capabilities);
   cloud_devices::printer::DocumentSheetBack document_sheet_back =
@@ -276,7 +276,7 @@
   result.rotate_all_pages = raster_capability.value().rotate_all_pages;
   result.reverse_page_order = raster_capability.value().reverse_order_streaming;
 
-  // No need to check for SRGB_8 support in |types|. CDD spec says:
+  // No need to check for SRGB_8 support in `types`. CDD spec says:
   // "any printer that doesn't support SGRAY_8 must be able to perform
   // conversion from RGB to grayscale... "
   const auto& types = raster_capability.value().document_types_supported;
diff --git a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
index 1e822ab..de6bac6 100644
--- a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
+++ b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
@@ -4,6 +4,7 @@
 
 module.exports = {
   'rules' : {
+    'arrow-spacing' : ['error'],
     'brace-style' : ['error', '1tbs'],
     'curly' : ['error', 'multi-line', 'consistent'],
     'eqeqeq' : ['error', 'always', {'null' : 'ignore'}],
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
index 1b2f0c5..439f9d35 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
@@ -42,6 +42,7 @@
     "dictation/earcons/audio_end.wav",
     "dictation/earcons/audio_initiate.wav",
     "dictation/earcons/null_selection.wav",
+    "dictation/focus_handler.js",
     "dictation/input_controller.js",
     "dictation/macros/input_text_view_macro.js",
     "dictation/macros/list_commands_macro.js",
@@ -124,6 +125,7 @@
     "dictation/dictation_test.js",
     "dictation/dictation_test_base.js",
     "dictation/dictation_ui_test.js",
+    "dictation/focus_handler_test.js",
     "dictation/macros/dictation_macros_test.js",
     "dictation/parse/dictation_parse_test.js",
     "magnifier/magnifier_test.js",
@@ -200,6 +202,7 @@
 js_library("dictation") {
   sources = [ "dictation/dictation.js" ]
   deps = [
+    ":dictation_focus_handler",
     ":dictation_input_controller",
     ":dictation_metrics",
     ":dictation_ui_controller",
@@ -214,10 +217,6 @@
 
 js_library("dictation_input_controller") {
   sources = [ "dictation/input_controller.js" ]
-  deps = [
-    "../common:automation_predicate",
-    "../common:constants",
-  ]
   externs_list = [
     "$externs_path/input_method_private.js",
     "$externs_path/language_settings_private.js",
@@ -270,3 +269,12 @@
     "$externs_path/speech_recognition_private.js",
   ]
 }
+
+js_library("dictation_focus_handler") {
+  sources = [ "dictation/focus_handler.js" ]
+  deps = [
+    "../common:automation_predicate",
+    "../common:constants",
+  ]
+  externs_list = [ "$externs_path/automation.js" ]
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js
index a7017c2cc..68a0981 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {FocusHandler} from '/accessibility_common/dictation/focus_handler.js';
 import {InputController} from '/accessibility_common/dictation/input_controller.js';
 import {Macro} from '/accessibility_common/dictation/macros/macro.js';
 import {MacroName} from '/accessibility_common/dictation/macros/macro_names.js';
@@ -65,6 +66,9 @@
     /** @private {boolean} */
     this.isPumpkinEnabled_ = false;
 
+    /** @private {?FocusHandler} */
+    this.focusHandler_ = null;
+
     this.initialize_();
   }
 
@@ -73,8 +77,9 @@
    * @private
    */
   initialize_() {
-    this.inputController_ =
-        new InputController(() => this.stopDictation_(/*notify=*/ true));
+    this.focusHandler_ = new FocusHandler();
+    this.inputController_ = new InputController(
+        () => this.stopDictation_(/*notify=*/ true), this.focusHandler_);
     this.uiController_ = new UIController();
     this.speechParser_ = new SpeechParser(this.inputController_);
     if (this.localePref_) {
@@ -213,6 +218,7 @@
   /**
    * Called when the Speech Recognition engine receives a recognition event.
    * @param {ResultEvent} event
+   * @return {!Promise}
    * @private
    */
   async onSpeechRecognitionResult_(event) {
@@ -233,6 +239,7 @@
    * @param {string} transcript
    * @param {boolean} isFinal Whether this is a finalized transcript or an
    *     interim result.
+   * @return {!Promise}
    * @private
    */
   async processSpeechRecognitionResult_(transcript, isFinal) {
@@ -295,6 +302,7 @@
 
     this.uiController_.setState(
         UIState.STANDBY, {context: HintContext.STANDBY});
+    this.focusHandler_.refresh();
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation_test_base.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation_test_base.js
index f660e19..3c445b2a 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation_test_base.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/dictation_test_base.js
@@ -16,7 +16,11 @@
 DictationE2ETestBase = class extends E2ETestBase {
   constructor() {
     super();
+    this.navigateLacrosWithAutoComplete = true;
+
     this.mockAccessibilityPrivate = MockAccessibilityPrivate;
+    this.iconType = this.mockAccessibilityPrivate.DictationBubbleIconType;
+    this.hintType = this.mockAccessibilityPrivate.DictationBubbleHintType;
     chrome.accessibilityPrivate = this.mockAccessibilityPrivate;
 
     this.mockInputIme = MockInputIme;
@@ -31,9 +35,6 @@
     this.mockSpeechRecognitionPrivate = new MockSpeechRecognitionPrivate();
     chrome.speechRecognitionPrivate = this.mockSpeechRecognitionPrivate;
 
-    this.iconType = this.mockAccessibilityPrivate.DictationBubbleIconType;
-    this.hintType = this.mockAccessibilityPrivate.DictationBubbleHintType;
-
     this.dictationEngineId =
         '_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation';
 
@@ -64,7 +65,7 @@
     const reinit = module => {
       accessibilityCommon = new module.AccessibilityCommon();
     };
-import('/accessibility_common/accessibility_common_loader.js').then(reinit);
+    import('/accessibility_common/accessibility_common_loader.js').then(reinit);
   }
 
   /** @override */
@@ -92,6 +93,8 @@
 #include "base/command_line.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "ui/accessibility/accessibility_features.h"
+#include "components/prefs/pref_service.h"
+#include "ash/constants/ash_pref_names.h"
     `);
   }
 
@@ -99,6 +102,9 @@
   testGenPreamble() {
     super.testGenPreamble();
     GEN(`
+  browser()->profile()->GetPrefs()->SetBoolean(
+        ash::prefs::kDictationAcceleratorDialogHasBeenAccepted, true);
+
   base::OnceClosure load_cb =
     base::BindOnce(&ash::AccessibilityManager::SetDictationEnabled,
         base::Unretained(ash::AccessibilityManager::Get()),
@@ -196,6 +202,7 @@
   /**
    * Checks that the latest IME commit text matches the expected value.
    * @param {string} expected
+   * @return {!Promise}
    */
   async assertCommittedText(expected) {
     if (!this.mockInputIme.getLastCommittedParameters()) {
@@ -217,6 +224,7 @@
   /**
    * Async function to get a preference value from Settings.
    * @param {string} name
+   * @return {!Promise<*>}
    */
   async getPref(name) {
     return new Promise(resolve => {
@@ -229,6 +237,7 @@
   /**
    * Async function to set a preference value in Settings.
    * @param {string} name
+   * @return {!Promise}
    */
   async setPref(name, value) {
     return new Promise(resolve => {
@@ -307,6 +316,7 @@
    * Waits for the updateDictationBubble() API to be called with the given
    * properties.
    * @param {DictationBubbleProperties} targetProps
+   * @return {!Promise}
    */
   async waitForUIProperties(targetProps) {
     // Poll until the updateDictationBubble() API gets called with
@@ -321,7 +331,7 @@
           clearInterval(intervalId);
           resolve();
         }
-      });
+      }, 100);
     });
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler.js
new file mode 100644
index 0000000..3669fa2ec
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler.js
@@ -0,0 +1,109 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const AutomationNode = chrome.automation.AutomationNode;
+const AutomationEvent = chrome.automation.AutomationEvent;
+const EventType = chrome.automation.EventType;
+
+export class FocusHandler {
+  constructor() {
+    /** @private {boolean} */
+    this.active_ = false;
+
+    /**
+     * The currently focused editable node.
+     * @private {?AutomationNode}
+     */
+    this.editableNode_ = null;
+
+    /** @private {?number} */
+    this.deactivateTimeoutId_ = null;
+
+    /** @private {?EventHandler} */
+    this.eventHandler_ = null;
+  }
+
+  /**
+   * Starts listening to focus events and sets a timeout to deactivate after
+   * a certain amount of inactivity.
+   * @return {!Promise}
+   */
+  async refresh() {
+    if (this.deactivateTimeoutId_ !== null) {
+      clearTimeout(this.deactivateTimeoutId_);
+    }
+    this.deactivateTimeoutId_ = setTimeout(
+        () => this.deactivate_(), FocusHandler.DEACTIVATE_TIMEOUT_MS_);
+
+    await this.activate_();
+  }
+
+  /**
+   * Gets the current focus and starts listening for focus events.
+   * @private
+   * @return {!Promise}
+   */
+  async activate_() {
+    if (this.active_) {
+      return;
+    }
+
+    const desktop =
+        await new Promise(resolve => chrome.automation.getDesktop(resolve));
+
+    const focus =
+        await new Promise(resolve => chrome.automation.getFocus(resolve));
+    if (focus && AutomationPredicate.editText(focus)) {
+      this.editableNode_ = focus;
+    }
+
+    if (!this.eventHandler_) {
+      this.eventHandler_ = new EventHandler(
+          [], EventType.FOCUS, event => this.onFocusChanged_(event));
+    }
+    this.eventHandler_.setNodes(desktop);
+    this.eventHandler_.start();
+
+    this.active_ = true;
+  }
+
+  /** @private */
+  deactivate_() {
+    this.eventHandler_.stop();
+    this.eventHandler_ = null;
+    this.active_ = false;
+    this.editableNode_ = null;
+  }
+
+  /**
+   * Saves the focused node if it's an editable.
+   * @param {!AutomationEvent} event
+   * @private
+   */
+  onFocusChanged_(event) {
+    const node = event.target;
+    if (!node || !AutomationPredicate.editText(node)) {
+      this.editableNode_ = null;
+      return;
+    }
+
+    this.editableNode_ = node;
+  }
+
+  /** @return {?AutomationNode} */
+  getEditableNode() {
+    return this.editableNode_;
+  }
+
+  /** @return {boolean} */
+  isReadyForTesting() {
+    return this.active_ && this.editableNode_ !== null;
+  }
+}
+
+/**
+ * @const {number}
+ * @private
+ */
+FocusHandler.DEACTIVATE_TIMEOUT_MS_ = 45 * 1000;
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler_test.js
new file mode 100644
index 0000000..378e11a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/focus_handler_test.js
@@ -0,0 +1,121 @@
+// 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.
+
+GEN_INCLUDE(['dictation_test_base.js']);
+
+DictationFocusHandlerTest = class extends DictationE2ETestBase {
+  /** @override */
+  async setUpDeferred() {
+    await super.setUpDeferred();
+    await importModule(
+        'FocusHandler', '/accessibility_common/dictation/focus_handler.js');
+  }
+
+  /** @return {!FocusHandler} */
+  getFocusHandler() {
+    return accessibilityCommon.dictation_.focusHandler_;
+  }
+
+  /** @return {!Promise} */
+  async activateFocusHandler() {
+    await this.getFocusHandler().refresh();
+    assertTrue(this.getFocusHandler().active_);
+    assertNotNullNorUndefined(this.getFocusHandler().deactivateTimeoutId_);
+  }
+
+  /**
+   * @param {boolean} active
+   * @return {!Promise}
+   */
+  async waitForFocusHandlerActive(active) {
+    return new Promise(resolve => {
+      const intervalId = setInterval(() => {
+        if (this.getFocusHandler().active_ === active) {
+          clearInterval(intervalId);
+          resolve();
+        }
+      }, 100);
+    });
+  }
+
+  /**
+   * @param {!AutomationNode} target
+   * @return {!Promise}
+   */
+  async waitForFocus(target) {
+    return new Promise(resolve => {
+      const intervalId = setInterval(() => {
+        if (this.getFocusHandler().editableNode_ === target) {
+          clearInterval(intervalId);
+          resolve();
+        }
+      }, 100);
+    });
+  }
+
+  /** @return {string} */
+  simpleSite() {
+    return `
+      <button autofocus>Start</button>
+      <input id="first" type="text"></input>
+    `;
+  }
+};
+
+// This test ensures that FocusHandler activates when Dictation is toggled on.
+SYNC_TEST_F('DictationFocusHandlerTest', 'Activate', async function() {
+  const root = await this.runWithLoadedTree(this.simpleSite());
+  const input = root.find({role: chrome.automation.RoleType.TEXT_FIELD});
+  assertTrue(Boolean(input));
+
+  // FocusHandler should not be activated until Dictation is toggled on.
+  assertFalse(this.getFocusHandler().active_);
+  assertEquals(null, this.getFocusHandler().editableNode_);
+  input.focus();
+  this.toggleDictationOn();
+  await this.waitForFocusHandlerActive(true);
+});
+
+// This test ensures that FocusHandler deactivates automatically after a
+// period of inactivity.
+SYNC_TEST_F('DictationFocusHandlerTest', 'Deactivate', async function() {
+  // Shorten timeout for testing.
+  FocusHandler.DEACTIVATE_TIMEOUT_MS_ = 1000;
+  await this.activateFocusHandler();
+  await this.waitForFocusHandlerActive(false);
+});
+
+// This test ensures that FocusHandler tracks focus once it's been activated.
+SYNC_TEST_F('DictationFocusHandlerTest', 'OnFocusChanged', async function() {
+  await this.activateFocusHandler();
+  const root = await this.runWithLoadedTree(this.simpleSite());
+  const input = root.find({role: chrome.automation.RoleType.TEXT_FIELD});
+  assertTrue(Boolean(input));
+
+  input.focus();
+  await this.waitForFocus(input);
+});
+
+// This test ensures that the timeout to deactivate FocusHandler is reset
+// whenever Dictation toggles on.
+SYNC_TEST_F(
+    'DictationFocusHandlerTest', 'ResetDeactivateTimeout', async function() {
+      this.mockSetTimeoutMethod();
+      this.toggleDictationOn();
+      await this.waitForFocusHandlerActive(true);
+      let callback =
+          this.getCallbackWithDelay(FocusHandler.DEACTIVATE_TIMEOUT_MS_);
+      assertNotNullNorUndefined(callback);
+
+      this.clearSetTimeoutData();
+      this.toggleDictationOff();
+      this.toggleDictationOn();
+      // Toggling Dictation on should set a new timeout to deactivate
+      // FocusHandler.
+      callback = this.getCallbackWithDelay(FocusHandler.DEACTIVATE_TIMEOUT_MS_);
+      assertNotNullNorUndefined(callback);
+      // Running `callback` should deactivate FocusHandler.
+      callback();
+      await this.waitForFocusHandlerActive(false);
+    });
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/input_controller.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/input_controller.js
index 7c3d268..15c10a175 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/input_controller.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/input_controller.js
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-const AutomationNode = chrome.automation.AutomationNode;
-const AutomationEvent = chrome.automation.AutomationEvent;
-const EventType = chrome.automation.EventType;
 const IconType = chrome.accessibilityPrivate.DictationBubbleIconType;
 
 /**
  * InputController handles interaction with input fields for Dictation.
  */
 export class InputController {
-  constructor(stopDictationCallback) {
+  constructor(stopDictationCallback, focusHandler) {
     /** @private {number} */
     this.activeImeContextId_ = InputController.NO_ACTIVE_IME_CONTEXT_ID_;
 
+    /** @private {!FocusHandler} */
+    this.focusHandler_ = focusHandler;
+
     /**
      * The engine ID of the previously active IME input method. Used to
      * restore the previous IME after Dictation is deactivated.
@@ -28,15 +28,6 @@
     /** @private {?function():void} */
     this.onConnectCallback_ = null;
 
-    /**
-     * The currently focused editable node.
-     * @private {?AutomationNode}
-     */
-    this.editableNode_ = null;
-
-    /** @private {?EventHandler} */
-    this.focusHandler_ = null;
-
     this.initialize_();
   }
 
@@ -50,16 +41,6 @@
         (context) => this.onImeFocus_(context));
     chrome.input.ime.onBlur.addListener(
         (contextId) => this.onImeBlur_(contextId));
-
-    // IME focus and blur listeners do not tell us which AutomationNode is
-    // currently focused. Register a focus event handler that will give us this
-    // information.
-    this.focusHandler_ = new EventHandler(
-        [], EventType.FOCUS, event => this.onFocusChanged_(event));
-    chrome.automation.getDesktop((desktop) => {
-      this.focusHandler_.setNodes(desktop);
-      this.focusHandler_.start();
-    });
   }
 
   /**
@@ -153,20 +134,6 @@
   }
 
   /**
-   * @param {!AutomationEvent} event
-   * @private
-   */
-  onFocusChanged_(event) {
-    const node = event.target;
-    if (!node || !AutomationPredicate.editText(node)) {
-      this.editableNode_ = null;
-      return;
-    }
-
-    this.editableNode_ = node;
-  }
-
-  /**
    * @param {string} text
    * @return {string}
    */
@@ -177,14 +144,15 @@
     // space when committed to a text field. This is a temporary workaround
     // until the blocking SODA bug can be fixed. Note, a similar strategy
     // already exists in Dictation::OnSpeechResult().
-    if (!this.editableNode_ ||
+    const editableNode = this.focusHandler_.getEditableNode();
+    if (!editableNode ||
         InputController.BEGINS_WITH_WHITESPACE_REGEX_.test(text)) {
       return text;
     }
 
-    const value = this.editableNode_.value;
-    const selStart = this.editableNode_.textSelStart;
-    const selEnd = this.editableNode_.textSelEnd;
+    const value = editableNode.value;
+    const selStart = editableNode.textSelStart;
+    const selEnd = editableNode.textSelEnd;
     // Prepend a space to `text` if there is text directly left of the cursor.
     if (!selStart || selStart !== selEnd || !value ||
         InputController.BEGINS_WITH_WHITESPACE_REGEX_.test(
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/speech_parser.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/speech_parser.js
index aef2ae4..a82d9c0c 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/speech_parser.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/speech_parser.js
@@ -36,6 +36,7 @@
   /**
    * @param {string} locale The Dictation recognition locale. Only some locales
    *     are supported by Pumpkin.
+   * @return {!Promise}
    */
   async initialize(locale) {
     this.isRTLLocale_ = SpeechParser.RTLLocales.has(locale);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 791497d6..de7b6eb 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -57,6 +57,7 @@
   "common/locale_output_helper.js",
   "common/log_types.js",
   "common/msgs.js",
+  "common/panel_bridge.js",
   "common/panel_command.js",
   "common/panel_menu_data.js",
   "common/spannable.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
index 505b94f..6e4ef0fd 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -3555,17 +3555,20 @@
           .call(clearCurrentRange)
           .call(toggleTalkBack)
           .call(nextObjectKeyboard)
-          .call(() => assertFalse(!!ChromeVoxState.instance.currentRange))
+          .call(
+              () => assertFalse(Boolean(ChromeVoxState.instance.currentRange)))
 
           .call(nextObjectBraille)
-          .call(() => assertFalse(!!ChromeVoxState.instance.currentRange))
+          .call(
+              () => assertFalse(Boolean(ChromeVoxState.instance.currentRange)))
 
           .call(nextObjectGesture)
-          .call(() => assertFalse(!!ChromeVoxState.instance.currentRange))
+          .call(
+              () => assertFalse(Boolean(ChromeVoxState.instance.currentRange)))
 
           .call(toggleTalkBack)
           .call(nextObjectKeyboard)
-          .call(() => assertTrue(!!ChromeVoxState.instance.currentRange))
+          .call(() => assertTrue(Boolean(ChromeVoxState.instance.currentRange)))
 
           .replay();
     });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler.js
index 9bddfc81..98f70fcb 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler.js
@@ -384,9 +384,9 @@
         throw Error('Unknown key code in event: ' + JSON.stringify(event));
       }
       EventGenerator.sendKeyPress(numericCode, {
-        shift: !!event.shiftKey,
-        ctrl: !!event.ctrlKey,
-        alt: !!event.altKey
+        shift: Boolean(event.shiftKey),
+        ctrl: Boolean(event.ctrlKey),
+        alt: Boolean(event.altKey)
       });
     });
   }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
index db2fbd3..3caca65 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -37,7 +37,7 @@
     super();
 
     /** @private {boolean} */
-    this.isIncognito_ = !!chrome.runtime.getManifest()['incognito'];
+    this.isIncognito_ = Boolean(chrome.runtime.getManifest()['incognito']);
 
     /** @private {boolean} */
     this.languageLoggingEnabled_ = false;
@@ -868,7 +868,7 @@
           // Search for a root window with a title.
           while (target) {
             const isNamedWindow =
-                !!target.name && target.role === RoleType.WINDOW;
+                Boolean(target.name) && target.role === RoleType.WINDOW;
             const isRootView = target.className === 'RootView';
             if (isNamedWindow && !firstWindow) {
               firstWindow = target;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
index d17035a..48991631 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
@@ -688,7 +688,7 @@
           walker = walker.parent;
         }
 
-        override = !!walker || override;
+        override = Boolean(walker) || override;
       }
 
       // Autofill popup menu items are always announced on selection events,
@@ -807,7 +807,7 @@
       this.textEditHandler_ = TextEditHandler.createForNode(target);
     }
 
-    return !!this.textEditHandler_;
+    return Boolean(this.textEditHandler_);
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
index d2f235a..8554b0f7 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
@@ -48,7 +48,7 @@
       const site = `<input type="range"></input>`;
       const root = await this.runWithLoadedTree(site);
       const slider = root.find({role: RoleType.SLIDER});
-      assertTrue(!!slider);
+      assertTrue(Boolean(slider));
 
       let sliderValue = '50%';
       Object.defineProperty(slider, 'value', {get: () => sliderValue});
@@ -148,7 +148,7 @@
       const site = `<button>Hello world</button>`;
       const root = await this.runWithLoadedTree(site);
       const button = root.find({role: RoleType.BUTTON});
-      assertTrue(!!button);
+      assertTrue(Boolean(button));
       const event = new CustomAutomationEvent(EventType.ALERT, button);
       mockFeedback
           .call(() => {
@@ -183,7 +183,7 @@
         role: RoleType.TEXT_FIELD_WITH_COMBO_BOX,
         attributes: {name: 'Choose one'}
       });
-      assertTrue(!!combobox);
+      assertTrue(Boolean(combobox));
       combobox.focus();
       await new Promise(r => combobox.addEventListener(EventType.FOCUS, r));
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js
index e82b73a18..9faabfe 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js
@@ -230,7 +230,7 @@
    *     if the previous word should be spoken.
    */
   isWordBreakChar(ch) {
-    return !!ch.match(/^\W$/);
+    return Boolean(ch.match(/^\W$/));
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js
index 6d3ae5ee..e046691 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js
@@ -392,9 +392,9 @@
       return true;
     }
     const exited = AutomationUtil.getUniqueAncestors(next, deep);
-    return !!exited.find(function(item) {
+    return Boolean(exited.find(function(item) {
       return item === this.node_;
-    }.bind(this));
+    }.bind(this)));
   }
 
   /** @override */
@@ -410,9 +410,9 @@
       return true;
     }
     const exited = AutomationUtil.getUniqueAncestors(next, deep);
-    return !!exited.find(function(item) {
+    return Boolean(exited.find(function(item) {
       return item === this.node_;
-    }.bind(this));
+    }.bind(this)));
   }
 
   /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
index ef5aa9f..01f09de 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -31,6 +31,7 @@
 goog.require('NavBraille');
 goog.require('Output');
 goog.require('OutputEventType');
+goog.require('PanelBridge');
 goog.require('PanelCommand');
 goog.require('PanelCommandType');
 goog.require('PanelNodeMenuData');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js
index 811ad78..6966263c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js
@@ -67,7 +67,7 @@
     } else {
       MathHandler.instance = undefined;
     }
-    return !!MathHandler.instance;
+    return Boolean(MathHandler.instance);
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
index 430a4b1..c021b331 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
@@ -180,9 +180,9 @@
 
       // These attributes default to false for empty strings.
       case 'roleDescription':
-        return !!node.roleDescription;
+        return Boolean(node.roleDescription);
       case 'value':
-        return !!node.value;
+        return Boolean(node.value);
       case 'selected':
         return node.selected === true;
       default:
@@ -1829,7 +1829,7 @@
     }
 
     const info = new OutputAncestryInfo(
-        node, prevNode, !!optionalArgs.suppressStartEndAncestry);
+        node, prevNode, Boolean(optionalArgs.suppressStartEndAncestry));
 
     // Enter, leave ancestry.
     this.ancestryHelper_({
@@ -2347,7 +2347,7 @@
     }
     if (uniqueAncestors.find(
             /** @type {function(?) : boolean} */ (function(n) {
-              return !!n.details;
+              return Boolean(n.details);
             }))) {
       ret.push({msgId: 'hint_details'});
     }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_tree.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_tree.js
index 47a159a..afea117 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_tree.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_tree.js
@@ -33,7 +33,7 @@
       format = format.replace(/([,:])\s+/gm, '$1');
       const words = format.split(' ');
       // Ignore empty strings.
-      words.filter(word => !!word);
+      words.filter(word => Boolean(word));
 
       formatTrees = words.map(word => OutputFormatTree.buildFromString_(word));
     } else if (format) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
index a0779a7..6b502dd 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
@@ -141,7 +141,8 @@
       let maybeControlledBy = evt.target;
       while (maybeControlledBy) {
         if (maybeControlledBy.controlledBy &&
-            maybeControlledBy.controlledBy.find((n) => !!n.autoComplete)) {
+            maybeControlledBy.controlledBy.find(
+                (n) => Boolean(n.autoComplete))) {
           clearTimeout(this.delayedAttributeOutputId_);
           this.delayedAttributeOutputId_ = setTimeout(() => {
             this.lastAttributeOutput_.go();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
index 48e631907..78a65238 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
@@ -57,7 +57,8 @@
     // Several cases arise which may lead to a sticky mode toggle:
     // The node is either editable itself or a descendant of an editable.
     // The node is a relation target of an editable.
-    const shouldTurnOffStickyMode = !!this.getEditableOrRelatedEditable_(node);
+    const shouldTurnOffStickyMode =
+        Boolean(this.getEditableOrRelatedEditable_(node));
 
     // This toggler should not make any changes when the range isn't what we're
     // lloking for and we haven't previously tracked any sticky mode state from
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
index 7323980..89054b8a 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
@@ -545,7 +545,7 @@
   /** @override */
   isSpeaking() {
     super.isSpeaking();
-    return !!this.currentUtterance_;
+    return Boolean(this.currentUtterance_);
   }
 
   /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background_test.js
index 549834e..7d280210 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background_test.js
@@ -438,7 +438,7 @@
       [{textString: 'Sorry; busy!', queueMode: QueueMode.INTERJECT}]);
 
   // The above call should have resulted in a setTimeout; call it.
-  assertTrue(!!lastSetTimeoutCallback);
+  assertTrue(Boolean(lastSetTimeoutCallback));
   lastSetTimeoutCallback();
   lastSetTimeoutCallback = undefined;
 
@@ -472,7 +472,7 @@
   ]);
 
   // The above call should have resulted in a setTimeout; call it.
-  assertTrue(!!lastSetTimeoutCallback);
+  assertTrue(Boolean(lastSetTimeoutCallback));
   lastSetTimeoutCallback();
   lastSetTimeoutCallback = undefined;
 
@@ -495,7 +495,7 @@
   tts.speak('Sorry! Gotta go!', QueueMode.INTERJECT, {});
   this.expectUtteranceQueueIsLike(
       [{textString: 'Sorry! Gotta go!', queueMode: QueueMode.INTERJECT}]);
-  assertTrue(!!lastSetTimeoutCallback);
+  assertTrue(Boolean(lastSetTimeoutCallback));
   lastSetTimeoutCallback();
   lastSetTimeoutCallback = undefined;
 
@@ -529,7 +529,7 @@
   tts.toggleSpeechOnOrOff();
 
   // The above call should have resulted in a setTimeout; call it.
-  assertTrue(!!lastSetTimeoutCallback);
+  assertTrue(Boolean(lastSetTimeoutCallback));
   lastSetTimeoutCallback();
   lastSetTimeoutCallback = undefined;
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille/braille_table_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille/braille_table_test.js
index c8f33a18..85fa526e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille/braille_table_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille/braille_table_test.js
@@ -50,7 +50,8 @@
       // Try getting a display name for a non-English language.
       chrome.i18n.getUILanguage = () => 'fr';
       displayName = BrailleTable.getDisplayName(table);
-      assertTrue(!!displayName, 'No display name for table: ' + table.id);
+      assertTrue(
+          Boolean(displayName), 'No display name for table: ' + table.id);
       assertTrue(displayName.length > 0);
 
       // Other languages only use the enDisplayName if they need to disambiguate
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.js
index 6a74fbe..9ce6a70 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/command_store.js
@@ -95,7 +95,7 @@
   if (!CommandStore.CMD_ALLOWLIST[command]) {
     return false;
   }
-  return !!CommandStore.CMD_ALLOWLIST[command].denyOOBE;
+  return Boolean(CommandStore.CMD_ALLOWLIST[command].denyOOBE);
 };
 
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js
index 600ba50..2987e0a0 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence.js
@@ -47,21 +47,21 @@
       originalEvent, opt_cvoxModifier, opt_doubleTap, opt_skipStripping,
       opt_requireStickyMode) {
     /** @type {boolean} */
-    this.doubleTap = !!opt_doubleTap;
+    this.doubleTap = Boolean(opt_doubleTap);
 
     /** @type {boolean} */
-    this.requireStickyMode = !!opt_requireStickyMode;
+    this.requireStickyMode = Boolean(opt_requireStickyMode);
 
     /** @type {boolean} */
-    this.skipStripping = !!opt_skipStripping;
+    this.skipStripping = Boolean(opt_skipStripping);
 
     if (opt_cvoxModifier === undefined) {
       this.cvoxModifier = this.isCVoxModifierActive(originalEvent);
     } else {
       this.cvoxModifier = opt_cvoxModifier;
     }
-    this.stickyMode = !!originalEvent['stickyMode'];
-    this.prefixKey = !!originalEvent['keyPrefix'];
+    this.stickyMode = Boolean(originalEvent['stickyMode']);
+    this.prefixKey = Boolean(originalEvent['keyPrefix']);
 
     if (this.stickyMode && this.prefixKey) {
       throw 'Prefix key and sticky mode cannot both be enabled: ' +
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/injected/api.js b/chrome/browser/resources/chromeos/accessibility/chromevox/injected/api.js
index 1ad49161..84ecd1d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/injected/api.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/injected/api.js
@@ -206,7 +206,7 @@
  * @return {boolean} True if ChromeVox is currently active.
  */
 cvox.Api.isChromeVoxActive = function() {
-  return !!channel;
+  return Boolean(channel);
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback.js
index 4c34c44..93daf54 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback.js
@@ -165,8 +165,8 @@
     Array.prototype.forEach.call(arguments, function(text) {
       this.pendingActions_.push({
         perform: function() {
-          return !!MockFeedback.matchAndConsume_(
-              text, {}, this.pendingUtterances_);
+          return Boolean(
+              MockFeedback.matchAndConsume_(text, {}, this.pendingUtterances_));
         }.bind(this),
         toString() {
           return 'Speak \'' + text + '\'';
@@ -239,8 +239,8 @@
     Array.prototype.forEach.call(rest, function(text) {
       this.pendingActions_.push({
         perform: function() {
-          return !!MockFeedback.matchAndConsume_(
-              text, expectedProps, this.pendingUtterances_);
+          return Boolean(MockFeedback.matchAndConsume_(
+              text, expectedProps, this.pendingUtterances_));
         }.bind(this),
         toString() {
           return 'Speak \'' + text + '\' with props ' +
@@ -305,7 +305,7 @@
         if (match) {
           this.lastMatchedBraille_ = match;
         }
-        return !!match;
+        return Boolean(match);
       }.bind(this),
       toString() {
         return 'Braille \'' + text + '\' ' + JSON.stringify(props);
@@ -326,7 +326,7 @@
       perform: function() {
         const match =
             MockFeedback.matchAndConsume_(earconName, {}, this.pendingEarcons_);
-        return !!match;
+        return Boolean(match);
       }.bind(this),
       toString() {
         return 'Earcon \'' + earconName + '\'';
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js
index 3e9752d..4f9b6c9 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_button.js
@@ -87,16 +87,28 @@
     // need to defer this until <emoji-variants> is created and sized by
     // Polymer.
     beforeNextRender(this, () => {
-      const button = this.variantsVisible ? this : null;
       const variants = this.variantsVisible ?
           this.shadowRoot.querySelector('emoji-variants') :
           null;
 
       this.dispatchEvent(
-          createCustomEvent(EMOJI_VARIANTS_SHOWN, {button, variants}));
+          createCustomEvent(EMOJI_VARIANTS_SHOWN,
+            {owner: this, variants: variants, baseEmoji: this.emoji}));
     });
   }
 
+  /**
+   * Hides emoji variants if any is visible.
+   */
+   hideEmojiVariants() {
+    /**
+     * TODO(b/233130994): Remove the function as part of the component removal.
+     * The function is only added to help merging emoji-button into
+     * emoji-group to allow removing emoji-button later.
+     */
+    this.variantsVisible = false;
+  }
+
   _className(variants) {
     return variants && variants.length > 0 ? 'has-variants' : '';
   }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
index 2e9acab..1ad99467 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -25,7 +25,7 @@
     justify-items: center;
   }
 
-  :host(:not([use-flex-layout])) emoji-button {
+  :host(:not([use-flex-layout])) {
     --emoji-button-button-style: {
       background: var(--emoji-background);
       border: none;
@@ -53,7 +53,7 @@
     gap: 12px 20px;
   }
 
-  :host([use-flex-layout]) emoji-button {
+  :host([use-flex-layout]) {
     --emoji-button-button-style: {
       background: var(--emoji-background);
       border: none;
@@ -137,12 +137,88 @@
      * border.*/
     padding: 7px 11px 7px 11px;
   }
+
   #clear-recents-hover:hover {
     background-color: var(--cros-button-background-color-secondary-hover);
     border: 2px solid var(--cros-button-background-color-secondary-hover);
   }
+
+  .emoji-button-container {
+    --emoji-background: transparent;
+    /* Fixed height and width are required for buttons that have variants,
+     * Otherwise, when showing variants, buttons' positions will be moved.
+     */
+    height: var(--emoji-button-height);
+    position: relative;
+    width: var(--emoji-button-width);
+  }
+
+  .emoji-button {
+    /* TODO(b/233130994): Remove this CSS mixin and use classes instead. */
+    @apply --emoji-button-button-style;
+  }
+
+  .emoji-button:focus,
+  .emoji-button:active {
+    outline-color: var(--cros-focus-ring-color);
+    outline-style: solid;
+    outline-width: 2px;
+  }
+
+  .emoji-button:disabled {
+    /* chrome makes disabled buttons semitransparent.
+     * we set a solid colour here to prevent that
+     * (exactly which colour is not important).
+     */
+    color: red;
+    cursor: default;
+  }
+
+  .emoji-button:hover {
+    background-color: var(--emoji-hover-background);
+  }
+
+  /* Implement has-variants as ::after so that it still works with hover
+   * ripple.
+   */
+  .has-variants::after {
+    /* 4px grey triangle in bottom-right.
+     * 315 degrees means starting at bottom-right towards top-left.
+     * Manual color here because there isn't something easy to use, but fine
+     * for dark mode since dark mode is the same.
+     */
+    background: linear-gradient(
+        315deg, var(--google-grey-500) 4px,
+        var(--emoji-background) 4px, var(--emoji-background));
+    content: '';
+    display: block;
+    height: var(--emoji-size);
+    position: relative;
+    top: calc(0px - var(--emoji-size));
+    width: var(--emoji-size);
+  }
+
+  paper-tooltip {
+    --paper-tooltip-background: var(--cros-tooltip-background-color);
+    --paper-tooltip-delay-in: var(--emoji-tooltip-delay-in);
+    --paper-tooltip-delay-out: var(--emoji-tooltip-delay-out);
+    --paper-tooltip-duration-in: 0;
+    --paper-tooltip-duration-out: 0;
+    --paper-tooltip-opacity: 1;
+    --paper-tooltip-text-color: var(--cros-tooltip-label-color);
+  }
+
+  paper-tooltip::part(tooltip) {
+    box-shadow: var(--cr-elevation-1);
+    font-family: 'Roboto', sans-serif;
+    font-size: 12px;
+    margin: 4px;
+    padding: 4px 8px 4px 8px;
+    white-space: nowrap;
+  }
 </style>
 
+<!-- Add header section. -->
 <template is="dom-if" if="[[group]]">
   <div id="heading" role="heading" aria-level="2" tabindex="-1">
     <div id="heading-left">[[group]]</div>
@@ -160,13 +236,32 @@
     </div>
   </button>
 </template>
-<div id="emoji">
+
+<!-- Add emoji buttons.
+  Note that the click and context menu listeners are shared among all the
+  elements to improve efficiency and performance.
+  -->
+<div id="emoji" on-click="onEmojiClick" on-contextmenu="onEmojiContextMenu">
   <div id="fake-focus-target" tabindex="-1"></div>
   <template is="dom-repeat" items="[[data]]">
-    <!-- TODO(b/233130994): Replace emoji-button with button. -->
-    <emoji-button emoji="[[getDisplayEmojiForEmoji(item.base.string)]]"
-      variants="[[item.alternates]]" category="[[category]]"
-      tooltip="[[getTooltipForEmoji(item.base)]]">
-    </emoji-button>
+    <div class="emoji-button-container">
+      <button id="[[getEmojiButtonId(index)]]" data-index$="[[index]]"
+        class$="[[getEmojiButtonClassName(item)]]"
+        aria-label="[[getEmojiAriaLabel(item)]]">
+        [[getDisplayEmojiForEmoji(item.base.string)]]
+      </button>
+      <paper-tooltip for="[[getEmojiButtonId(index)]]"
+        fit-to-visible-bounds offset="8">
+        [[item.base.name]]
+      </paper-tooltip>
+      <template is="dom-if"
+        if="[[isEmojiVariantVisible(index,shownEmojiVariantIndex)]]">
+        <emoji-variants
+          id="[[getEmojiVariantId(index)]]"
+          variants="[[item.alternates]]"
+          tooltip="[[item.base.name]]">
+        </emoji-variants>
+      </template>
+    </div>
   </template>
 </div>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
index b9bc797..7256c42c 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
@@ -4,11 +4,11 @@
 
 import './emoji_button.js';
 
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {createCustomEvent, EMOJI_CLEAR_RECENTS_CLICK} from './events.js';
+import {beforeNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {createCustomEvent, EMOJI_VARIANTS_SHOWN, EMOJI_BUTTON_CLICK, EMOJI_CLEAR_RECENTS_CLICK} from './events.js';
 import {CategoryEnum, EmojiVariants} from './types.js';
 
-class EmojiGroupComponent extends PolymerElement {
+export class EmojiGroupComponent extends PolymerElement {
   static get is() {
     return 'emoji-group';
   }
@@ -33,6 +33,10 @@
         value: CategoryEnum.EMOJI,
         readonly: true,
       },
+      /** @private {?number} */
+      shownEmojiVariantIndex: {type: Number, value: null},
+      /** @private {?boolean} */
+      isLangEnglish: {type: Boolean, value: false},
       /** @type {boolean} */
       useFlexLayout: {
         type: Boolean,
@@ -43,13 +47,12 @@
     };
   }
 
-  /** @param emoji {Emoji} */
-  getTooltipForEmoji(emoji) {
-    return emoji.name;
-  }
+  constructor() {
+    super();
 
-  getDisplayEmojiForEmoji(emoji) {
-    return this.preferred[emoji] || emoji;
+    // TODO(crbug/1227852): Remove after setting arial label to emoji.
+    this.isLangEnglish = navigator.languages.some(
+      lang => lang.startsWith('en')) > 0;
   }
 
   /**
@@ -81,19 +84,188 @@
   }
 
   /**
-   * Returns the first emoji button (<button>) in the group.
+   * Handles event of clicking on an emoji button. It finds the emoji details
+   * for the clicked emoji and fires another event including these the details.
+   * Note: Initially, it validates and returns if the event is not for an
+   * emoji button.
    *
-   * @returns {Element} The first button if exist, otherwise null.
+   * @fires CustomEvent#`EMOJI_BUTTON_CLICK`
+   * @param {MouseEvent} event Click event
    */
-  firstEmojiButton() {
-    // TODO(b/234074956): Change to optional chaining in typescript.
-    const emojiButton = this.shadowRoot.querySelector('emoji-button');
+  onEmojiClick(event) {
+    const emoji = this.findEmojiOfEmojiButton(event.target);
 
-    if (emojiButton) {
-      return emojiButton.shadowRoot.querySelector('#emoji-button');
+    // Ensure target is an emoji button.
+    if (!emoji) {
+      return;
     }
 
-    return null;
+    const text = this.getDisplayEmojiForEmoji(emoji.base.string);
+
+    this.dispatchEvent(createCustomEvent(EMOJI_BUTTON_CLICK, {
+      text: text,
+      isVariant: text !== emoji.base.string,
+      baseEmoji: emoji.base.string,
+      allVariants: emoji.alternates,
+      name: emoji.base.name,
+      category: this.category,
+    }));
+  }
+
+  /**
+   * Handles event of opening context menu of an emoji button. Emoji variants
+   * are shown as the context menu.
+   * Note: Initially, it validates and returns if the event is not for an
+   * emoji button.
+   *
+   * @fires CustomEvent#`EMOJI_VARIANTS_SHOWN`
+   * @param {Event} event
+   */
+  onEmojiContextMenu(event) {
+    const emoji = this.findEmojiOfEmojiButton(event.target);
+
+    // Ensure target is an emoji button.
+    if (!emoji) {
+      return;
+    }
+    event.preventDefault();
+
+    const dataIndex = parseInt(event.target.getAttribute('data-index'), 10);
+
+    // If the variants of the emoji is already shown, then hide it.
+    // Otherwise, show the variants if there are some.
+    if (emoji.alternates && emoji.alternates.length &&
+        dataIndex !== this.shownEmojiVariantIndex) {
+          this.shownEmojiVariantIndex = dataIndex;
+    } else {
+      this.shownEmojiVariantIndex = null;
+    }
+
+    // Send event so emoji-picker knows to close other variants.
+    // need to defer this until <emoji-variants> is created and sized by
+    // Polymer.
+    beforeNextRender(this, () => {
+      const variants = this.shownEmojiVariantIndex ?
+          this.shadowRoot.getElementById(this.getEmojiVariantId(dataIndex)) :
+          null;
+
+      this.dispatchEvent(createCustomEvent(EMOJI_VARIANTS_SHOWN, {
+        owner: this,
+        variants: variants,
+        baseEmoji: emoji.base.string,
+      }));
+    });
+  }
+
+  /**
+   * Returns the id of an emoji button element at a specific data index.
+   *
+   * @param {number} index Index of the emoji button in `this.data`.
+   * @returns {string} The id of the element.
+   */
+  getEmojiButtonId(index) {
+    return `emoji-${index}`;
+  }
+
+  /**
+   * Returns the id of an emoji variants element for an emoji at a
+   * specific data index.
+   *
+   * @param {number} index Index of the emoji in `this.data`.
+   * @returns {string} The id of the element.
+   */
+  getEmojiVariantId(index) {
+    return `emoji-variant-${index}`;
+  }
+
+  /**
+   * Returns HTML class attribute of an emoji button.
+   *
+   * @param {EmojiVariants} emoji The emoji to be shown.
+   * @returns {string} HTML class attribute of the button.
+   */
+  getEmojiButtonClassName(emoji) {
+    if (emoji.alternates && emoji.alternates.length > 0) {
+      return 'emoji-button has-variants';
+    } else {
+      return 'emoji-button';
+    }
+  }
+
+  /**
+   * Returns the arial label of an emoji.
+   *
+   * @param {EmojiVariants} emoji The emoji to be shown.
+   * @returns {string} Arial label for the input emoji.
+   */
+  getEmojiAriaLabel(emoji) {
+    // TODO(crbug/1227852): Just use emoji as the tooltip once ChromeVox can
+    // announce them properly.
+    const emojiLabel = this.isLangEnglish ?
+        emoji.base.name : this.getDisplayEmojiForEmoji(emoji.base.string);
+    if (emoji.alternates && emoji.alternates.length > 0) {
+      return emojiLabel + ' with variants.';
+    } else {
+      return emojiLabel;
+    }
+  }
+
+  /**
+   * Returns the character to be shown for the emoji.
+   *
+   * @param {string} baseEmoji Base emoji character.
+   * @returns {string} Character to be shown for the emoji.
+   */
+  getDisplayEmojiForEmoji(baseEmoji) {
+    return this.preferred[baseEmoji] || baseEmoji;
+  }
+
+  /**
+   * Return weather variants of an emoji is visible or not.
+   *
+   * @param {number} emojiIndex Index of an emoji in `this.data`.
+   * @param {?number} shownEmojiVariantIndex Index of an emoji variant that is
+   *    shown.
+   * @returns {boolean} True if the variants is shown and false otherwise.
+   */
+  isEmojiVariantVisible(emojiIndex, shownEmojiVariantIndex) {
+    return emojiIndex === shownEmojiVariantIndex;
+  }
+
+  /**
+   * Hides emoji variants if any is visible.
+   */
+  hideEmojiVariants() {
+    this.shownEmojiVariantIndex = null;
+  }
+
+  /**
+   * Finds emoji details for an HTML button based on the attribute of
+   * data-index and event target information.
+   * The result will be null if the target is not for a button element
+   * or it does not have data-index attribute.
+   *
+   * @param {?EventTarget} target focused element
+   * @returns {?EmojiVariants} Emoji details.
+   */
+  findEmojiOfEmojiButton(target){
+    // TODO(b/234074956): Use optional chaining when converting to TS.
+    const dataIndex = target ? target.getAttribute('data-index') : null;
+
+    if (target.nodeName !== 'BUTTON' || !dataIndex) {
+      return null;
+    }
+    return this.data[parseInt(dataIndex, 10)];
+  }
+
+  /**
+   * Returns the first emoji button in the group.
+   *
+   * @returns {HTMLButtonElement} The first button if exist, otherwise null.
+   */
+   firstEmojiButton() {
+    return /** @type {HTMLButtonElement} */ (
+      this.shadowRoot.querySelector('.emoji-button'));
   }
 }
 
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
index 44630df..0cfbdd1 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -10,7 +10,7 @@
 import 'chrome://resources/cr_elements/cr_icons_css.m.js';
 import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import * as constants from './constants.js';
-import {EmojiButton} from './emoji_button.js';
+import {EmojiGroupComponent} from './emoji_group.js';
 import {Feature} from './emoji_picker.mojom-webui.js';
 import {EmojiPickerApiProxy, EmojiPickerApiProxyImpl} from './emoji_picker_api_proxy.js';
 import * as events from './events.js';
@@ -115,7 +115,7 @@
     /** @private {?number} */
     this.groupButtonScrollTimeout = null;
 
-    /** @private {?EmojiButton} */
+    /** @private {?EmojiGroupComponent} */
     this.activeVariant = null;
 
     /** @private {!EmojiPickerApiProxy} */
@@ -639,7 +639,7 @@
 
   hideEmojiVariants() {
     if (this.activeVariant) {
-      this.activeVariant.variantsVisible = false;
+      this.activeVariant.hideEmojiVariants();
       this.activeVariant = null;
     }
   }
@@ -704,10 +704,19 @@
    * @param {!events.EmojiVariantsShownEvent} ev
    */
   onShowEmojiVariants(ev) {
-    this.hideEmojiVariants();
-    this.activeVariant = /** @type {EmojiButton} */ (ev.detail.button);
-    if (this.activeVariant) {
-      this.$.message.textContent = this.activeVariant + ' variants shown.';
+
+    // Hide the currently shown emoji variants if the new one belongs
+    // to a different emoji group.
+    if (this.activeVariant && ev.detail.owner !== this.activeVariant) {
+      this.hideEmojiVariants();
+    }
+
+    this.activeVariant =
+        /** @type {EmojiGroupComponent} */ (ev.detail.owner);
+
+    // Updates the UI if a variant is shown.
+    if (ev.detail.variants) {
+      this.$.message.textContent = ev.detail.baseEmoji + ' variants shown.';
       this.positionEmojiVariants(ev.detail.variants);
     }
   }
diff --git a/chrome/browser/resources/chromeos/emoji_picker/events.js b/chrome/browser/resources/chromeos/emoji_picker/events.js
index 3d2cc1b8..a404d7a 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/events.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/events.js
@@ -25,7 +25,15 @@
 export const EMOJI_BUTTON_CLICK = 'emoji-button-click';
 
 /**
- * @typedef {!CustomEvent<{button: ?Element, variants: ?Element}>}
+ * TODO(b/233130994): Update the type after removing emoji-button.
+ * The current event type is used as an intermediate step for a refactor
+ * leading to the removal of emoji-button. Therefore, its current state allows
+ * keeping variants events for both emoji-button and emoji-group valid at the
+ * same time. It will be be improved after removing emoji-button.
+ */
+/**
+ * @typedef {!CustomEvent<{owner: ?Element,
+ *            variants: ?Element, baseEmoji: String}>}
  */
 export let EmojiVariantsShownEvent;
 
diff --git a/chrome/browser/resources/media/mei_preload/manifest.json b/chrome/browser/resources/media/mei_preload/manifest.json
index d7cb3438..1b4fa8a1 100644
--- a/chrome/browser/resources/media/mei_preload/manifest.json
+++ b/chrome/browser/resources/media/mei_preload/manifest.json
@@ -1,8 +1,8 @@
 {
   "name": "MEI Preload", 
   "icons": {}, 
-  "version": "1.0.6.0", 
+  "version": "1.0.7.1652906823", 
   "manifest_version": 2, 
   "update_url": "https://clients2.google.com/service/update2/crx", 
   "description": "Contains preloaded data for Media Engagement"
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/resources/media/mei_preload/preloaded_data.pb b/chrome/browser/resources/media/mei_preload/preloaded_data.pb
index 9cf6733c..78f104c 100644
--- a/chrome/browser/resources/media/mei_preload/preloaded_data.pb
+++ b/chrome/browser/resources/media/mei_preload/preloaded_data.pb
Binary files differ
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
index 37c7d0ea..589356f 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
@@ -12,8 +12,7 @@
   #dialog {
     background-color: var(--md-background-color);
     border: 0;
-    display: flex;
-    flex-direction: column;
+    display: block;
     height: 100vh;
     margin: 0;
     max-height: 100vh;
@@ -22,14 +21,10 @@
     width: 100vw;
   }
 
-  settings-privacy-guide-page {
-    margin-inline-end: auto;
-    margin-inline-start: auto;
-  }
-
   settings-privacy-guide-page::part(privacyGuideCard) {
     background-color: transparent;
     box-shadow: none;
+    margin: auto;
     max-width: 680px;
     min-width: 550px;
   }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediatorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediatorTest.java
index bc189d1..456bbcc 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediatorTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediatorTest.java
@@ -69,13 +69,6 @@
 
     @Test
     @MediumTest
-    public void testShowAreaSelectionDone() {
-        mMediator.showAreaSelectionDialog(mBitmap);
-        Assert.assertTrue(mMediator.getDialog().isShowing());
-    }
-
-    @Test
-    @MediumTest
     public void testAreaSelectionDone() {
         mMediator.showAreaSelectionDialog(mBitmap);
         Assert.assertTrue(mMediator.getDialog().isShowing());
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index 29ca3f6c..12ae499 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -6,6 +6,7 @@
 
 #include "base/check.h"
 #include "base/logging.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/bind.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -16,9 +17,11 @@
 #include "chrome/browser/sync/test/integration/sync_app_helper.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
+#include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
 #include "chrome/browser/web_applications/commands/install_from_info_command.h"
 #include "chrome/browser/web_applications/test/web_app_test_observers.h"
 #include "chrome/browser/web_applications/web_app_command_manager.h"
+#include "chrome/browser/web_applications/web_app_id.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
@@ -37,29 +40,21 @@
   return "fakeapp" + base::NumberToString(index);
 }
 
-std::unique_ptr<web_app::WebAppTestInstallObserver>
-SetupSyncInstallObserverForProfile(Profile* profile) {
-  auto apps_to_be_sync_installed = web_app::WebAppProvider::GetForTest(profile)
-                                       ->install_manager()
-                                       .GetEnqueuedInstallAppIdsForTesting();
-
-  if (apps_to_be_sync_installed.empty()) {
-    return nullptr;
-  }
-
-  auto install_observer =
-      std::make_unique<web_app::WebAppTestInstallObserver>(profile);
-  install_observer->BeginListening(apps_to_be_sync_installed);
-  return install_observer;
-}
-
 std::unique_ptr<web_app::WebAppTestUninstallObserver>
-SetupSyncUninstallObserverForProfile(Profile* profile) {
+SetupUninstallObserverForProfile(Profile* profile) {
   std::set<web_app::AppId> apps_in_sync_uninstall =
       web_app::WebAppProvider::GetForTest(profile)
           ->sync_bridge()
           .GetAppsInSyncUninstallForTest();
 
+  std::vector<web_app::AppId> apps_in_uninstall =
+      web_app::WebAppProvider::GetForTest(profile)
+          ->install_finalizer()
+          .GetPendingUninstallsForTesting();
+
+  apps_in_sync_uninstall.insert(apps_in_uninstall.begin(),
+                                apps_in_uninstall.end());
+
   if (apps_in_sync_uninstall.empty()) {
     return nullptr;
   }
@@ -70,6 +65,55 @@
   return uninstall_observer;
 }
 
+void FlushPendingOperations(std::vector<Profile*> profiles) {
+  for (Profile* profile : profiles) {
+    web_app::WebAppProvider::GetForTest(profile)
+        ->command_manager()
+        .AwaitAllCommandsCompleteForTesting();
+
+    // First, wait for all installations to complete.
+
+    std::set<web_app::AppId> apps_to_be_installed =
+        web_app::WebAppProvider::GetForTest(profile)
+            ->install_manager()
+            .GetEnqueuedInstallAppIdsForTesting();
+
+    std::vector<web_app::AppId> apps_to_be_sync_installed =
+        web_app::WebAppProvider::GetForTest(profile)
+            ->registrar()
+            .GetAppsFromSyncAndPendingInstallation();
+    apps_to_be_installed.insert(apps_to_be_sync_installed.begin(),
+                                apps_to_be_sync_installed.end());
+
+    if (!apps_to_be_installed.empty()) {
+      // Because we don't know whether these have been installed yet or if we
+      // are waiting for installation with hooks, wait on either.
+      base::RunLoop loop;
+      auto install_listener_callback =
+          base::BindLambdaForTesting([&](const web_app::AppId& app_id) {
+            apps_to_be_installed.erase(app_id);
+            if (apps_to_be_installed.empty())
+              loop.Quit();
+          });
+
+      web_app::WebAppInstallManagerObserverAdapter install_adapter(profile);
+      install_adapter.SetWebAppInstalledDelegate(install_listener_callback);
+      install_adapter.SetWebAppInstalledWithOsHooksDelegate(
+          install_listener_callback);
+      loop.Run();
+    }
+
+    // Next, wait for uninstalls. These are easier because they don't have two
+    // stages.
+    std::unique_ptr<web_app::WebAppTestUninstallObserver> uninstall_observer =
+        SetupUninstallObserverForProfile(profile);
+    // This actually waits for all observed apps to be installed.
+    if (uninstall_observer) {
+      uninstall_observer->Wait();
+    }
+  }
+}
+
 }  // namespace
 
 namespace apps_helper {
@@ -194,20 +238,21 @@
   SyncAppHelper::GetInstance()->FixNTPOrdinalCollisions(profile);
 }
 
-void AwaitWebAppQuiescence(std::vector<Profile*> profiles) {
-  for (Profile* profile : profiles) {
-    std::unique_ptr<web_app::WebAppTestInstallObserver> install_observer =
-        SetupSyncInstallObserverForProfile(profile);
-    // This actually waits for all observed apps to be installed.
-    if (install_observer) {
-      install_observer->Wait();
-    }
+bool AwaitWebAppQuiescence(std::vector<Profile*> profiles) {
+  FlushPendingOperations(profiles);
 
-    std::unique_ptr<web_app::WebAppTestUninstallObserver> uninstall_observer =
-        SetupSyncUninstallObserverForProfile(profile);
-    // This actually waits for all observed apps to be installed.
-    if (uninstall_observer) {
-      uninstall_observer->Wait();
+  // If sync is off, then `AwaitQuiescence()` will crash. This code can be
+  // removed once https://crbug.com/1330792 is fixed.
+  if (sync_datatype_helper::test()) {
+    SyncTest* test = sync_datatype_helper::test();
+    bool is_sync_on = true;
+    for (SyncServiceImplHarness* client : test->GetSyncClients()) {
+      is_sync_on = is_sync_on && client->service()->IsSyncFeatureActive();
+    }
+    if (is_sync_on) {
+      if (!test->AwaitQuiescence())
+        return false;
+      FlushPendingOperations(profiles);
     }
   }
 
@@ -218,17 +263,27 @@
     // happens asynchronously after the observer gets OnWebAppInstalled. And
     // some installs might not have OS hooks installed but they will be in the
     // registry.
-    ASSERT_TRUE(web_app::WebAppProvider::GetForTest(profile)
-                    ->registrar()
-                    .GetAppsFromSyncAndPendingInstallation()
-                    .empty());
+    std::vector<web_app::AppId> sync_apps_pending_install =
+        web_app::WebAppProvider::GetForTest(profile)
+            ->registrar()
+            .GetAppsFromSyncAndPendingInstallation();
+    if (!sync_apps_pending_install.empty()) {
+      LOG(ERROR) << "Apps from sync are still pending installation: "
+                 << sync_apps_pending_install.size();
+      return false;
+    }
 
     std::set<web_app::AppId> apps_in_sync_uninstall =
         web_app::WebAppProvider::GetForTest(profile)
             ->sync_bridge()
             .GetAppsInSyncUninstallForTest();
-    ASSERT_TRUE(apps_in_sync_uninstall.empty());
+    if (!apps_in_sync_uninstall.empty()) {
+      LOG(ERROR) << "App uninstalls from sync are still pending: "
+                 << apps_in_sync_uninstall.size();
+      return false;
+    }
   }
+  return true;
 }
 
 web_app::AppId InstallWebApp(Profile* profile, const WebAppInstallInfo& info) {
diff --git a/chrome/browser/sync/test/integration/apps_helper.h b/chrome/browser/sync/test/integration/apps_helper.h
index 020b924..a77ee24a 100644
--- a/chrome/browser/sync/test/integration/apps_helper.h
+++ b/chrome/browser/sync/test/integration/apps_helper.h
@@ -110,8 +110,9 @@
 // Fix any NTP icon collisions that are currently in |profile|.
 void FixNTPOrdinalCollisions(Profile* profile);
 
-// Wait for all the web app install and uninstall tasks to finish.
-void AwaitWebAppQuiescence(std::vector<Profile*> profiles);
+// Flushes pending changes and verifies that the profiles have no pending
+// installs or uninstalls afterwards.
+bool AwaitWebAppQuiescence(std::vector<Profile*> profiles);
 }  // namespace apps_helper
 
 // An app specific version of StatusChangeChecker which checks the exit
diff --git a/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
index bbdb51d2..172b266 100644
--- a/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_web_apps_sync_test.cc
@@ -66,8 +66,7 @@
   }
 
   void AwaitWebAppQuiescence() {
-    ASSERT_TRUE(AwaitQuiescence());
-    apps_helper::AwaitWebAppQuiescence(GetAllProfiles());
+    ASSERT_TRUE(apps_helper::AwaitWebAppQuiescence(GetAllProfiles()));
     content::RunAllTasksUntilIdle();
     base::RunLoop run_loop;
     internals::GetShortcutIOTaskRunner()->PostTask(
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
index 51802b0..31a0c23 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_bmo_sync_test.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/webapps/browser/install_result_code.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
@@ -38,10 +39,14 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/app_sorting.h"
 #include "extensions/browser/extension_system.h"
+#include "testing/gmock/include/gmock/gmock.h"
 
 namespace web_app {
 namespace {
 
+using testing::ElementsAreArray;
+using testing::Not;
+
 std::unique_ptr<KeyedService> CreateFakeWebAppProvider(Profile* profile) {
   auto provider = std::make_unique<FakeWebAppProvider>(profile);
   provider->SetOsIntegrationManager(std::make_unique<FakeOsIntegrationManager>(
@@ -78,20 +83,8 @@
     return true;
   }
 
-  // Installs a dummy app with the given |url| on |profile1| and waits for it to
-  // sync to |profile2|. This ensures that the sync system has fully flushed any
-  // pending changes from |profile1| to |profile2|.
-  AppId InstallDummyAppAndWaitForSync(const GURL& url,
-                                      Profile* profile1,
-                                      Profile* profile2) {
-    WebAppInstallInfo info = WebAppInstallInfo();
-    info.title = base::UTF8ToUTF16(url.spec());
-    info.start_url = url;
-    AppId dummy_app_id = InstallApp(info, profile1);
-    EXPECT_EQ(WebAppTestInstallObserver(profile2).BeginListeningAndWait(
-                  {dummy_app_id}),
-              dummy_app_id);
-    return dummy_app_id;
+  bool AwaitWebAppQuiescence() {
+    return apps_helper::AwaitWebAppQuiescence(GetAllProfiles());
   }
 
   GURL GetUserInitiatedAppURL() const {
@@ -181,19 +174,8 @@
     return extensions::ExtensionSystem::Get(profile)->app_sorting();
   }
 
-  bool AllProfilesHaveSameWebAppIds() {
-    absl::optional<base::flat_set<AppId>> app_ids;
-    for (Profile* profile : GetAllProfiles()) {
-      base::flat_set<AppId> profile_app_ids(GetRegistrar(profile).GetAppIds());
-      if (!app_ids) {
-        app_ids = profile_app_ids;
-      } else {
-        if (app_ids != profile_app_ids) {
-          return false;
-        }
-      }
-    }
-    return true;
+  std::vector<AppId> GetAllAppIdsForProfile(Profile* profile) {
+    return GetRegistrar(profile).GetAppIds();
   }
 
  private:
@@ -205,7 +187,8 @@
                        DISABLED_SyncDoubleInstallation) {
   ASSERT_TRUE(SetupClients());
   ASSERT_TRUE(embedded_test_server()->Start());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   // Install web app to both profiles.
   AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
@@ -215,12 +198,10 @@
 
   ASSERT_TRUE(SetupSync());
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
-                                GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
@@ -240,14 +221,10 @@
 
   ASSERT_TRUE(SetupSync());
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy1.org/"), GetProfile(0),
-                                GetProfile(1));
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy2.org/"), GetProfile(1),
-                                GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   // The titles should respect the installation, even though the sync system
   // would only have one name.
   EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppShortName(app_id), "Test name");
@@ -265,7 +242,8 @@
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
                        MAYBE_SyncDoubleInstallationDifferentUserDisplayMode) {
   ASSERT_TRUE(SetupClients());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   WebAppInstallInfo info;
   info.title = u"Test name";
@@ -282,14 +260,10 @@
 
   ASSERT_TRUE(SetupSync());
 
-  // Install a 'dummy' apps & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy1.org/"), GetProfile(0),
-                                GetProfile(1));
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy2.org/"), GetProfile(1),
-                                GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   // The user display setting is syned, so these should match. However, the
   // actual value here is racy.
@@ -299,26 +273,31 @@
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, DisplayMode) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   WebAppTestInstallObserver install_observer(GetProfile(1));
+  WebAppTestInstallWithOsHooksObserver install_observer_with_os_hooks(
+      GetProfile(1));
   install_observer.BeginListening();
+  install_observer_with_os_hooks.BeginListening();
   // Install web app to profile 0 and wait for it to sync to profile 1.
   AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
-  EXPECT_EQ(install_observer.Wait(), app_id);
-
+  if (AreAppsLocallyInstalledBySync()) {
+    EXPECT_EQ(install_observer_with_os_hooks.Wait(), app_id);
+  } else {
+    EXPECT_EQ(install_observer.Wait(), app_id);
+  }
   WebAppProvider::GetForTest(GetProfile(1))
       ->sync_bridge()
       .SetAppUserDisplayMode(app_id, UserDisplayMode::kBrowser,
                              /*is_user_action=*/false);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(1),
-                                GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   // The change should have synced to profile 0.
   EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppUserDisplayMode(app_id),
@@ -339,7 +318,8 @@
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
                        MAYBE_DoubleInstallWithUninstall) {
   ASSERT_TRUE(SetupClients());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install web app to both profiles.
@@ -352,39 +332,37 @@
   // Uninstall the app from one of the profiles.
   UninstallWebApp(GetProfile(0), app_id);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
-                                GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // The apps should either be installed on both or uninstalled on both. This
   // fails, hence disabled test.
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NotSynced) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install a non-syncing web app.
   AppId app_id = InstallAppAsUserInitiated(
       GetProfile(0), webapps::WebappInstallSource::EXTERNAL_DEFAULT);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
-                                GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // Profile 0 should have an extra unsynced app, and it should not be in
   // profile 1.
-  EXPECT_FALSE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              Not(ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1)))));
   EXPECT_FALSE(GetRegistrar(GetProfile(1)).IsInstalled(app_id));
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NotSyncedThenSynced) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install a non-syncing web app.
@@ -395,13 +373,11 @@
   AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
   EXPECT_EQ(app_id, app_id2);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
-                                GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // The app is in both profiles.
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   // The app should have synced from profile 0 to profile 1, which enables sync
   // on profile 0. So changes should propagate from profile 0 to profile 1 now.
@@ -410,10 +386,7 @@
       .SetAppUserDisplayMode(app_id, UserDisplayMode::kBrowser,
                              /*is_user_action=*/false);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.seconddummy.org/"),
-                                GetProfile(0), GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // Check that profile 1 has the display mode change.
   EXPECT_EQ(GetRegistrar(GetProfile(1)).GetAppUserDisplayMode(app_id),
@@ -427,7 +400,8 @@
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
                        PolicyAppPersistsUninstalledOnSync) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install a non-syncing web app.
@@ -438,13 +412,11 @@
   AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
   EXPECT_EQ(app_id, app_id2);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(1),
-                                GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // The app is in both profiles.
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   const WebApp* app = GetRegistrar(GetProfile(0)).GetAppById(app_id);
   ASSERT_TRUE(app);
   EXPECT_TRUE(app->IsPolicyInstalledApp());
@@ -453,13 +425,11 @@
   // Uninstall the web app on the sync profile.
   UninstallWebApp(GetProfile(1), app_id);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.seconddummy.org/"),
-                                GetProfile(1), GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // The policy app should remain on profile 0.
-  EXPECT_FALSE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              Not(ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1)))));
   app = GetRegistrar(GetProfile(0)).GetAppById(app_id);
   ASSERT_TRUE(app);
   EXPECT_TRUE(app->IsPolicyInstalledApp());
@@ -468,7 +438,8 @@
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, AppSortingSynced) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
@@ -480,13 +451,11 @@
   GetAppSorting(GetProfile(0))->SetPageOrdinal(app_id, page_ordinal);
   GetAppSorting(GetProfile(0))->SetAppLaunchOrdinal(app_id, launch_ordinal);
 
-  // Install a 'dummy' app & wait for installation to ensure sync has processed
-  // the initial apps.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
-                                GetProfile(1));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // The app is in both profiles.
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   EXPECT_EQ(page_ordinal, GetAppSorting(GetProfile(1))->GetPageOrdinal(app_id));
   EXPECT_EQ(launch_ordinal,
             GetAppSorting(GetProfile(1))->GetAppLaunchOrdinal(app_id));
@@ -496,7 +465,8 @@
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
                        DISABLED_AppSortingFixCollisions) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install two different apps.
@@ -507,10 +477,10 @@
   ASSERT_NE(app_id1, app_id2);
 
   // Wait for both of the webapps to be installed on profile 1.
-  ASSERT_TRUE(AwaitQuiescence());
-  apps_helper::AwaitWebAppQuiescence({GetProfile(0), GetProfile(1)});
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 
   syncer::StringOrdinal page_ordinal =
       GetAppSorting(GetProfile(0))->CreateFirstAppPageOrdinal();
@@ -522,12 +492,7 @@
   GetAppSorting(GetProfile(1))->SetPageOrdinal(app_id2, page_ordinal);
   GetAppSorting(GetProfile(1))->SetAppLaunchOrdinal(app_id2, launch_ordinal);
 
-  // Install 'dummy' apps & wait for installation to ensure sync has processed
-  // the ordinals both ways.
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy1.org/"), GetProfile(0),
-                                GetProfile(1));
-  InstallDummyAppAndWaitForSync(GURL("http://www.dummy2.org/"), GetProfile(1),
-                                GetProfile(0));
+  ASSERT_TRUE(AwaitWebAppQuiescence());
 
   // Page & launch ordinals should be synced.
   EXPECT_EQ(GetAppSorting(GetProfile(0))->GetPageOrdinal(app_id1),
@@ -556,7 +521,8 @@
 #endif
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, MAYBE_UninstallSynced) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   AppId app_id;
@@ -566,7 +532,8 @@
     app_listener.BeginListening();
     InstallAppAsUserInitiated(GetProfile(0));
     app_id = app_listener.Wait();
-    EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+    EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+                ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   }
 
   // Uninstall the webapp on profile 0, and validate profile 1 gets the change.
@@ -575,7 +542,8 @@
     app_listener.BeginListening();
     UninstallWebApp(GetProfile(0), app_id);
     app_listener.Wait();
-    EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+    EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+                ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   }
 
   // Next, install on profile 1, uninstall on profile 0, and validate that
@@ -585,7 +553,8 @@
     app_listener.BeginListening();
     InstallAppAsUserInitiated(GetProfile(1));
     app_id = app_listener.Wait();
-    EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+    EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+                ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   }
   {
     WebAppTestUninstallObserver app_listener(GetProfile(1));
@@ -594,12 +563,14 @@
     app_listener.Wait();
   }
 
-  EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+  EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, UninstallDoesNotReinstall) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   AppId app_id;
@@ -609,7 +580,8 @@
     app_listener.BeginListening();
     InstallAppAsUserInitiated(GetProfile(0));
     app_id = app_listener.Wait();
-    EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+    EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+                ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   }
 
   // Uninstall the webapp on profile 0.
@@ -658,7 +630,8 @@
 
 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NoShortcutsCreatedOnSync) {
   ASSERT_TRUE(SetupSync());
-  ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
+  ASSERT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+              ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Install & uninstall on profile 0, and validate profile 1 sees it.
@@ -681,7 +654,8 @@
     app_listener.SetWebAppInstalledWithOsHooksDelegate(on_hooks_closure);
     InstallAppAsUserInitiated(GetProfile(0));
     loop.Run();
-    EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
+    EXPECT_THAT(GetAllAppIdsForProfile(GetProfile(0)),
+                ElementsAreArray(GetAllAppIdsForProfile(GetProfile(1))));
   }
   EXPECT_EQ(
       1u, GetOsIntegrationManager(GetProfile(0)).num_create_shortcuts_calls());
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.cc
index 5350ee64..2be4fa6 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_base.cc
@@ -51,15 +51,7 @@
 }
 
 void TwoClientWebAppsIntegrationTestBase::AwaitWebAppQuiescence() {
-  bool is_sync_on = true;
-  for (SyncServiceImplHarness* client : GetSyncClients()) {
-    is_sync_on = is_sync_on && client->service()->IsSyncFeatureActive();
-  }
-  // If sync is off, then `AwaitQuiescence()` will crash.
-  if (is_sync_on) {
-    ASSERT_TRUE(AwaitQuiescence());
-  }
-  apps_helper::AwaitWebAppQuiescence(GetAllProfiles());
+  ASSERT_TRUE(apps_helper::AwaitWebAppQuiescence(GetAllProfiles()));
 }
 
 void TwoClientWebAppsIntegrationTestBase::SetUp() {
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 1923e04..97aafaf 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -812,6 +812,22 @@
 class MultiScreenFullscreenControllerInteractiveTest
     : public FullscreenControllerInteractiveTest {
  public:
+  void SetUp() override {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    screen_.display_list().AddDisplay({1, gfx::Rect(100, 100, 801, 802)},
+                                      display::DisplayList::Type::PRIMARY);
+    display::Screen::SetScreenInstance(&screen_);
+#endif
+    FullscreenControllerInteractiveTest::SetUp();
+  }
+
+  void TearDown() override {
+    FullscreenControllerInteractiveTest::TearDown();
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    display::Screen::SetScreenInstance(nullptr);
+#endif
+  }
+
   // Perform common setup operations for multi-screen fullscreen testing:
   // Mock a screen with two displays, move the browser onto the first display,
   // and auto-grant the Window Placement permission on its active tab.
@@ -821,12 +837,8 @@
     display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
         .UpdateDisplay("0+0-800x800,800+0-800x800");
 #else
-    original_screen_ = display::Screen::GetScreen();
-    screen_.display_list().AddDisplay({1, gfx::Rect(0, 0, 800, 800)},
-                                      display::DisplayList::Type::PRIMARY);
     screen_.display_list().AddDisplay({2, gfx::Rect(800, 0, 800, 800)},
                                       display::DisplayList::Type::NOT_PRIMARY);
-    display::Screen::SetScreenInstance(&screen_);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     EXPECT_EQ(2, display::Screen::GetScreen()->GetNumDisplays());
 
@@ -849,14 +861,6 @@
     return tab;
   }
 
-  void TearDown() override {
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-    if (original_screen_)
-      display::Screen::SetScreenInstance(original_screen_);
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
-    FullscreenControllerInteractiveTest::TearDown();
-  }
-
   // Wait for a JS content fullscreen change with the given script and options.
   void RequestContentFullscreenFromScript(
       const std::string& eval_js_script,
@@ -930,14 +934,12 @@
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
   display::DisplayList& display_list() { return screen_.display_list(); }
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
-
  private:
   base::test::ScopedFeatureList feature_list_{
       blink::features::kWindowPlacement};
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-  raw_ptr<display::Screen> original_screen_ = nullptr;
   display::ScreenBase screen_;
-#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#endif
 };
 
 // TODO(crbug.com/1034772): Disabled on Windows, where views::FullscreenHandler
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
index e7b0a4d..a95ee61d 100644
--- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
+++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.cc
@@ -4,80 +4,144 @@
 
 #include "chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h"
 
+#include <vector>
+
 #include "base/containers/contains.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/notreached.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
+#include "chrome/browser/ui/tabs/tab_menu_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "content/public/browser/web_contents.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/accelerators/menu_label_accelerator_util.h"
 #include "ui/base/models/image_model.h"
+#include "ui/base/models/list_selection_model.h"
 #include "ui/color/color_provider.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
 
+namespace {
+constexpr int kIconSize = 14;
+}  // anonymous namespace
+
 ExistingTabGroupSubMenuModel::ExistingTabGroupSubMenuModel(
     ui::SimpleMenuModel::Delegate* parent_delegate,
+    TabMenuModelDelegate* tab_menu_model_delegate,
     TabStripModel* model,
     int context_index)
     : ExistingBaseSubMenuModel(parent_delegate,
                                model,
                                context_index,
                                kMinExistingTabGroupCommandId,
-                               TabStripModel::CommandAddToNewGroup) {
+                               TabStripModel::CommandAddToNewGroup),
+      tab_menu_model_delegate_(tab_menu_model_delegate) {
   DCHECK(model->SupportsTabGroups());
-  const ui::ColorProvider& color_provider =
-      model->GetWebContentsAt(context_index)->GetColorProvider();
-  constexpr int kIconSize = 14;
   std::vector<MenuItemInfo> menu_item_infos;
 
-  std::vector<tab_groups::TabGroupId> ordered_tab_groups =
-      GetOrderedTabGroupsInSubMenu();
-  for (size_t i = 0; i < ordered_tab_groups.size(); ++i) {
-    tab_groups::TabGroupId group = ordered_tab_groups[i];
-    const TabGroup* tab_group = model->group_model()->GetTabGroup(group);
-    const std::u16string group_title = tab_group->visual_data()->title();
-    const std::u16string displayed_title =
-        group_title.empty() ? tab_group->GetContentString() : group_title;
-    const int color_id =
-        GetTabGroupContextMenuColorId(tab_group->visual_data()->color());
-    ui::ImageModel image_model = ui::ImageModel::FromVectorIcon(
-        kTabGroupIcon, color_provider.GetColor(color_id), kIconSize);
-    menu_item_infos.emplace_back(MenuItemInfo{displayed_title, image_model});
-    menu_item_infos.back().may_have_mnemonics = false;
-
-    menu_item_infos.back().target_index = static_cast<int>(i);
-    target_index_to_group_mapping_.emplace(i, group);
+  menu_item_infos = GetMenuItemsFromModel(model);
+  std::vector<tab_groups::TabGroupId> groups = GetGroupsFromModel(model);
+  // TODO(dljames): Consider moving CHECK + loop into a separate private
+  // function that updates both `menu_item_infos` and
+  // `target_index_to_group_mapping_`.
+  CHECK_EQ(menu_item_infos.size(), groups.size());
+  for (const auto& group : groups) {
+    int index = target_index_to_group_mapping_.size();
+    menu_item_infos[index].target_index = index;
+    target_index_to_group_mapping_.emplace(index, group);
   }
+
+  // For each window, append the tab groups to the end of the menu items.
+  if (tab_menu_model_delegate_) {
+    // TODO(dljames): Rename GetExistingWindowsForMoveMenu to something generic
+    // since this function is now used for 'Move tab to window' and 'Add tab to
+    // group'
+    for (Browser* browser :
+         tab_menu_model_delegate_->GetExistingWindowsForMoveMenu()) {
+      if (browser->tab_strip_model() == model)
+        continue;
+      const std::vector<MenuItemInfo> retrieved_menu_item_infos =
+          GetMenuItemsFromModel(browser->tab_strip_model());
+      menu_item_infos.insert(menu_item_infos.end(),
+                             retrieved_menu_item_infos.begin(),
+                             retrieved_menu_item_infos.end());
+      groups = GetGroupsFromModel(browser->tab_strip_model());
+      CHECK_EQ(menu_item_infos.size(),
+               groups.size() + target_index_to_group_mapping_.size());
+      for (const auto& group : groups) {
+        int index = target_index_to_group_mapping_.size();
+        menu_item_infos[index].target_index = index;
+        target_index_to_group_mapping_.emplace(index, group);
+      }
+    }
+  }
+
   Build(IDS_TAB_CXMENU_SUBMENU_NEW_GROUP, menu_item_infos);
 }
 
 ExistingTabGroupSubMenuModel::~ExistingTabGroupSubMenuModel() = default;
 
-std::vector<tab_groups::TabGroupId>
-ExistingTabGroupSubMenuModel::GetOrderedTabGroupsInSubMenu() {
-  std::vector<tab_groups::TabGroupId> ordered_groups;
-  absl::optional<tab_groups::TabGroupId> current_group = absl::nullopt;
-  for (int i = 0; i < model()->count(); ++i) {
-    absl::optional<tab_groups::TabGroupId> new_group =
-        model()->GetTabGroupForTab(i);
-    if (new_group.has_value() && new_group != current_group &&
-        ShouldShowGroup(model(), GetContextIndex(), new_group.value())) {
-      ordered_groups.push_back(new_group.value());
+const std::vector<tab_groups::TabGroupId>
+ExistingTabGroupSubMenuModel::GetGroupsFromModel(TabStripModel* current_model) {
+  // No model, no group model, no service.
+  if (!current_model || !current_model->group_model())
+    return {};
+
+  // Add tab groups to `groups` if they differ from our indexes current group.
+  std::vector<tab_groups::TabGroupId> groups;
+  for (auto& group : current_model->group_model()->ListTabGroups()) {
+    if (model() == current_model &&
+        model()->GetTabGroupForTab(GetContextIndex()).has_value() &&
+        model()->GetTabGroupForTab(GetContextIndex()).value() == group) {
+      continue;
     }
-    current_group = new_group;
+
+    groups.push_back(group);
   }
-  return ordered_groups;
+
+  return groups;
+}
+
+const std::vector<ExistingTabGroupSubMenuModel::MenuItemInfo>
+ExistingTabGroupSubMenuModel::GetMenuItemsFromModel(
+    TabStripModel* current_model) {
+  const std::vector<tab_groups::TabGroupId> groups =
+      GetGroupsFromModel(current_model);
+  std::vector<MenuItemInfo> menu_item_infos;
+
+  for (const auto& group : groups) {
+    const TabGroup* tab_group =
+        current_model->group_model()->GetTabGroup(group);
+    const std::u16string group_title = tab_group->visual_data()->title();
+    // TODO(dljames): Add method to tab_group.cc to return displayed_title.
+    // TODO(dljames): Add unit tests for all of tab_group.h
+    const std::u16string displayed_title =
+        group_title.empty() ? tab_group->GetContentString() : group_title;
+    const int color_id =
+        GetTabGroupContextMenuColorId(tab_group->visual_data()->color());
+    const ui::ColorProvider& color_provider =
+        model()->GetWebContentsAt(GetContextIndex())->GetColorProvider();
+    ui::ImageModel image_model = ui::ImageModel::FromVectorIcon(
+        kTabGroupIcon, color_provider.GetColor(color_id), kIconSize);
+
+    menu_item_infos.emplace_back(MenuItemInfo{displayed_title, image_model});
+    menu_item_infos.back().may_have_mnemonics = false;
+  }
+
+  return menu_item_infos;
 }
 
 // static
@@ -101,25 +165,75 @@
 }
 
 void ExistingTabGroupSubMenuModel::ExecuteExistingCommand(int target_index) {
+  DCHECK_LE(size_t(target_index), target_index_to_group_mapping_.size());
   TabGroupModel* group_model = model()->group_model();
   if (!group_model)
     return;
 
   base::RecordAction(base::UserMetricsAction("TabContextMenu_NewTabInGroup"));
 
-  if (static_cast<size_t>(target_index) >= group_model->ListTabGroups().size())
+  tab_groups::TabGroupId group =
+      target_index_to_group_mapping_.at(target_index);
+
+  if (group_model->ContainsTabGroup(group)) {
+    model()->ExecuteAddToExistingGroupCommand(GetContextIndex(), group);
+    return;
+  }
+
+  int browser_index = -1;
+  std::vector<Browser*> browsers =
+      tab_menu_model_delegate_->GetExistingWindowsForMoveMenu();
+  for (size_t i = 0; i < browsers.size(); ++i) {
+    TabStripModel* potential_model = browsers[i]->tab_strip_model();
+    if (potential_model && potential_model != model() &&
+        potential_model->group_model()->ContainsTabGroup(group)) {
+      browser_index = i;
+      break;
+    }
+  }
+
+  if (browser_index < 0)
     return;
 
-  if (!model()->ContainsIndex(GetContextIndex()))
-    return;
+  std::vector<int> selected_indices;
+  if (!model()->IsTabSelected(GetContextIndex())) {
+    selected_indices = {GetContextIndex()};
+  } else {
+    const ui::ListSelectionModel::SelectedIndices selection_indices =
+        model()->selection_model().selected_indices();
+    selected_indices =
+        std::vector<int>(selection_indices.begin(), selection_indices.end());
+  }
+  TabStripModel* found_model = browsers[browser_index]->tab_strip_model();
+  std::vector<int> selected_indices_in_found_model;
+  const ui::ListSelectionModel::SelectedIndices selection_indices =
+      found_model->selection_model().selected_indices();
+  selected_indices_in_found_model =
+      std::vector<int>(selection_indices.begin(), selection_indices.end());
 
-  if (!base::Contains(target_index_to_group_mapping_, target_index) ||
-      !model()->group_model()->ContainsTabGroup(
-          target_index_to_group_mapping_.at(target_index)))
-    return;
+  // At the time this was written, all tabs moved to a new window via
+  // MoveToExistingWindow() are placed at the end of the tabstrip, and any
+  // previously selected tabs in the new window are unselected.
+  model()->delegate()->MoveToExistingWindow(selected_indices, browser_index);
 
-  model()->ExecuteAddToExistingGroupCommand(
-      GetContextIndex(), target_index_to_group_mapping_.at(target_index));
+  // DCHECK that previously selected indices in the new model are now
+  // unselected.
+  for (int index : selected_indices_in_found_model)
+    DCHECK(!found_model->IsTabSelected(index));
+
+  // Ensure that the selected_indices maintain selection in the new window.
+  // Our indices to consider are guaranteed to be at the end of the tabstrip.
+  for (size_t count = 0; count < selected_indices.size(); ++count) {
+    int tab = found_model->count() - 1 - count;
+    if (!found_model->IsTabSelected(tab))
+      found_model->ToggleSelectionAt(tab);
+  }
+
+  // Move all selected tabs into `group`. Note, we can choose any tab that is
+  // currently selected. For consistency we choose the last tab since we know
+  // where it is.
+  found_model->ExecuteAddToExistingGroupCommand(found_model->count() - 1,
+                                                group);
 }
 
 // static
@@ -139,3 +253,8 @@
   }
   return false;
 }
+
+void ExistingTabGroupSubMenuModel::ExecuteExistingCommandForTesting(
+    int target_index) {
+  ExecuteExistingCommand(target_index);
+}
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h
index 6ffe079..9fa71cd 100644
--- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h
+++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h
@@ -6,10 +6,12 @@
 #define CHROME_BROWSER_UI_TABS_EXISTING_TAB_GROUP_SUB_MENU_MODEL_H_
 
 #include <stddef.h>
+#include <vector>
 
 #include "chrome/browser/ui/tabs/existing_base_sub_menu_model.h"
 
 class TabStripModel;
+class TabMenuModelDelegate;
 
 namespace tab_groups {
 class TabGroupId;
@@ -18,6 +20,7 @@
 class ExistingTabGroupSubMenuModel : public ExistingBaseSubMenuModel {
  public:
   ExistingTabGroupSubMenuModel(ui::SimpleMenuModel::Delegate* parent_delegate,
+                               TabMenuModelDelegate* tab_menu_model_delegate,
                                TabStripModel* model,
                                int context_index);
   ExistingTabGroupSubMenuModel(const ExistingTabGroupSubMenuModel&) = delete;
@@ -33,16 +36,20 @@
   // ExistingBaseSubMenuModel:
   std::u16string GetLabelAt(int index) const override;
 
+  // Used for testing.
+  void ExecuteExistingCommandForTesting(int target_index);
+
  private:
   // ExistingBaseSubMenuModel
   void ExecuteExistingCommand(int target_index) override;
 
-  // Returns the group ids that appear in the submenu in the order that they
-  // appear in the tab strip model, so that the user sees an ordered display.
-  // Only needed for creating items and executing commands, which must be in
-  // order. Otherwise, ListTabGroups() is cheaper and sufficient for determining
-  // visibility and size of the menu.
-  std::vector<tab_groups::TabGroupId> GetOrderedTabGroupsInSubMenu();
+  // Retrieves all tab groups ids from the given model.
+  const std::vector<tab_groups::TabGroupId> GetGroupsFromModel(
+      TabStripModel* current_model);
+
+  // Retrieves all menu items from the given model.
+  const std::vector<MenuItemInfo> GetMenuItemsFromModel(
+      TabStripModel* current_model);
 
   // Whether the submenu should contain the group |group|. True iff at least
   // one tab that would be affected by the command is not in |group|.
@@ -50,11 +57,14 @@
                               int context_index,
                               tab_groups::TabGroupId group);
 
-  // mapping of the initial tab group to index in the menu model. this must
+  // Mapping of the initial tab group to index in the menu model. this must
   // be used in cases where the tab groups returned from
   // GetOrderedTabGroupsInSubMenu changes after the menu has been opened but
   // before the action is taken from the menumodel.
   std::map<int, tab_groups::TabGroupId> target_index_to_group_mapping_;
+
+  // Used to retrieve a list of browsers which potentially hold tab groups.
+  const raw_ptr<TabMenuModelDelegate> tab_menu_model_delegate_;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_EXISTING_TAB_GROUP_SUB_MENU_MODEL_H_
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc
index ecb2bf76..07db517 100644
--- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc
@@ -3,17 +3,20 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/tabs/existing_tab_group_sub_menu_model.h"
+#include <memory>
 
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_tab_menu_model_delegate.h"
+#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/tab_groups/tab_group_id.h"
 #include "url/gurl.h"
 
-namespace {
-
 class ExistingTabGroupSubMenuModelTest : public BrowserWithTestWindowTest {
  public:
-  ExistingTabGroupSubMenuModelTest() : BrowserWithTestWindowTest() {}
+  ExistingTabGroupSubMenuModelTest() = default;
 };
 
 // Ensure that add to group submenu only appears when there is another group to
@@ -49,14 +52,138 @@
   ASSERT_FALSE(model->GetTabGroupForTab(2).has_value());
   ASSERT_EQ(model->count(), 3);
 
-  ExistingTabGroupSubMenuModel menu1(nullptr, model, 0);
+  ExistingTabGroupSubMenuModel menu1(nullptr, nullptr, model, 0);
   EXPECT_EQ(3, menu1.GetItemCount());
 
-  ExistingTabGroupSubMenuModel menu2(nullptr, model, 1);
+  ExistingTabGroupSubMenuModel menu2(nullptr, nullptr, model, 1);
   EXPECT_EQ(3, menu2.GetItemCount());
 
-  ExistingTabGroupSubMenuModel menu3(nullptr, model, 2);
+  ExistingTabGroupSubMenuModel menu3(nullptr, nullptr, model, 2);
   EXPECT_EQ(4, menu3.GetItemCount());
 }
 
-}  // namespace
+// Verify tabs can be added tab groups in the same window.
+TEST_F(ExistingTabGroupSubMenuModelTest, AddTabsToGroupSameWindow) {
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+
+  TabStripModel* model = browser()->tab_strip_model();
+  model->AddToNewGroup({0});
+  model->AddToNewGroup({1});
+  ExistingTabGroupSubMenuModel menu(nullptr, nullptr, model, 2);
+  EXPECT_EQ(4, menu.GetItemCount());
+
+  // Move the tab at index 2 into the group with the tab at index 0.
+  menu.ExecuteExistingCommandForTesting(0);
+
+  ASSERT_EQ(size_t(2), model->group_model()->ListTabGroups().size());
+  EXPECT_EQ(2, model->group_model()
+                   ->GetTabGroup(model->group_model()->ListTabGroups()[0])
+                   ->tab_count());
+
+  ExistingTabGroupSubMenuModel menu2(nullptr, nullptr, model, 2);
+  EXPECT_EQ(3, menu2.GetItemCount());
+}
+
+// Verify non-selected tabs can be added tab groups in the same window.
+TEST_F(ExistingTabGroupSubMenuModelTest, AddNonSelectedTabsToTabGroup) {
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+
+  TabStripModel* model = browser()->tab_strip_model();
+  model->AddToNewGroup({0});
+  model->AddToNewGroup({1});
+
+  // Select the tab at index 2.
+  model->ToggleSelectionAt(2);
+
+  // Create the menu on the tab at index 3.
+  ExistingTabGroupSubMenuModel menu(nullptr, nullptr, model, 3);
+  EXPECT_EQ(4, menu.GetItemCount());
+
+  // Move the tab at index 2 into the group with the tab at index 0.
+  menu.ExecuteExistingCommandForTesting(0);
+
+  ASSERT_EQ(size_t(2), model->group_model()->ListTabGroups().size());
+  EXPECT_EQ(2, model->group_model()
+                   ->GetTabGroup(model->group_model()->ListTabGroups()[0])
+                   ->tab_count());
+
+  ExistingTabGroupSubMenuModel menu2(nullptr, nullptr, model, 2);
+  ExistingTabGroupSubMenuModel menu3(nullptr, nullptr, model, 3);
+
+  EXPECT_EQ(3, menu2.GetItemCount());
+  EXPECT_EQ(4, menu3.GetItemCount());
+}
+
+// Verify tabs can be added to tab groups in other browser windows.
+TEST_F(ExistingTabGroupSubMenuModelTest, AddAllSelectedTabsToAnotherWindow) {
+  std::unique_ptr<BrowserWindow> window_1 = CreateBrowserWindow();
+  std::unique_ptr<Browser> new_browser = CreateBrowser(
+      browser()->profile(), browser()->type(), false, window_1.get());
+
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+  AddTab(browser(), GURL("chrome://newtab"));
+
+  AddTab(new_browser.get(), GURL("chrome://newtab"));
+  AddTab(new_browser.get(), GURL("chrome://newtab"));
+  AddTab(new_browser.get(), GURL("chrome://newtab"));
+  AddTab(new_browser.get(), GURL("chrome://newtab"));
+
+  TabStripModel* model_1 = new_browser->tab_strip_model();
+  TabStripModel* model_2 = browser()->tab_strip_model();
+
+  EXPECT_EQ(model_1->count(), 4);
+  EXPECT_EQ(model_1->count(), 4);
+
+  std::unique_ptr<TabMenuModelDelegate> delegate_1 =
+      std::make_unique<chrome::BrowserTabMenuModelDelegate>(new_browser.get());
+
+  // First tabs of each model consists of a tab group.
+  model_1->AddToNewGroup({0});
+  model_2->AddToNewGroup({0});
+
+  ExistingTabGroupSubMenuModel menu_1(nullptr, delegate_1.get(), model_1, 1);
+
+  // In order to move the 3 un-grouped tabs in `model_1` we must select those
+  // tabs in addition to unselecting the grouped tab. We do this in reverse
+  // order since at this point the only tab that is selected is the grouped tab.
+  // We are unable to deselect this tab first. Doing so creates a state where no
+  // tabs are selected which is not allowed.
+  for (int i = model_1->count() - 1; i >= 0; --i)
+    model_1->ToggleSelectionAt(i);
+
+  const ui::ListSelectionModel::SelectedIndices selection_indices =
+      model_1->selection_model().selected_indices();
+  std::vector<int> selected_indices =
+      std::vector<int>(selection_indices.begin(), selection_indices.end());
+  EXPECT_EQ(selected_indices.size(), size_t(3));
+  EXPECT_EQ(4, menu_1.GetItemCount());
+
+  // Move the 3 selected indices in model_1 to model_2.
+  menu_1.ExecuteExistingCommandForTesting(1);
+  EXPECT_EQ(model_2->count(), 7);
+
+  // Verify the tab group in model_2 now has 4 tabs in it.
+  TabGroup* group = model_2->group_model()->GetTabGroup(
+      model_2->GetTabGroupForTab(0).value());
+  EXPECT_EQ(group->tab_count(), 4);
+
+  int num_selected = 0;
+
+  for (int i = 0; i < model_2->count(); ++i) {
+    if (model_2->IsTabSelected(i))
+      ++num_selected;
+  }
+
+  // Expect the number of tabs we moved from model_1 into model_2 is still 3.
+  EXPECT_EQ(num_selected, 3);
+
+  new_browser.get()->tab_strip_model()->CloseAllTabs();
+  new_browser.reset();
+}
diff --git a/chrome/browser/ui/tabs/tab_menu_model.cc b/chrome/browser/ui/tabs/tab_menu_model.cc
index 8b70098..dc8b4891 100644
--- a/chrome/browser/ui/tabs/tab_menu_model.cc
+++ b/chrome/browser/ui/tabs/tab_menu_model.cc
@@ -35,7 +35,7 @@
   Build(tab_strip, index);
 }
 
-TabMenuModel::~TabMenuModel() {}
+TabMenuModel::~TabMenuModel() = default;
 
 void TabMenuModel::Build(TabStripModel* tab_strip, int index) {
   std::vector<int> indices;
@@ -61,8 +61,8 @@
   if (ExistingTabGroupSubMenuModel::ShouldShowSubmenu(tab_strip, index)) {
     // Create submenu with existing groups
     add_to_existing_group_submenu_ =
-        std::make_unique<ExistingTabGroupSubMenuModel>(delegate(), tab_strip,
-                                                       index);
+        std::make_unique<ExistingTabGroupSubMenuModel>(
+            delegate(), tab_menu_model_delegate_, tab_strip, index);
     AddSubMenu(TabStripModel::CommandAddToExistingGroup,
                l10n_util::GetPluralStringFUTF16(IDS_TAB_CXMENU_ADD_TAB_TO_GROUP,
                                                 num_tabs),
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
index 2ab3e82..4f6c28fc 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
@@ -25,6 +25,10 @@
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(USE_AURA)
+#include "ui/aura/env.h"
+#endif
+
 namespace {
 
 // An arbitrary index for the result view under test. Used to test the selection
@@ -59,18 +63,16 @@
 class OmniboxResultViewTest : public ChromeViewsTestBase {
  public:
   void SetUp() override {
-    ChromeViewsTestBase::SetUp();
-
-    // Create a widget and assign bounds to support calls to HitTestPoint.
-    widget_ = CreateTestWidget();
-
-    // Install |test_screen_| after superclass setup and widget creation; on Ash
-    // both these require the Screen to work well with the underlying Shell, and
-    // TestScreen has no knowledge of that.
+#if !defined(USE_AURA)
     test_screen_ = std::make_unique<display::test::TestScreen>();
     scoped_screen_override_ =
         std::make_unique<display::test::ScopedScreenOverride>(
             test_screen_.get());
+#endif
+    ChromeViewsTestBase::SetUp();
+
+    // Create a widget and assign bounds to support calls to HitTestPoint.
+    widget_ = CreateTestWidget();
 
     edit_model_ = std::make_unique<OmniboxEditModel>(
         nullptr, nullptr, std::make_unique<TestOmniboxClient>());
@@ -89,10 +91,10 @@
   }
 
   void TearDown() override {
-    scoped_screen_override_.reset();
-    test_screen_.reset();
     widget_.reset();
     ChromeViewsTestBase::TearDown();
+    scoped_screen_override_.reset();
+    test_screen_.reset();
   }
 
   // Also sets the fake screen's mouse cursor to 0, 0.
@@ -105,7 +107,11 @@
                                 int flags,
                                 float x,
                                 float y) {
+#if !defined(USE_AURA)
     test_screen_->set_cursor_screen_point(gfx::Point(x, y));
+#else
+    aura::Env::GetInstance()->SetLastMouseLocation(gfx::Point(x, y));
+#endif
     return ui::MouseEvent(type, gfx::Point(x, y), gfx::Point(),
                           ui::EventTimeForNow(), flags, 0);
   }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index fa43f05..5612da6 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -640,7 +640,8 @@
         did_restore_window_ = true;
         // When all tabs in a maximized browser are dragged the browser gets
         // restored during the drag and maximized back when the drag ends.
-        const int tab_area_width = attached_context_->GetTabDragAreaWidth();
+        const int previous_tab_area_width =
+            attached_context_->GetTabDragAreaWidth();
         std::vector<gfx::Rect> drag_bounds =
             attached_context_->CalculateBoundsForDraggedViews(attached_views_);
         OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds);
@@ -653,8 +654,9 @@
         widget->Restore();
         widget->SetBounds(new_bounds);
         drag_offset = GetWindowOffset(point_in_screen);
-        AdjustBrowserAndTabBoundsForDrag(tab_area_width, point_in_screen,
-                                         &drag_offset, &drag_bounds);
+        AdjustBrowserAndTabBoundsForDrag(previous_tab_area_width,
+                                         point_in_screen, &drag_offset,
+                                         &drag_bounds);
         widget->SetVisibilityChangedAnimationsEnabled(true);
       } else {
         new_bounds =
@@ -1477,7 +1479,7 @@
     return;
   }
 
-  const int tab_area_width = attached_context_->GetTabDragAreaWidth();
+  const int previous_tab_area_width = attached_context_->GetTabDragAreaWidth();
   std::vector<gfx::Rect> drag_bounds =
       attached_context_->CalculateBoundsForDraggedViews(attached_views_);
   OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds);
@@ -1517,7 +1519,7 @@
   DetachAndAttachToNewContext(
       release_capture, dragged_browser_view->tabstrip()->GetDragContext(),
       gfx::Point());
-  AdjustBrowserAndTabBoundsForDrag(tab_area_width, point_in_screen,
+  AdjustBrowserAndTabBoundsForDrag(previous_tab_area_width, point_in_screen,
                                    &drag_offset, &drag_bounds);
   browser->window()->Show();
   dragged_widget->SetVisibilityChangedAnimationsEnabled(true);
@@ -1977,8 +1979,7 @@
       }
 
       // If source window was maximized - maximize the new window as well.
-#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX) && \
-    !BUILDFLAG(IS_CHROMEOS_LACROS) && !BUILDFLAG(IS_MAC)
+#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_MAC)
       // Keeping maximized state breaks snap to Grid on Windows when dragging
       // tabs from maximized windows. TODO:(crbug.com/727051) Explore doing this
       // for other desktop OS's. kMaximizedStateRetainedOnTabDrag in
@@ -1987,13 +1988,9 @@
       // macOS opts out since this maps maximize to fullscreen, which can
       // violate user expectations and interacts poorly with some window
       // management actions.
-      //
-      // TODO(https://crbug.com/1252941): Remove the lacros if-clause above when
-      // lacros understands the snapped window state types (eg
-      // chromeos::WindowStateType::kPrimarySnapped|kSecondarySnapped).
       if (was_source_maximized_ || was_source_fullscreen_)
         MaximizeAttachedWindow();
-#endif  // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX)
+#endif  // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_MAC)
     }
     attached_context_->StoppedDragging(
         GetViewsMatchingDraggedContents(attached_context_),
@@ -2226,51 +2223,54 @@
 }
 
 void TabDragController::AdjustBrowserAndTabBoundsForDrag(
-    int tab_area_width,
+    int previous_tab_area_width,
     const gfx::Point& point_in_screen,
     gfx::Vector2d* drag_offset,
     std::vector<gfx::Rect>* drag_bounds) {
   attached_context_->ForceLayout();
-  const int dragged_context_width = attached_context_->GetTabDragAreaWidth();
+  const int current_tab_area_width = attached_context_->GetTabDragAreaWidth();
 
-  // If the new tabstrip region is smaller than the old, resize the tabs.
-  if (dragged_context_width < tab_area_width) {
+  // If the new tabstrip region is smaller than the old, resize and reposition
+  // the tabs to provide a sense of continuity.
+  if (current_tab_area_width < previous_tab_area_width) {
     // TODO(https://crbug.com/1324577): Fix the case where the source window
     // spans two monitors horizontally, and IsRTL is true.
+
+    // `leading_ratio` is the proportion of the previous tab area width which is
+    // ahead of the first dragged tab's previous position.
     const float leading_ratio =
-        drag_bounds->front().x() / static_cast<float>(tab_area_width);
+        drag_bounds->front().x() / static_cast<float>(previous_tab_area_width);
     *drag_bounds =
         attached_context_->CalculateBoundsForDraggedViews(attached_views_);
 
-    if (drag_bounds->back().right() < dragged_context_width) {
-      const int delta_x = std::min(
-          static_cast<int>(leading_ratio * dragged_context_width),
-          dragged_context_width -
-              (drag_bounds->back().right() - drag_bounds->front().x()));
-      OffsetX(delta_x, drag_bounds);
+    // If the tabs can fit within the new tab area with room to spare, align
+    // them within it so the leading tab is in the same position as it was in
+    // the previous tab area, proportionally speaking.
+    if (drag_bounds->back().right() < current_tab_area_width) {
+      // The tabs must stay within the tabstrip.
+      const int maximum_tab_x =
+          current_tab_area_width -
+          (drag_bounds->back().right() - drag_bounds->front().x());
+      const int leading_tab_x =
+          std::min(static_cast<int>(leading_ratio * current_tab_area_width),
+                   maximum_tab_x);
+      OffsetX(leading_tab_x, drag_bounds);
     }
 
     // Reposition the restored window such that the tab that was dragged remains
     // under the mouse cursor.
-    gfx::Rect tab_bounds = (*drag_bounds)[source_view_index_];
-    int tab_bounds_x = tab_bounds.x();
-    if (source_context_) {
-      tab_bounds_x =
-          source_context_->AsView()->GetMirroredXInView(tab_bounds.x());
-    }
-    // `source_context_` can be null, e.g., if you drag the only tab in a window
-    // into another window's tab strip and then back out, in one continuous
-    // drag.
-    if (!source_context_ && base::i18n::IsRTL())
-      tab_bounds_x = tab_area_width - tab_bounds.x();
+    gfx::Rect source_tab_bounds = (*drag_bounds)[source_view_index_];
 
-    int tab_width_offset =
-        base::ClampRound(tab_bounds.width() * offset_to_width_ratio_);
-    gfx::Point offset(
-        base::i18n::IsRTL() ? tab_bounds_x : tab_bounds_x + tab_width_offset,
+    int cursor_offset_within_tab =
+        base::ClampRound(source_tab_bounds.width() * offset_to_width_ratio_);
+    gfx::Point cursor_offset_in_widget(
+        attached_context_->AsView()->GetMirroredXInView(
+            source_tab_bounds.x() + cursor_offset_within_tab),
         0);
+    attached_context_->AsView()->ConvertPointToWidget(
+        attached_context_->AsView(), &cursor_offset_in_widget);
     gfx::Rect bounds = GetAttachedBrowserWidget()->GetWindowBoundsInScreen();
-    bounds.set_x(point_in_screen.x() - offset.x());
+    bounds.set_x(point_in_screen.x() - cursor_offset_in_widget.x());
     GetAttachedBrowserWidget()->SetBounds(bounds);
     *drag_offset = point_in_screen - bounds.origin();
   }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index 393d23f..afa14715 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -491,15 +491,15 @@
       views::Widget* widget,
       const gfx::Point& point_in_screen);
 
-  // Calculates scaled |drag_bounds| for dragged tabs and sets the tabs bounds.
+  // Calculates scaled `drag_bounds` for dragged tabs and sets the tabs bounds.
   // Layout of the tabstrip is performed and a new tabstrip width calculated.
-  // When |last_tabstrip_width| is larger than the new tabstrip width the tabs
-  // in the attached tabstrip are scaled and the attached browser is positioned
-  // such that the tab that was dragged remains under the |point_in_screen|.
-  // |drag_offset| is the offset of |point_in_screen| from the origin of the
-  // dragging browser window, and will be updated when this method ends up with
-  // changing the origin of the attached browser window.
-  void AdjustBrowserAndTabBoundsForDrag(int last_tabstrip_width,
+  // When `previous_tab_area_width` is larger than the new tab area width the
+  // tabs in the attached tabstrip are scaled and repositioned and the attached
+  // browser is positioned such that the tab that was dragged remains under the
+  // `point_in_screen`. `drag_offset` is the offset of `point_in_screen` from
+  // the origin of the dragging browser window, and will be updated when this
+  // method ends up with changing the origin of the attached browser window.
+  void AdjustBrowserAndTabBoundsForDrag(int previous_tab_area_width,
                                         const gfx::Point& point_in_screen,
                                         gfx::Vector2d* drag_offset,
                                         std::vector<gfx::Rect>* drag_bounds);
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 7dd3710b..6dac3aa2 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1799,7 +1799,7 @@
       new_browser->window()->GetNativeWindow()));
 
   const bool kMaximizedStateRetainedOnTabDrag =
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
       false;
 #else
       true;
diff --git a/chrome/browser/ui/views/test/view_event_test_base.cc b/chrome/browser/ui/views/test/view_event_test_base.cc
index 54c917a..fed341ee 100644
--- a/chrome/browser/ui/views/test/view_event_test_base.cc
+++ b/chrome/browser/ui/views/test/view_event_test_base.cc
@@ -14,13 +14,13 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "mojo/core/embedder/embedder.h"
+#include "ui/display/screen.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
 #if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ui/display/screen.h"
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
 
 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_OZONE)
@@ -98,13 +98,12 @@
   // TODO(pkasting): Determine why the TestScreen in AuraTestHelper is
   // insufficient for these tests, then either bolster/replace it or fix the
   // tests.
-  DCHECK(!display::Screen::GetScreen());
+  DCHECK(!display::Screen::HasScreen());
 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_OZONE)
-  if (!display::Screen::GetScreen())
-    display::Screen::SetScreenInstance(
-        views::test::TestDesktopScreenOzone::GetInstance());
+  if (!display::Screen::HasScreen())
+    screen_ = views::test::TestDesktopScreenOzone::Create();
 #endif
-  if (!display::Screen::GetScreen())
+  if (!display::Screen::HasScreen())
     screen_ = views::CreateDesktopScreen();
 #endif
 }
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index 12edced..c296f40 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -70,11 +70,11 @@
   return source;
 }
 
-void SetIfNotNull(base::DictionaryValue* dict,
+void SetIfNotNull(base::Value::Dict& dict,
                   const base::StringPiece& path,
                   std::unique_ptr<base::Value> in_value) {
   if (in_value) {
-    dict->Set(path, std::move(in_value));
+    dict.Set(path, base::Value::FromUniquePtrValue(std::move(in_value)));
   }
 }
 
@@ -173,7 +173,7 @@
   if (select_file_dialog_)
     select_file_dialog_->ListenerDestroyed();
 
-  file_writer_->StopNetLog(nullptr);
+  file_writer_->StopNetLog();
 }
 
 void NetExportMessageHandler::RegisterMessages() {
@@ -248,16 +248,15 @@
 void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::unique_ptr<base::DictionaryValue> ui_thread_polled_data(
-      new base::DictionaryValue());
+  base::Value::Dict ui_thread_polled_data;
 
   Profile* profile = Profile::FromWebUI(web_ui());
-  SetIfNotNull(ui_thread_polled_data.get(), "prerenderInfo",
+  SetIfNotNull(ui_thread_polled_data, "prerenderInfo",
                chrome_browser_net::GetPrerenderInfo(profile));
-  SetIfNotNull(ui_thread_polled_data.get(), "extensionInfo",
+  SetIfNotNull(ui_thread_polled_data, "extensionInfo",
                chrome_browser_net::GetExtensionInfo(profile));
 #if BUILDFLAG(IS_WIN)
-  SetIfNotNull(ui_thread_polled_data.get(), "serviceProviders",
+  SetIfNotNull(ui_thread_polled_data, "serviceProviders",
                chrome_browser_net::GetWindowsServiceProviders());
 #endif
 
diff --git a/chrome/browser/ui/window_sizer/DEPS b/chrome/browser/ui/window_sizer/DEPS
index 046d8fd0..ea16c4459 100644
--- a/chrome/browser/ui/window_sizer/DEPS
+++ b/chrome/browser/ui/window_sizer/DEPS
@@ -1,6 +1,5 @@
 specific_include_rules = {
-  ".*test.*": [
-   "!ash",
-   "+ash/public",
+  ".*chromeos.*test.*": [
+   "+ash",
   ],
 }
diff --git a/chrome/browser/ui/window_sizer/window_sizer_chromeos_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_chromeos_unittest.cc
index a29e51a..90696be 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_chromeos_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_chromeos_unittest.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/window_sizer/window_sizer_chromeos.h"
 
 #include "ash/public/cpp/window_properties.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
@@ -45,16 +47,30 @@
   void GetWindowBounds(const Browser* browser,
                        const gfx::Rect& passed_in,
                        int64_t display_id,
+                       const gfx::Rect& bounds,
+                       const gfx::Rect& work_area,
+                       Source source,
                        gfx::Rect* out_bounds) {
     auto state_provider = std::make_unique<TestStateProvider>();
-    state_provider->SetPersistentState(gfx::Rect(), gfx::Rect(),
-                                       ui::SHOW_STATE_DEFAULT);
+    if (source == PERSISTED) {
+      state_provider->SetPersistentState(bounds, work_area,
+                                         ui::SHOW_STATE_DEFAULT);
+    } else {
+      DCHECK_EQ(source, DEFAULT);
+    }
     display::Screen::GetScreen()->SetDisplayForNewWindows(display_id);
 
     ui::WindowShowState ignored;
     WindowSizer::GetBrowserWindowBoundsAndShowState(
         std::move(state_provider), passed_in, browser, out_bounds, &ignored);
   }
+  void GetWindowBounds(const Browser* browser,
+                       const gfx::Rect& passed_in,
+                       int64_t display_id,
+                       gfx::Rect* out_bounds = nullptr) {
+    GetWindowBounds(browser, passed_in, display_id, gfx::Rect(), gfx::Rect(),
+                    PERSISTED, out_bounds);
+  }
 
   // Returns browser window |out_bounds| and |out_show_state| for simulated
   // persisted and last-active window bounds, work area, show state, etc.
@@ -124,9 +140,13 @@
 
 }  // namespace
 
+// WindowSizerChromeOSNoAshTest are the tests that does not require ash
+// environment, thus it can use WindowSizerTestUtil that create a TestScreen
+// inside.
+
 // Test that the window is sized appropriately for the first run experience
 // where the default window bounds calculation is invoked.
-TEST_F(WindowSizerChromeOSTest, DefaultSizeCase) {
+TEST(WindowSizerChromeOSNoAshTest, DefaultSizeCase) {
   {
     // 4:3 monitor case, 1024x768, no taskbar.
     gfx::Rect window_bounds;
@@ -237,7 +257,7 @@
 
 // Test that the next opened window is positioned appropriately given the
 // bounds of an existing window of the same type.
-TEST_F(WindowSizerChromeOSTest, LastWindowBoundsCase) {
+TEST(WindowSizerChromeOS2NoAshTest, LastWindowBoundsCase) {
   {
     // Normal, in the middle of the screen somewhere.
     gfx::Rect window_bounds;
@@ -294,8 +314,8 @@
   }
 }
 
-TEST_F(WindowSizerChromeOSTest,
-       LastWindowOffscreenWithNonAggressiveRepositioning) {
+TEST(WindowSizerChromeOSNoAshTest,
+     LastWindowOffscreenWithNonAggressiveRepositioning) {
   {
     // Taskbar on left.
     gfx::Rect window_bounds;
@@ -370,6 +390,12 @@
 
 // Test the placement of newly created windows.
 TEST_F(WindowSizerChromeOSTest, PlaceNewWindows) {
+  UpdateDisplay("1600x1200");
+  auto* shelf = ash::Shell::GetPrimaryRootWindowController()->shelf();
+  shelf->SetAutoHideBehavior(ash::ShelfAutoHideBehavior::kAlways);
+
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+
   // Create a browser to pass into the WindowSizerTestUtil::GetWindowBounds
   // function.
   Browser::CreateParams native_params(&profile_, true);
@@ -395,10 +421,9 @@
     Browser::CreateParams params_popup(Browser::TYPE_POPUP, &profile_, true);
     auto new_popup = CreateWindowlessBrowser(params_popup);
     gfx::Rect window_bounds;
-    WindowSizerTestUtil::GetWindowBounds(
-        p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(50, 100, 300, 150),
-        bottom_s1600x1200, PERSISTED, new_popup.get(), gfx::Rect(),
-        &window_bounds);
+    GetWindowBounds(new_popup.get(), gfx::Rect(), display_id,
+                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200, PERSISTED,
+                    &window_bounds);
     EXPECT_EQ("50,100 300x150", window_bounds.ToString());
   }
 
@@ -406,19 +431,17 @@
   {
     // If a window is there but not shown the persisted default should be used.
     gfx::Rect window_bounds;
-    WindowSizerTestUtil::GetWindowBounds(
-        p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(50, 100, 300, 150),
-        bottom_s1600x1200, PERSISTED, browser.get(), gfx::Rect(),
-        &window_bounds);
+    GetWindowBounds(browser.get(), gfx::Rect(), display_id,
+                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200, PERSISTED,
+                    &window_bounds);
     EXPECT_EQ("50,100 300x150", window_bounds.ToString());
   }
 
   {
     // If a window is there but not shown the default should be returned.
     gfx::Rect window_bounds;
-    WindowSizerTestUtil::GetWindowBounds(
-        p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(), bottom_s1600x1200,
-        DEFAULT, browser.get(), gfx::Rect(), &window_bounds);
+    GetWindowBounds(browser.get(), gfx::Rect(), display_id, gfx::Rect(),
+                    bottom_s1600x1200, DEFAULT, &window_bounds);
     // Note: We need to also take the defaults maximum width into account here
     // since that might get used if the resolution is too big.
     EXPECT_EQ(
diff --git a/chrome/browser/user_agent/user_agent_browsertest.cc b/chrome/browser/user_agent/user_agent_browsertest.cc
index a4e1f26..be6ef64e 100644
--- a/chrome/browser/user_agent/user_agent_browsertest.cc
+++ b/chrome/browser/user_agent/user_agent_browsertest.cc
@@ -58,9 +58,11 @@
         prefs::kUserAgentReduction);
   }
 
-  void set_force_major_version_to_minor_policy(int policy) {
+  void set_force_major_version_to_minor_policy(
+      ForceMajorVersionToMinorPolicyState policy) {
     browser()->profile()->GetPrefs()->SetInteger(
-        prefs::kForceMajorVersionToMinorPositionInUserAgent, policy);
+        prefs::kForceMajorVersionToMinorPositionInUserAgent,
+        static_cast<int>(policy));
   }
 
   std::string observed_user_agent() { return observered_user_agent_; }
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 12507bd..4231a79 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -414,6 +414,15 @@
   translation_manager_ = translation_manager;
 }
 
+std::vector<AppId> WebAppInstallFinalizer::GetPendingUninstallsForTesting()
+    const {
+  std::vector<AppId> ids;
+  for (const auto& [key, _] : pending_uninstalls_) {
+    ids.push_back(key);
+  }
+  return ids;
+}
+
 void WebAppInstallFinalizer::UninstallWebAppInternal(
     const AppId& app_id,
     webapps::WebappUninstallSource uninstall_source,
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h
index 53fe77a..b720eb0 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.h
+++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -172,6 +172,8 @@
                                   bool is_placeholder,
                                   GURL install_url);
 
+  std::vector<AppId> GetPendingUninstallsForTesting() const;
+
  private:
   using CommitCallback = base::OnceCallback<void(bool success)>;
 
diff --git a/chrome/browser/window_placement/window_placement_printing_interactive_uitest.cc b/chrome/browser/window_placement/window_placement_printing_interactive_uitest.cc
index 8efceba..b10fccc 100644
--- a/chrome/browser/window_placement/window_placement_printing_interactive_uitest.cc
+++ b/chrome/browser/window_placement/window_placement_printing_interactive_uitest.cc
@@ -25,6 +25,15 @@
 
 class WindowPlacementTest : public InProcessBrowserTest {
  public:
+  void SetUp() override {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    display::Screen::SetScreenInstance(&screen_);
+    screen_.display_list().AddDisplay({1, gfx::Rect(0, 0, 803, 600)},
+                                      display::DisplayList::Type::PRIMARY);
+#endif
+    InProcessBrowserTest::SetUp();
+  }
+
   void SetUpOnMainThread() override {
     // Window placement features are only available on secure contexts.
     https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
@@ -33,10 +42,20 @@
     ASSERT_TRUE(https_test_server_->Start());
   }
 
+  void TearDown() override {
+    InProcessBrowserTest::TearDown();
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    display::Screen::SetScreenInstance(nullptr);
+#endif
+  }
+
  protected:
   std::unique_ptr<net::EmbeddedTestServer> https_test_server_;
   base::test::ScopedFeatureList scoped_feature_list_{
       blink::features::kWindowPlacement};
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+  display::ScreenBase screen_;
+#endif
 };
 
 // TODO(crbug.com/1042990): Windows crashes static casting to ScreenWin.
@@ -56,11 +75,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
       .UpdateDisplay("0+0-803x600");
-#else
-  display::ScreenBase screen;
-  screen.display_list().AddDisplay({1, gfx::Rect(0, 0, 803, 600)},
-                                   display::DisplayList::Type::PRIMARY);
-  display::test::ScopedScreenOverride screen_override(&screen);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
 
@@ -99,9 +113,9 @@
   display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
       .UpdateDisplay("0+0-807x600");
 #else
-  screen.display_list().UpdateDisplay({1, gfx::Rect(0, 0, 807, 600)},
-                                      display::DisplayList::Type::PRIMARY);
-  EXPECT_EQ(screen.display_list().displays().size(), 1u);
+  screen_.display_list().UpdateDisplay({1, gfx::Rect(0, 0, 807, 600)},
+                                       display::DisplayList::Type::PRIMARY);
+  EXPECT_EQ(screen_.display_list().displays().size(), 1u);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
 
@@ -116,9 +130,9 @@
   display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
       .UpdateDisplay("0+0-807x600,1000+0-804x600");
 #else
-  screen.display_list().AddDisplay({2, gfx::Rect(1000, 0, 804, 600)},
-                                   display::DisplayList::Type::NOT_PRIMARY);
-  EXPECT_EQ(screen.display_list().displays().size(), 2u);
+  screen_.display_list().AddDisplay({2, gfx::Rect(1000, 0, 804, 600)},
+                                    display::DisplayList::Type::NOT_PRIMARY);
+  EXPECT_EQ(screen_.display_list().displays().size(), 2u);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   ASSERT_EQ(2, display::Screen::GetScreen()->GetNumDisplays());
 
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 95aa920..0a0d2227 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1654084629-88ef78a37a3844db910308c92fcae2cadd81afd2.profdata
+chrome-linux-main-1654106273-dbf910d92285f866bfe20fa62cef7bb521e076e9.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index ba6bd75..3715eff 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1654084629-2e4a077a32fbdc22de6784d16188674959719ee9.profdata
+chrome-mac-arm-main-1654106273-02ddc33f6f1e8cfc21be0d6f09bd54fbc5100dc5.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index ce415fe..92d41eb 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1654084629-9ad5e12689849a7e51134585bc2f97718ca2c950.profdata
+chrome-mac-main-1654106273-5f74585bdc28e27dfa1a0c4da6b9e2cd6dc56bfc.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index cdeb8990..1ce0a80 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1654095358-c584e3d00ca67339756384f10d6db80ad5d760b6.profdata
+chrome-win32-main-1654117182-4a5c1f5d406ab9939f8ff46d944568c452e135a4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 2f6edb91..928c5fe 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1654095358-5d7d79735dfab517cee6421bfe17b0065432e90e.profdata
+chrome-win64-main-1654117182-f4939ebe694c82bbc59ba50a86f4d32e4c789da4.profdata
diff --git a/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc b/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
index cfa4f6e5..8c3049a 100644
--- a/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
+++ b/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
@@ -183,11 +183,11 @@
 
   ExtensionMsg_TabConnectionInfo tab_connection_info;
   tab_connection_info.frame_id = 0;
-  const int tab_id = 10;
   GURL source_url("http://example.com");
-  tab_connection_info.tab.Swap(
-      DictionaryBuilder().Set("tabId", tab_id).Build().get());
   ExtensionMsg_ExternalConnectionInfo external_connection_info;
+  // We'd normally also have a tab here (stored in `tab_connection_info.tab`),
+  // but then we need a very large JSON object for it to comply with our
+  // schema. Just pretend it's not there.
   external_connection_info.target_id = extension()->id();
   external_connection_info.source_endpoint =
       MessagingEndpoint::ForExtension(extension()->id());
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 5c5e1d4..ec659c51 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -119,6 +119,10 @@
 #include "ui/events/test/event_generator.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+#if defined(USE_OZONE)
+#include "ui/views/test/test_desktop_screen_ozone.h"
+#endif
+
 #if defined(TOOLKIT_VIEWS)
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -595,6 +599,22 @@
   return true;
 }
 
+void InProcessBrowserTest::SetScreenInstance() {
+  // TODO(crbug.com/1317416): On wayland platform, we need to check if the
+  // wayland-ozone platform is initialized at this point due to the async
+  // initialization of the display. Investigate if we can eliminate
+  // IsOzoneInitialized.
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  if (!display::Screen::HasScreen() &&
+      views::test::TestDesktopScreenOzone::IsOzoneInitialized()) {
+    // This is necessary for interactive UI tests.
+    // It is enabled in interactive_ui_tests_main.cc
+    // (or through GPUMain)
+    screen_ = views::test::TestDesktopScreenOzone::Create();
+  }
+#endif
+}
+
 #if !BUILDFLAG(IS_MAC)
 void InProcessBrowserTest::OpenDevToolsWindow(
     content::WebContents* web_contents) {
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h
index b9ac30b..e154efc 100644
--- a/chrome/test/base/in_process_browser_test.h
+++ b/chrome/test/base/in_process_browser_test.h
@@ -52,6 +52,10 @@
 }
 #endif  // defined(TOOLKIT_VIEWS)
 
+namespace display {
+class Screen;
+}
+
 class Browser;
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 class FakeAccountManagerUI;
@@ -225,7 +229,7 @@
   [[nodiscard]] virtual bool SetUpUserDataDirectory();
 
   // Initializes the display::Screen instance.
-  virtual void SetScreenInstance() {}
+  virtual void SetScreenInstance();
 
   // BrowserTestBase:
   void PreRunTestOnMainThread() override;
@@ -314,6 +318,10 @@
   FakeAccountManagerUI* GetFakeAccountManagerUI() const;
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  std::unique_ptr<display::Screen> screen_;
+#endif
+
  private:
   void Initialize();
 
diff --git a/chrome/test/data/extensions/api_test/vpn_provider/basic.js b/chrome/test/data/extensions/api_test/vpn_provider/basic.js
index bea399f..5cc68ba4 100644
--- a/chrome/test/data/extensions/api_test/vpn_provider/basic.js
+++ b/chrome/test/data/extensions/api_test/vpn_provider/basic.js
@@ -302,6 +302,24 @@
       chrome.test.succeed();
     });
   },
+  platformMessage: function () {
+    let i = 0;
+    chrome.vpnProvider.onPlatformMessage.addListener((config_name,
+                                                      message, error) => {
+      chrome.test.assertEq(config_name, 'testconfig');
+      if (message === 'connected') {
+        chrome.test.assertEq(i, 0);
+        chrome.test.succeed();
+        i++;
+      } else {
+        chrome.test.assertEq(i, 1);
+        chrome.test.assertEq(message, 'disconnected');
+        chrome.test.succeed();
+        i++;
+      }
+    });
+    chrome.test.succeed();
+  }
 };
 
 testRoutines[selectedTest]();
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.js
index 05f54f7f..11fa1da 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_extension_test.js
@@ -136,7 +136,7 @@
               emojiPicker.emoticonData[idx].emoji.length;
           await waitForCondition(
               () => expectedNumberOfEmoticons ===
-                  group.shadowRoot.querySelectorAll('emoji-button').length);
+                  group.shadowRoot.querySelectorAll('.emoji-button').length);
         }
       });
 
@@ -224,7 +224,7 @@
 
         const recentlyUsedEmoticons =
             findInEmojiPicker(emoticonHistoryGroupSelector
-                ).shadowRoot.querySelectorAll('emoji-button');
+                ).shadowRoot.querySelectorAll('.emoji-button');
         assertEquals(1, recentlyUsedEmoticons.length);
       });
 
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_search_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_search_test.js
index c715e5fc..5cbe789 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_search_test.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_search_test.js
@@ -59,12 +59,12 @@
         emojiSearch.search = 'face';
         flush();
         const emojiResults = findInEmojiPicker('emoji-search', 'emoji-group')
-                                 .shadowRoot.querySelectorAll('emoji-button');
+                                 .shadowRoot.querySelectorAll('.emoji-button');
         assertGT(emojiResults.length, 0);
         const emoticonResults =
           findInEmojiPicker(
             'emoji-search', 'emoji-group[category="emoticon"]')
-              .shadowRoot.querySelectorAll('emoji-button');
+              .shadowRoot.querySelectorAll('.emoji-button');
         assertGT(emoticonResults.length, 0);
       });
 
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
index 762ff31..557b9169 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
@@ -21,6 +21,8 @@
   let emojiPicker;
   /** @type {function(...!string): ?HTMLElement} */
   let findInEmojiPicker;
+  /** @type {function(...!string): ?HTMLElement} */
+  let findEmojiFirstButton;
 
   setup(() => {
     // Reset DOM state.
@@ -33,6 +35,14 @@
 
     findInEmojiPicker = (...path) => deepQuerySelector(emojiPicker, path);
 
+    findEmojiFirstButton = (...path) => {
+      const emojiElement = deepQuerySelector(emojiPicker, path);
+      if (emojiElement) {
+          return emojiElement.firstEmojiButton();
+      }
+      return null;
+    };
+
     // Wait until emoji data is loaded before executing tests.
     return new Promise((resolve) => {
       emojiPicker.addEventListener(EMOJI_REMAINING_DATA_LOADED, resolve);
@@ -78,8 +88,8 @@
 
     // wait so emoji-groups render and we have something to scroll to.
     await waitForCondition(
-        () => findInEmojiPicker(
-            '[data-group="2"] > emoji-group', 'emoji-button', 'button'));
+        () => findEmojiFirstButton(
+            '[data-group="2"] > emoji-group'));
     thirdButton.click();
 
     // wait while waiting for scroll to happen and update buttons.
@@ -108,15 +118,14 @@
             new Promise((resolve) => resolve({incognito: false}));
         // yield to allow emoji-group and emoji buttons to render.
         const emojiButton = await waitForCondition(
-            () => findInEmojiPicker(
-                '[data-group="0"] > emoji-group', 'emoji-button', 'button'));
+            () => findEmojiFirstButton(
+                '[data-group="0"] > emoji-group'));
         emojiButton.click();
 
         // wait until emoji exists in recently used section.
         const recentlyUsed = await waitForCondition(
-            () => findInEmojiPicker(
-                '[data-group=history] > emoji-group', 'emoji-button',
-                'button'));
+            () => findEmojiFirstButton(
+                '[data-group=history] > emoji-group'));
 
         // check text is correct.
         const recentText = recentlyUsed.innerText;
@@ -132,15 +141,14 @@
             new Promise((resolve) => resolve({incognito: false}));
         // yield to allow emoji-group and emoji buttons to render.
         const emojiButton = await waitForCondition(
-            () => findInEmojiPicker(
-                '[data-group="0"] > emoji-group', 'emoji-button', 'button'));
+            () => findEmojiFirstButton(
+                '[data-group="0"] > emoji-group'));
         emojiButton.click();
 
         // wait until emoji exists in recently used section.
         const recentlyUsed = await waitForCondition(
-            () => findInEmojiPicker(
-                '[data-group=history] > emoji-group', 'emoji-button',
-                'button'));
+            () => findEmojiFirstButton(
+                '[data-group=history] > emoji-group'));
 
         // check text is correct.
         await (waitForCondition(async () => {
@@ -155,17 +163,15 @@
     // yield to allow emoji-group and emoji buttons to render.
     const emojiButton = (await waitForCondition(
                              () => findInEmojiPicker(
-                                 '[data-group="0"] > emoji-group',
-                                 'emoji-button:nth-child(3)')))
-                            .shadowRoot.querySelector('button');
+                               '[data-group="0"] > emoji-group',
+                               'button[data-index="2"]')));
     emojiButton.click();
 
     // wait until emoji exists in recently used section.
     const recentlyUsed =
         (await waitForCondition(
-             () => findInEmojiPicker(
-                 '[data-group=history] > emoji-group', 'emoji-button')))
-            .shadowRoot.querySelector('button');
+             () => findEmojiFirstButton(
+                 '[data-group=history] > emoji-group')));
 
     // check variants class is applied
     assertTrue(recentlyUsed.classList.contains('has-variants'));
@@ -180,16 +186,14 @@
         const emojiButton = (await waitForCondition(
                                  () => findInEmojiPicker(
                                      '[data-group="0"] > emoji-group',
-                                     'emoji-button:nth-child(2)')))
-                                .shadowRoot.querySelector('button');
+                                     'button[data-index="0"]')));
         emojiButton.click();
 
         // wait until emoji exists in recently used section.
         const recentlyUsed =
             (await waitForCondition(
-                 () => findInEmojiPicker(
-                     '[data-group=history] > emoji-group', 'emoji-button')))
-                .shadowRoot.querySelector('button');
+                 () => findEmojiFirstButton(
+                     '[data-group=history] > emoji-group')));
 
         // check variants class is not applied
         assertFalse(recentlyUsed.classList.contains('has-variants'));
@@ -202,8 +206,7 @@
             new Promise((resolve) => resolve({incognito: true}));
         // yield to allow emoji-group and emoji buttons to render.
         const emojiButton = await waitForCondition(
-            () => findInEmojiPicker(
-                '[data-group="0"] > emoji-group', 'emoji-button', 'button'));
+            () => findEmojiFirstButton('[data-group="0"] > emoji-group'));
         emojiButton.click();
 
         // Wait to ensure recents has a chance to render if we have a bug.
@@ -222,16 +225,14 @@
     const emojiButton = (await waitForCondition(
                              () => findInEmojiPicker(
                                  '[data-group="0"] > emoji-group',
-                                 'emoji-button:nth-child(2)')))
-                            .shadowRoot.querySelector('button');
+                                 'button[data-index="1"]')));
     emojiButton.click();
 
     // wait until emoji exists in recently used section.
     const recentlyUsed =
         (await waitForCondition(
-             () => findInEmojiPicker(
-                 '[data-group=history] > emoji-group', 'emoji-button')))
-            .shadowRoot.querySelector('button');
+             () => findEmojiFirstButton(
+               '[data-group=history] > emoji-group')));
 
     // click show clear button
     findInEmojiPicker('.group', '#show-clear').click();
@@ -263,9 +264,7 @@
       firstEmojiButton = (await waitForCondition(
                               () => findInEmojiPicker(
                                   '[data-group="0"] > emoji-group',
-                                  'emoji-button:nth-child(3)')))
-                             .shadowRoot;
-
+                                  '.emoji-button-container:nth-child(3)')));
 
       // right click and wait for variants to appear.
       const variantsPromise = waitForEvent(emojiPicker, EMOJI_VARIANTS_SHOWN);
@@ -299,8 +298,8 @@
       const emojiButton2 = await waitForCondition(
           () =>
               findInEmojiPicker(
-                  '[data-group="0"] > emoji-group', 'emoji-button:nth-child(4)')
-                  .shadowRoot);
+                '[data-group="0"] > emoji-group',
+                '.emoji-button-container:nth-child(4)'));
 
       // right click on second emoji button
       dispatchMouseEvent(emojiButton2.querySelector('button'), 2);
@@ -327,8 +326,8 @@
       const coupleEmojiButton = await waitForCondition(
           () =>
               findInEmojiPicker(
-                  '[data-group="0"] > emoji-group', 'emoji-button:nth-child(5)')
-                  .shadowRoot);
+                  '[data-group="0"] > emoji-group',
+                  '.emoji-button-container:nth-child(5)'));
 
       // listen for emoji variants event.
       const variantsPromise = waitForEvent(emojiPicker, EMOJI_VARIANTS_SHOWN);
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts
index e4c1a09..bd2812a 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts
@@ -126,8 +126,10 @@
                     PersonalizationActionName.SET_ERROR) as SetErrorAction;
 
             // Verify |error| expectations.
-            assertEquals(error.message, 'Something went wrong.');
-            assertEquals(error.dismiss?.message, 'Retry');
+            assertEquals(
+                error.message,
+                'Couldn’t load images. Check your network connection or try loading the images again.');
+            assertEquals(error.dismiss?.message, 'Try again');
             assertNotEquals(error.dismiss?.callback, undefined);
 
             wallpaperProvider.reset();
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts
index 2699c06..3067613 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts
@@ -84,8 +84,10 @@
                     PersonalizationActionName.SET_ERROR) as SetErrorAction;
 
             // Verify |error| expectations.
-            assertEquals(error.message, 'Something went wrong.');
-            assertEquals(error.dismiss?.message, 'Retry');
+            assertEquals(
+                error.message,
+                'Couldn’t load images. Check your network connection or try loading the images again.');
+            assertEquals(error.dismiss?.message, 'Try again');
             assertNotEquals(error.dismiss?.callback, undefined);
 
             wallpaperProvider.reset();
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_element_test.ts
index 5e194333..e8492cb 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_element_test.ts
@@ -274,8 +274,10 @@
                     PersonalizationActionName.SET_ERROR) as SetErrorAction;
 
             // Verify |error| expectations.
-            assertEquals(error.message, 'Something went wrong.');
-            assertEquals(error.dismiss?.message, 'Retry');
+            assertEquals(
+                error.message,
+                'Couldn’t load images. Check your network connection or try loading the images again.');
+            assertEquals(error.dismiss?.message, 'Try again');
             assertNotEquals(error.dismiss?.callback, undefined);
 
             wallpaperProvider.reset();
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 0b86750..e8eeb29 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -16,20 +16,17 @@
 js_library("fake_personalization_search_handler") {
   deps = [
     "//ash/webui/personalization_app/search:mojo_bindings_js_library_for_compile",
-    "//ui/webui/resources/js:cr",
   ]
 }
 
 js_library("fake_settings_search_handler") {
   deps = [
     "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile",
-    "//ui/webui/resources/js:cr",
   ]
 }
 
 js_library("fake_user_action_recorder") {
   deps = [
     "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile",
-    "//ui/webui/resources/js:cr",
   ]
 }
diff --git a/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js b/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
index 5024278..f6a1eb1 100644
--- a/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+
 import {AmbientModeBrowserProxyImpl, AmbientModeTemperatureUnit, AmbientModeTopicSource, CrSettingsPrefs, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {waitAfterNextRender} from 'chrome://test/test_util.js';
@@ -132,12 +134,12 @@
     assertFalse(!!topicSourceListDiv);
 
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -156,12 +158,12 @@
 
   test('topicSourceItemHasCorrectRowHeight', function() {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -177,12 +179,12 @@
 
   test('doubleClickTopicSource', () => {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -217,12 +219,12 @@
     Router.getInstance().navigateTo(routes.AMBIENT_MODE, params);
 
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -237,7 +239,7 @@
 
   test('temperatureUnitRadioButtonsVisibility', () => {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
@@ -251,7 +253,7 @@
 
     // When |selectedTemperatureUnit_| is valid the radio buttons should be
     // visible and enabled.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -263,12 +265,12 @@
 
   test('temperatureUnitRadioButtons', async () => {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -311,12 +313,12 @@
 
   test('temperatureUnitRadioButtonsDoubleClick', async () => {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
@@ -332,12 +334,12 @@
 
   test('topicSourceAndWeatherDisabledWhenToggleOff', () => {
     // Select the google photos topic source.
-    cr.webUIListenerCallback('topic-source-changed', {
+    webUIListenerCallback('topic-source-changed', {
       'topicSource': AmbientModeTopicSource.GOOGLE_PHOTOS,
       'hasAlbums': true
     });
     // Select celsius as the initial temperature unit.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'temperature-unit-changed', AmbientModeTemperatureUnit.CELSIUS);
     flush();
 
diff --git a/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js b/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js
index 1ed12a6..b4accf43 100644
--- a/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {AmbientModeBrowserProxyImpl, AmbientModeTopicSource} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {waitAfterNextRender} from 'chrome://test/test_util.js';
 
@@ -570,7 +571,7 @@
 
     // Update album URL.
     const url = 'url';
-    cr.webUIListenerCallback('album-preview-changed', {
+    webUIListenerCallback('album-preview-changed', {
       topicSource: AmbientModeTopicSource.ART_GALLERY,
       albumId: 'id0',
       url: url
@@ -592,7 +593,7 @@
 
     // Different topic source will no update album URL.
     const url = 'chrome://ambient';
-    cr.webUIListenerCallback('album-preview-changed', {
+    webUIListenerCallback('album-preview-changed', {
       topicSource: AmbientModeTopicSource.GOOGLE_PHOTOS,
       albumId: 'id0',
       url: url
@@ -617,7 +618,7 @@
 
     // Update album URL.
     const url = 'url';
-    cr.webUIListenerCallback('album-preview-changed', {
+    webUIListenerCallback('album-preview-changed', {
       topicSource: AmbientModeTopicSource.ART_GALLERY,
       albumId: 'id0',
       url: url
@@ -648,7 +649,7 @@
 
     // Update Recent Highlights album URLs.
     const url = 'url';
-    cr.webUIListenerCallback('album-preview-changed', {
+    webUIListenerCallback('album-preview-changed', {
       topicSource: AmbientModeTopicSource.GOOGLE_PHOTOS,
       albumId: 'id0',
       recentHighlightsUrls: [url, url, url, url]
@@ -697,7 +698,7 @@
 
     // Only update 3 images.
     const url = 'url';
-    cr.webUIListenerCallback('album-preview-changed', {
+    webUIListenerCallback('album-preview-changed', {
       topicSource: AmbientModeTopicSource.GOOGLE_PHOTOS,
       albumId: 'id0',
       recentHighlightsUrls: [url, url, url]
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
index 3a5679174..f1e4afa 100644
--- a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
@@ -5,6 +5,7 @@
 import {CupsPrintersBrowserProxyImpl, PrinterType} from 'chrome://os-settings/chromeos/lazy_load.js';
 import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
 import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {waitAfterNextRender} from 'chrome://test/test_util.js';
@@ -177,7 +178,7 @@
         printerList.splice(index, 1);
 
         // Simuluate saved printer changes.
-        cr.webUIListenerCallback(
+        webUIListenerCallback(
             'on-saved-printers-changed', cupsPrintersBrowserProxy.printerList);
         flush();
       });
@@ -259,7 +260,7 @@
 
   function updateSavedPrinters() {
     cupsPrintersBrowserProxy.printerList = {printerList: printerList};
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'on-saved-printers-changed', cupsPrintersBrowserProxy.printerList);
     flush();
   }
@@ -1022,7 +1023,7 @@
       assertEquals(0, nearbyPrinterEntries.length);
 
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', automaticPrinterList,
           discoveredPrinterList);
 
@@ -1067,7 +1068,7 @@
       assertTrue(!!nearbyPrintersElement);
 
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', automaticPrinterList,
           discoveredPrinterList);
 
@@ -1091,7 +1092,7 @@
           assertTrue(!!nearbyPrintersElement);
 
           // Simuluate finding nearby printers.
-          cr.webUIListenerCallback(
+          webUIListenerCallback(
               'on-nearby-printers-changed', automaticPrinterList,
               discoveredPrinterList);
 
@@ -1134,7 +1135,7 @@
 
       assertTrue(!!nearbyPrintersElement);
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', [], discoveredPrinterList);
       flush();
 
@@ -1185,7 +1186,7 @@
           assertTrue(!!nearbyPrintersElement);
 
           // Simuluate finding nearby printers.
-          cr.webUIListenerCallback(
+          webUIListenerCallback(
               'on-nearby-printers-changed', automaticPrinterList,
               discoveredPrinterList);
 
@@ -1295,7 +1296,7 @@
           ];
 
           // Simuluate finding nearby printers.
-          cr.webUIListenerCallback(
+          webUIListenerCallback(
               'on-nearby-printers-changed', automaticPrinterList,
               discoveredPrinterList);
 
@@ -1332,7 +1333,7 @@
       assertTrue(!!printerEntryListTestElement);
 
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', [], discoveredPrinterList);
 
       flush();
@@ -1382,7 +1383,7 @@
           createCupsPrinterInfo('google2', 'printerAddress5', 'printerId5'));
 
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', [], discoveredPrinterList);
 
       flush();
@@ -1418,7 +1419,7 @@
       assertTrue(!!printerEntryListTestElement);
 
       // Simuluate finding nearby printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', [], discoveredPrinterList);
 
       flush();
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
index 52fddf7..53133ce 100644
--- a/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/cups_printer_page_tests.js
@@ -5,6 +5,7 @@
 import {CupsPrintersBrowserProxyImpl, CupsPrintersEntryManager, PrinterSetupResult, PrinterType, PrintServerResult} from 'chrome://os-settings/chromeos/lazy_load.js';
 import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
 import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {keyEventOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -1410,7 +1411,7 @@
 
       // Simulate the underlying model changes. Nearby printers are also
       // updated after changes to saved printers.
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'on-nearby-printers-changed', /*automaticPrinter=*/[],
           /*discoveredPrinters=*/[]);
       flush();
diff --git a/chrome/test/data/webui/settings/chromeos/date_time_page_tests.js b/chrome/test/data/webui/settings/chromeos/date_time_page_tests.js
index ca7d453..23e08dce 100644
--- a/chrome/test/data/webui/settings/chromeos/date_time_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/date_time_page_tests.js
@@ -5,6 +5,7 @@
 import {TimeZoneAutoDetectMethod, TimeZoneBrowserProxyImpl} from 'chrome://os-settings/chromeos/lazy_load.js';
 import {CrSettingsPrefs, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js';
@@ -438,7 +439,7 @@
     assertTrue(timeZoneAutoDetectOff.disabled);
 
     await testBrowserProxy.whenCalled('showParentAccessForTimeZone');
-    cr.webUIListenerCallback('access-code-validation-complete');
+    webUIListenerCallback('access-code-validation-complete');
 
     // Verify elements are enabled.
     assertFalse(resolveMethodDropdown.disabled);
@@ -478,7 +479,7 @@
     assertTrue(timeZoneAutoDetectOff.disabled);
 
     await testBrowserProxy.whenCalled('showParentAccessForTimeZone');
-    cr.webUIListenerCallback('access-code-validation-complete');
+    webUIListenerCallback('access-code-validation-complete');
 
     // |resolveMethodDropdown| is disabled when auto detect off.
     assertTrue(resolveMethodDropdown.disabled);
@@ -499,7 +500,7 @@
     assertEquals(0, setDateTimeButton.offsetHeight);
 
     // Make the date and time editable.
-    cr.webUIListenerCallback('can-set-date-time-changed', true);
+    webUIListenerCallback('can-set-date-time-changed', true);
     await flushTasks();
     assertGT(setDateTimeButton.offsetHeight, 0);
 
@@ -509,7 +510,7 @@
     assertEquals(1, testBrowserProxy.getCallCount('showSetDateTimeUI'));
 
     // Make the date and time not editable.
-    cr.webUIListenerCallback('can-set-date-time-changed', false);
+    webUIListenerCallback('can-set-date-time-changed', false);
     assertEquals(setDateTimeButton.offsetHeight, 0);
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/fingerprint_browsertest_chromeos.js b/chrome/test/data/webui/settings/chromeos/fingerprint_browsertest_chromeos.js
index cf922db..1e2f8b67 100644
--- a/chrome/test/data/webui/settings/chromeos/fingerprint_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/chromeos/fingerprint_browsertest_chromeos.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {FingerprintBrowserProxyImpl, FingerprintResultType, FingerprintSetupStep, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {flushTasks, isVisible, waitAfterNextRender} from 'chrome://test/test_util.js';
@@ -41,7 +42,7 @@
       this.fingerprintsList_.push('New Label');
     }
 
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'on-fingerprint-scan-received',
         {result: result, isComplete: complete, percentComplete: percent});
   }
diff --git a/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.js b/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.js
index 1b32bbc..00a819d 100644
--- a/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.js
+++ b/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.js
@@ -5,6 +5,7 @@
 import 'chrome://os-settings/chromeos/os_settings.js';
 
 import {GuestOsBrowserProxyImpl} from 'chrome://os-settings/chromeos/lazy_load.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {flushTasks} from 'chrome://test/test_util.js';
 
@@ -24,7 +25,7 @@
   /** @override */
   notifyGuestOsSharedUsbDevicesPageReady() {
     this.methodCalled('notifyGuestOsSharedUsbDevicesPageReady');
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'guest-os-shared-usb-devices-changed', this.sharedUsbDevices);
   }
 
@@ -92,7 +93,7 @@
     assertEquals('0001', args[1]);
     assertEquals(true, args[2]);
     // Simulate a change in the underlying model.
-    cr.webUIListenerCallback('guest-os-shared-usb-devices-changed', [
+    webUIListenerCallback('guest-os-shared-usb-devices-changed', [
       {
         guid: '0001',
         label: 'usb_dev1',
diff --git a/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js b/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js
index 8fadfcc..dffd2fe8 100644
--- a/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js
+++ b/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.js
@@ -11,6 +11,7 @@
 import {flushTasks} from 'chrome://test/test_util.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {waitAfterNextRender} from 'chrome://test/test_util.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 
 // Tests for the Kerberos Accounts settings page.
 suite('KerberosAccountsTests', function() {
@@ -255,7 +256,7 @@
 
   test('AccountListIsUpdatedWhenKerberosAccountsUpdates', function() {
     assertEquals(1, browserProxy.getCallCount('getAccounts'));
-    cr.webUIListenerCallback('kerberos-accounts-changed');
+    webUIListenerCallback('kerberos-accounts-changed');
     assertEquals(2, browserProxy.getCallCount('getAccounts'));
   });
 
diff --git a/chrome/test/data/webui/settings/chromeos/lock_screen_tests.js b/chrome/test/data/webui/settings/chromeos/lock_screen_tests.js
index 5532557..d4b22aa 100644
--- a/chrome/test/data/webui/settings/chromeos/lock_screen_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/lock_screen_tests.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {flushTasks, waitAfterNextRender} from 'chrome://test/test_util.js';
@@ -52,19 +53,19 @@
     // This block is not really validating the change because it checks the same
     // state as initial. However it improves the reliability of the next assert
     // block as it adds some wait time.
-    cr.webUIListenerCallback('quick-unlock-disabled-by-policy-changed', false);
+    webUIListenerCallback('quick-unlock-disabled-by-policy-changed', false);
     await flushTasks();
     assertFalse(
         unlockTypeRadioGroup.disabled,
         'Unlock type radio group unexpectedly disabled after policy change');
 
-    cr.webUIListenerCallback('quick-unlock-disabled-by-policy-changed', true);
+    webUIListenerCallback('quick-unlock-disabled-by-policy-changed', true);
     await flushTasks();
     assertTrue(
         unlockTypeRadioGroup.disabled,
         'Unlock type radio group unexpectedly enabled after policy change');
 
-    cr.webUIListenerCallback('quick-unlock-disabled-by-policy-changed', false);
+    webUIListenerCallback('quick-unlock-disabled-by-policy-changed', false);
     await flushTasks();
     assertFalse(
         unlockTypeRadioGroup.disabled,
diff --git a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
index a0702f9f..38d935f 100644
--- a/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/manage_accessibility_page_tests.js
@@ -5,6 +5,7 @@
 import 'chrome://os-settings/chromeos/lazy_load.js';
 
 import {DevicePageBrowserProxy, DevicePageBrowserProxyImpl, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {eventToPromise, isVisible, waitAfterNextRender, waitBeforeNextRender} from 'chrome://test/test_util.js';
@@ -27,24 +28,24 @@
     /** @param {boolean} hasMouse */
     set hasMouse(hasMouse) {
       this.hasMouse_ = hasMouse;
-      cr.webUIListenerCallback('has-mouse-changed', this.hasMouse_);
+      webUIListenerCallback('has-mouse-changed', this.hasMouse_);
     }
 
     /** @param {boolean} hasTouchpad */
     set hasTouchpad(hasTouchpad) {
       this.hasTouchpad_ = hasTouchpad;
-      cr.webUIListenerCallback('has-touchpad-changed', this.hasTouchpad_);
+      webUIListenerCallback('has-touchpad-changed', this.hasTouchpad_);
     }
 
     /** @override */
     initializePointers() {
-      cr.webUIListenerCallback('has-mouse-changed', this.hasMouse_);
-      cr.webUIListenerCallback('has-touchpad-changed', this.hasTouchpad_);
+      webUIListenerCallback('has-mouse-changed', this.hasMouse_);
+      webUIListenerCallback('has-touchpad-changed', this.hasTouchpad_);
     }
 
     /** @override */
     initializeKeyboardWatcher() {
-      cr.webUIListenerCallback('has-hardware-keyboard', this.hasKeyboard_);
+      webUIListenerCallback('has-hardware-keyboard', this.hasKeyboard_);
     }
   }
 
@@ -282,7 +283,7 @@
       recommended: true,
       value: 'en-US',
     }];
-    cr.webUIListenerCallback('dictation-locales-set', locales);
+    webUIListenerCallback('dictation-locales-set', locales);
     flush();
 
     // Dictation toggle.
@@ -307,8 +308,7 @@
         dictationLocaleMenuSubtitle.innerText);
 
     // Fake a request to change the dictation locale menu subtitle.
-    cr.webUIListenerCallback(
-        'dictation-locale-menu-subtitle-changed', 'Testing');
+    webUIListenerCallback('dictation-locale-menu-subtitle-changed', 'Testing');
     flush();
 
     // Only the dictation locale subtitle should have changed.
@@ -355,7 +355,7 @@
         value: 'fr-FR'
       }
     ];
-    cr.webUIListenerCallback('dictation-locales-set', locales);
+    webUIListenerCallback('dictation-locales-set', locales);
     page.dictationLocaleSubtitleOverride_ = 'Testing';
     flush();
     assertEquals(
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_notification_access_setup_dialog_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_notification_access_setup_dialog_tests.js
index a7527ad..ff726a5 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_notification_access_setup_dialog_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_notification_access_setup_dialog_tests.js
@@ -4,6 +4,7 @@
 
 import {MultiDeviceBrowserProxyImpl, NotificationAccessSetupOperationStatus} from 'chrome://os-settings/chromeos/os_settings.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
@@ -28,8 +29,8 @@
    * @param {NotificationAccessSetupOperationStatus} status
    */
   function simulateStatusChanged(status) {
-    cr.webUIListenerCallback('settings.onNotificationAccessSetupStatusChanged',
-        status);
+    webUIListenerCallback(
+        'settings.onNotificationAccessSetupStatusChanged', status);
     flush();
   }
 
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js
index b7de8ff..95235a3e 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {MultiDeviceBrowserProxyImpl, MultiDeviceFeature, MultiDeviceFeatureState, MultiDevicePageContentData, MultiDeviceSettingsMode, PhoneHubFeatureAccessStatus, Router, routes, setContactManagerForTesting, setNearbyShareSettingsForTesting} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -28,7 +29,7 @@
    * @param {!MultiDevicePageContentData}
    */
   function setPageContentData(newPageContentData) {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.updateMultidevicePageContentData', newPageContentData);
     flush();
   }
@@ -37,9 +38,8 @@
    * Sets screen lock status via WebUI Listener and flushes.
    */
   function setScreenLockStatus(chromeStatus, phoneStatus) {
-    cr.webUIListenerCallback(
-        'settings.OnEnableScreenLockChanged', chromeStatus);
-    cr.webUIListenerCallback('settings.OnScreenLockStatusChanged', phoneStatus);
+    webUIListenerCallback('settings.OnEnableScreenLockChanged', chromeStatus);
+    webUIListenerCallback('settings.OnScreenLockStatusChanged', phoneStatus);
     flush();
   }
 
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js
index 83bcaf6..7df053e1 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js
@@ -4,6 +4,7 @@
 
 import {MultiDeviceBrowserProxyImpl, PermissionsSetupStatus, SetupFlowStatus} from 'chrome://os-settings/chromeos/os_settings.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
@@ -31,7 +32,7 @@
    * @param {PermissionsSetupStatus} status
    */
   function simulateNotificationStatusChanged(status) {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.onNotificationAccessSetupStatusChanged', status);
     flush();
   }
@@ -40,12 +41,12 @@
    * @param {PermissionsSetupStatus} status
    */
   function simulateAppsStatusChanged(status) {
-    cr.webUIListenerCallback('settings.onAppsAccessSetupStatusChanged', status);
+    webUIListenerCallback('settings.onAppsAccessSetupStatusChanged', status);
     flush();
   }
 
   function simulateCombinedStatusChanged(status) {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.onCombinedAccessSetupStatusChanged', status);
     flush();
   }
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_item_test.js b/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_item_test.js
index fa2e78c..aac611d 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_item_test.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_item_test.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {MultiDeviceBrowserProxyImpl, MultiDeviceFeature, MultiDeviceFeatureState, MultiDevicePageContentData, MultiDeviceSettingsMode, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
@@ -24,7 +25,7 @@
    * @param {!MultiDevicePageContentData}
    */
   function setPageContentData(newPageContentData) {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.updateMultidevicePageContentData', newPageContentData);
     flush();
   }
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_subpage_test.js b/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_subpage_test.js
index 9e6ea70..fe685ab 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_subpage_test.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_smartlock_subpage_test.js
@@ -4,6 +4,7 @@
 
 import {MultiDeviceBrowserProxyImpl, MultiDeviceFeatureState, Router, routes, SmartLockSignInEnabledState} from 'chrome://os-settings/chromeos/os_settings.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {eventToPromise, waitAfterNextRender} from 'chrome://test/test_util.js';
@@ -232,7 +233,7 @@
     assertEquals(
         SmartLockSignInEnabledState.DISABLED, smartLockSignInRadio.selected);
 
-    cr.webUIListenerCallback('smart-lock-signin-enabled-changed', true);
+    webUIListenerCallback('smart-lock-signin-enabled-changed', true);
     flush();
 
     assertEquals(
@@ -322,7 +323,7 @@
     smartLockSubPage = createSmartLockSubPage();
 
     // Set sign in as enabled.
-    cr.webUIListenerCallback('smart-lock-signin-enabled-changed', true);
+    webUIListenerCallback('smart-lock-signin-enabled-changed', true);
     flush();
 
     const smartLockSignInRadio = getSmartLockSignInRadio();
@@ -375,7 +376,7 @@
     const smartLockSignInRadio = getSmartLockSignInRadio();
     assertFalse(smartLockSignInRadio.disabled);
 
-    cr.webUIListenerCallback('smart-lock-signin-allowed-changed', false);
+    webUIListenerCallback('smart-lock-signin-allowed-changed', false);
     flush();
 
     assertTrue(smartLockSignInRadio.disabled);
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
index 89ea005b..0fce2ad 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_task_continuation_item_tests.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {SyncBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertFalse, assertTrue} from '../../chai_assert.js';
@@ -40,7 +41,7 @@
     prefs.tabsSynced = false;
     flush();
 
-    cr.webUIListenerCallback('sync-prefs-changed', prefs);
+    webUIListenerCallback('sync-prefs-changed', prefs);
     flush();
 
     assertTrue(!!taskContinuationItem.$$(
@@ -54,7 +55,7 @@
   test('Chrome Sync on', async () => {
     const prefs = getPrefs();
     prefs.tabsSynced = true;
-    cr.webUIListenerCallback('sync-prefs-changed', prefs);
+    webUIListenerCallback('sync-prefs-changed', prefs);
     flush();
 
     assertFalse(!!taskContinuationItem.$$(
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
index 61c9d49..41b6ad6 100644
--- a/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/multidevice_wifi_sync_item_tests.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {OsSyncBrowserProxyImpl, SyncBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.js';
 
@@ -53,7 +54,7 @@
   test('Chrome Sync off', async () => {
     const prefs = getPrefs();
     prefs.wifiConfigurationsSynced = false;
-    cr.webUIListenerCallback('sync-prefs-changed', prefs);
+    webUIListenerCallback('sync-prefs-changed', prefs);
     flush();
 
     assertTrue(
@@ -68,7 +69,7 @@
   test('Chrome Sync on', async () => {
     const prefs = getPrefs();
     prefs.wifiConfigurationsSynced = true;
-    cr.webUIListenerCallback('sync-prefs-changed', prefs);
+    webUIListenerCallback('sync-prefs-changed', prefs);
     flush();
 
     assertFalse(
@@ -114,7 +115,7 @@
   test('Wifi Sync off', async () => {
     const prefs = getOsPrefs();
     prefs.osWifiConfigurationsSynced = false;
-    cr.webUIListenerCallback('os-sync-prefs-changed', prefs);
+    webUIListenerCallback('os-sync-prefs-changed', prefs);
     flush();
 
     assertTrue(
@@ -129,7 +130,7 @@
   test('Wifi Sync on', async () => {
     const prefs = getOsPrefs();
     prefs.osWifiConfigurationsSynced = true;
-    cr.webUIListenerCallback('os-sync-prefs-changed', prefs);
+    webUIListenerCallback('os-sync-prefs-changed', prefs);
     flush();
 
     assertFalse(
diff --git a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
index 38facec9..de7ee54 100644
--- a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
@@ -4,6 +4,7 @@
 
 import {CrPolicyIndicatorType} from '//resources/cr_elements/policy/cr_policy_indicator_behavior.m.js';
 import {AboutPageBrowserProxyImpl, BrowserChannel, DeviceNameBrowserProxyImpl, DeviceNameState, LifetimeBrowserProxyImpl, Router, routes, SetDeviceNameResult, UpdateStatus} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -53,7 +54,7 @@
    */
   function fireStatusChanged(status, opt_options) {
     const options = opt_options || {};
-    cr.webUIListenerCallback('update-status-changed', {
+    webUIListenerCallback('update-status-changed', {
       progress: options.progress === undefined ? 1 : options.progress,
       message: options.message,
       status: status,
@@ -1054,7 +1055,7 @@
    * @return {!Promise}
    */
   function checkDeviceNameMetadata(testDeviceName, deviceNameState) {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.updateDeviceNameMetadata',
         {deviceName: testDeviceName, deviceNameState: deviceNameState});
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_sync_controls_test.js b/chrome/test/data/webui/settings/chromeos/os_sync_controls_test.js
index 6779367..511b84c 100644
--- a/chrome/test/data/webui/settings/chromeos/os_sync_controls_test.js
+++ b/chrome/test/data/webui/settings/chromeos/os_sync_controls_test.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {OsSyncBrowserProxyImpl, Router, StatusAction, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-import {flush} from'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {OsSyncBrowserProxyImpl, Router, routes, StatusAction} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
@@ -71,7 +73,7 @@
 }
 
 function setupSync() {
-  cr.webUIListenerCallback('os-sync-prefs-changed', getSyncAllPrefs());
+  webUIListenerCallback('os-sync-prefs-changed', getSyncAllPrefs());
   flush();
 }
 
@@ -141,7 +143,7 @@
   test('PrefChangeUpdatesControls', function() {
     const prefs = getSyncAllPrefs();
     prefs.syncAllOsTypes = false;
-    cr.webUIListenerCallback('os-sync-prefs-changed', prefs);
+    webUIListenerCallback('os-sync-prefs-changed', prefs);
 
     const datatypeControls = syncControls.shadowRoot.querySelectorAll(
         '.list-item:not([hidden]) > cr-toggle');
diff --git a/chrome/test/data/webui/settings/chromeos/search_engine_test.js b/chrome/test/data/webui/settings/chromeos/search_engine_test.js
index 6f855d4..61fb4f6 100644
--- a/chrome/test/data/webui/settings/chromeos/search_engine_test.js
+++ b/chrome/test/data/webui/settings/chromeos/search_engine_test.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {Router, SearchEnginesBrowserProxy, SearchEnginesBrowserProxyImpl, SearchEnginesInfo} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
@@ -194,7 +195,7 @@
     searchEngineInfo.defaults[1].default = true;
     searchEngineInfo.defaults[2].default = false;
     await browserProxy.whenCalled('setDefaultSearchEngine');
-    cr.webUIListenerCallback('search-engines-changed', searchEngineInfo);
+    webUIListenerCallback('search-engines-changed', searchEngineInfo);
     flush();
 
     // The sublabel should now be updated to the new search engine.
@@ -208,7 +209,7 @@
     searchEngineInfo.defaults[2].default = true;
 
     browserProxy.resetResolver('setDefaultSearchEngine');
-    cr.webUIListenerCallback('search-engines-changed', searchEngineInfo);
+    webUIListenerCallback('search-engines-changed', searchEngineInfo);
     flush();
     assertEquals(
         searchEngineInfo.defaults[2].name,
diff --git a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
index f35ff92d..9845806 100644
--- a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {SmbBrowserProxyImpl, SmbMountResult} from 'chrome://os-settings/chromeos/lazy_load.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {assertFalse, assertTrue} from '../../chai_assert.js';
@@ -275,10 +276,10 @@
 
     await smbBrowserProxy.whenCalled('startDiscovery');
 
-    cr.webUIListenerCallback('on-shares-found', ['smb://foo/bar'], false);
+    webUIListenerCallback('on-shares-found', ['smb://foo/bar'], false);
     assertTrue(url.showLoading);
 
-    cr.webUIListenerCallback('on-shares-found', ['smb://foo/bar2'], true);
+    webUIListenerCallback('on-shares-found', ['smb://foo/bar2'], true);
     assertFalse(url.showLoading);
 
     assertEquals(2, url.items.length);
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_setup_guide_dialog_test.js b/chrome/test/data/webui/settings/chromeos/switch_access_setup_guide_dialog_test.js
index 98b3cbdd..ebbacb9 100644
--- a/chrome/test/data/webui/settings/chromeos/switch_access_setup_guide_dialog_test.js
+++ b/chrome/test/data/webui/settings/chromeos/switch_access_setup_guide_dialog_test.js
@@ -4,9 +4,11 @@
 
 import 'chrome://os-settings/chromeos/lazy_load.js';
 
-import {assertTrue, assertFalse} from '../../chai_assert.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {assertFalse, assertTrue} from '../../chai_assert.js';
+
 suite('SwitchAccessSetupGuideDialogTest', function() {
   /** @type {SettingsSwitchAccessSetupGuideDialog} */
   let dialog;
@@ -383,7 +385,7 @@
     assertEquals('select', assignContents.firstChild.action);
 
     // Simulate the pane exiting without successfully assigning a switch.
-    cr.webUIListenerCallback('exit-pane');
+    webUIListenerCallback('exit-pane');
 
     // Confirm the page has not changed and the pane was loaded.
     assertEquals(/*Assign select=*/ 1, dialog.currentPageId_);
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
index 83175f529..c3ff0b9 100644
--- a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
@@ -4,14 +4,16 @@
 
 import 'chrome://os-settings/chromeos/lazy_load.js';
 
-import {SwitchAccessSubpageBrowserProxyImpl, SwitchAccessSubpageBrowserProxy, routes, Router} from 'chrome://os-settings/chromeos/os_settings.js';
+import {Router, routes, SwitchAccessSubpageBrowserProxy, SwitchAccessSubpageBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {TestBrowserProxy} from '../../test_browser_proxy.js';
-import {assertEquals, assertDeepEquals} from '../../chai_assert.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {waitAfterNextRender} from 'chrome://test/test_util.js';
 
+import {assertDeepEquals, assertEquals} from '../../chai_assert.js';
+import {TestBrowserProxy} from '../../test_browser_proxy.js';
+
 /**
  * @implements {SwitchAccessSubpageBrowserProxy}
  */
@@ -116,7 +118,7 @@
    * @return {string} Sub-label text from the select link row.
    */
   function getSublabelForSelectUpdates(keys) {
-    cr.webUIListenerCallback('switch-access-assignments-changed', {
+    webUIListenerCallback('switch-access-assignments-changed', {
       select: keys.map(key => ({key, device: 'usb'})),
       next: [],
       previous: []
@@ -136,7 +138,7 @@
     assertEquals(0, page.previousAssignments_.length);
 
     // Simulate a pref change for the select action.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-assignments-changed',
         {select: [{key: 'a', device: 'usb'}], next: [], previous: []});
 
@@ -188,15 +190,15 @@
 
     // Make sure we populate the initial |keyCodes_| state on the
     // SwitchAccessActionAssignmentDialog.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-assignments-changed',
         {select: [], next: [], previous: []});
 
     // Simulate pressing 'a' twice.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-got-key-press-for-assignment',
         {key: 'a', keyCode: 65, device: 'usb'});
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-got-key-press-for-assignment',
         {key: 'a', keyCode: 65, device: 'usb'});
 
@@ -215,10 +217,10 @@
         'notifySwitchAccessActionAssignmentPaneActive');
 
     // Simulate pressing 'a', and then 'b'.
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-got-key-press-for-assignment',
         {key: 'a', keyCode: 65, device: 'usb'});
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'switch-access-got-key-press-for-assignment',
         {key: 'b', keyCode: 66, device: 'usb'});
 
diff --git a/chrome/test/data/webui/settings/chromeos/test_about_page_browser_proxy_chromeos.js b/chrome/test/data/webui/settings/chromeos/test_about_page_browser_proxy_chromeos.js
index aa3c3d9..53269ca 100644
--- a/chrome/test/data/webui/settings/chromeos/test_about_page_browser_proxy_chromeos.js
+++ b/chrome/test/data/webui/settings/chromeos/test_about_page_browser_proxy_chromeos.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {BrowserChannel, UpdateStatus} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
-import {BrowserChannel,UpdateStatus} from 'chrome://os-settings/chromeos/os_settings.js';
 
 /** @implements {AboutPageBrowserProxy} */
 export class TestAboutPageBrowserProxyChromeOS extends TestBrowserProxy {
@@ -83,7 +85,7 @@
   }
 
   sendStatusNoInternet() {
-    cr.webUIListenerCallback('update-status-changed', {
+    webUIListenerCallback('update-status-changed', {
       progress: 0,
       status: UpdateStatus.FAILED,
       message: 'offline',
@@ -109,7 +111,7 @@
   /** @override */
   refreshUpdateStatus() {
     if (this.sendUpdateStatus_) {
-      cr.webUIListenerCallback('update-status-changed', {
+      webUIListenerCallback('update-status-changed', {
         progress: 1,
         status: this.updateStatus_,
       });
@@ -210,7 +212,7 @@
   /** @override */
   refreshTPMFirmwareUpdateStatus() {
     this.methodCalled('refreshTPMFirmwareUpdateStatus');
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'tpm-firmware-update-status-changed', this.tpmFirmwareUpdateStatus_);
   }
 
diff --git a/chrome/test/data/webui/settings/chromeos/test_android_apps_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_android_apps_browser_proxy.js
index b80d5bc..23c46a7 100644
--- a/chrome/test/data/webui/settings/chromeos/test_android_apps_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_android_apps_browser_proxy.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
 /** @implements {AndroidAppsBrowserProxy} */
@@ -31,6 +33,6 @@
       playStoreEnabled: playStoreEnabled,
       settingsAppAvailable: settingsAppAvailable,
     };
-    cr.webUIListenerCallback('android-apps-info-update', appsInfo);
+    webUIListenerCallback('android-apps-info-update', appsInfo);
   }
 }
diff --git a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
index 429f2209..7edef58 100644
--- a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
 /** @implements {CrostiniBrowserProxy} */
@@ -93,12 +95,12 @@
   /** @override */
   requestCrostiniInstallerStatus() {
     this.methodCalled('requestCrostiniInstallerStatus');
-    cr.webUIListenerCallback('crostini-installer-status-changed', false);
+    webUIListenerCallback('crostini-installer-status-changed', false);
   }
 
   /** @override */
   requestCrostiniExportImportOperationStatus() {
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'crostini-export-import-operation-status-changed', false);
   }
 
@@ -119,13 +121,12 @@
 
   /** @override */
   requestCrostiniUpgraderDialogStatus() {
-    cr.webUIListenerCallback('crostini-upgrader-status-changed', false);
+    webUIListenerCallback('crostini-upgrader-status-changed', false);
   }
 
   /** @override */
   requestCrostiniContainerUpgradeAvailable() {
-    cr.webUIListenerCallback(
-        'crostini-container-upgrade-available-changed', true);
+    webUIListenerCallback('crostini-container-upgrade-available-changed', true);
   }
 
   /** @override */
@@ -218,7 +219,7 @@
   /** @override */
   requestContainerInfo() {
     this.methodCalled('requestContainerInfo');
-    cr.webUIListenerCallback('crostini-container-info', this.containerInfo);
+    webUIListenerCallback('crostini-container-info', this.containerInfo);
   }
 
   /** @override */
diff --git a/chrome/test/data/webui/settings/chromeos/test_guest_os_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_guest_os_browser_proxy.js
index 5d92878..b142a25 100644
--- a/chrome/test/data/webui/settings/chromeos/test_guest_os_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_guest_os_browser_proxy.js
@@ -4,6 +4,8 @@
 
 import 'chrome://os-settings/chromeos/os_settings.js';
 
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
 /** @implements {GuestOsBrowserProxy} */
@@ -29,7 +31,7 @@
   /** @override */
   notifyGuestOsSharedUsbDevicesPageReady() {
     this.methodCalled('notifyGuestOsSharedUsbDevicesPageReady');
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'guest-os-shared-usb-devices-changed', this.sharedUsbDevices);
   }
 
diff --git a/chrome/test/data/webui/settings/chromeos/test_multidevice_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_multidevice_browser_proxy.js
index 32fb828..5f8ed791 100644
--- a/chrome/test/data/webui/settings/chromeos/test_multidevice_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_multidevice_browser_proxy.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {MultiDeviceFeature, MultiDevicePageContentData, MultiDeviceSettingsMode} from 'chrome://os-settings/chromeos/os_settings.js';
+import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 
 import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
@@ -83,7 +84,7 @@
         'setFeatureEnabledState', [feature, enabled, opt_authToken]);
     if (feature === MultiDeviceFeature.MESSAGES) {
       this.androidSmsInfo.enabled = enabled;
-      cr.webUIListenerCallback(
+      webUIListenerCallback(
           'settings.onAndroidSmsInfoChange', this.androidSmsInfo);
     }
   }
@@ -102,7 +103,7 @@
   /** @override */
   setSmartLockSignInEnabled(enabled, opt_authToken) {
     this.methodCalled('setSmartLockSignInEnabled', [enabled, opt_authToken]);
-    cr.webUIListenerCallback('smart-lock-signin-enabled-changed', enabled);
+    webUIListenerCallback('smart-lock-signin-enabled-changed', enabled);
   }
 
   /** @override */
@@ -153,7 +154,7 @@
    */
   setInstantTetheringStateForTest(state) {
     this.data.instantTetheringState = state;
-    cr.webUIListenerCallback(
+    webUIListenerCallback(
         'settings.updateMultidevicePageContentData',
         Object.assign({}, this.data));
   }
diff --git a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
index d3e05e1..80764fc 100644
--- a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
@@ -9,6 +9,15 @@
 import test_util
 
 
+def getElementFromShadowRoot(driver, element, selector):
+  if element is None:
+    return None
+  else:
+    return driver.execute_script(
+        "return arguments[0].shadowRoot.querySelector(arguments[1])", element,
+        selector)
+
+
 def main(argv):
   options = webdriver.ChromeOptions()
   os.environ["CHROME_LOG_FILE"] = r"c:\temp\chrome_log.txt"
@@ -22,10 +31,15 @@
     policy_url = "chrome://policy"
     driver.get(policy_url)
     driver.find_element_by_id('reload-policies').click
-    print(driver.find_element_by_class_name('legend').text)
-    print(driver.find_element_by_class_name('machine-enrollment-name').text)
-    print(driver.find_element_by_class_name('machine-enrollment-token').text)
-    print(driver.find_element_by_class_name('status').text)
+    # Give the page 2 seconds to render the legend
+    time.sleep(2)
+    status_box = driver.find_element_by_css_selector("status-box")
+    el = getElementFromShadowRoot(driver, status_box, "fieldset")
+
+    print(el.find_element_by_class_name('legend').text)
+    print(el.find_element_by_class_name('machine-enrollment-name').text)
+    print(el.find_element_by_class_name('machine-enrollment-token').text)
+    print(el.find_element_by_class_name('status').text)
   except Exception as error:
     print(error)
   finally:
diff --git a/chrome/utility/importer/bookmark_html_reader.cc b/chrome/utility/importer/bookmark_html_reader.cc
index e76e8cb0..bcf37cb 100644
--- a/chrome/utility/importer/bookmark_html_reader.cc
+++ b/chrome/utility/importer/bookmark_html_reader.cc
@@ -360,7 +360,7 @@
   }
 
   if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
-      base::LowerCaseEqualsASCII(value, "true"))
+      base::EqualsCaseInsensitiveASCII(value, "true"))
     *is_toolbar_folder = true;
   else
     *is_toolbar_folder = false;
diff --git a/chrome/utility/importer/ie_importer_win.cc b/chrome/utility/importer/ie_importer_win.cc
index c518c24..f5d3e12 100644
--- a/chrome/utility/importer/ie_importer_win.cc
+++ b/chrome/utility/importer/ie_importer_win.cc
@@ -668,7 +668,7 @@
   for (std::vector<base::FilePath::StringType>::iterator it = file_list.begin();
        it != file_list.end(); ++it) {
     base::FilePath shortcut(*it);
-    if (!base::LowerCaseEqualsASCII(shortcut.Extension(), ".url"))
+    if (!base::EqualsCaseInsensitiveASCII(shortcut.Extension(), ".url"))
       continue;
 
     // Skip the bookmark with invalid URL.
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc
index 85475c06..b3519fd5 100644
--- a/chromecast/app/cast_main_delegate.cc
+++ b/chromecast/app/cast_main_delegate.cc
@@ -232,11 +232,16 @@
 }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
-bool CastMainDelegate::ShouldCreateFeatureList() {
-  return false;
+bool CastMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
+  return invoked_in == InvokedIn::kChildProcess;
 }
 
-void CastMainDelegate::PostEarlyInitialization(bool is_running_tests) {
+void CastMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
+  if (ShouldCreateFeatureList(invoked_in)) {
+    // content is handling the feature list.
+    return;
+  }
+
   DCHECK(cast_feature_list_creator_);
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -253,7 +258,7 @@
   //
   // The FieldTrialList is a dependency of the feature list. In tests, it is
   // constructed as part of the test suite.
-  if (is_running_tests) {
+  if (invoked_in == InvokedIn::kBrowserProcessUnderTest) {
     DCHECK(base::FieldTrialList::GetInstance());
   } else {
     // This is intentionally leaked since it needs to live for the duration of
diff --git a/chromecast/app/cast_main_delegate.h b/chromecast/app/cast_main_delegate.h
index 7372eb2..14411db 100644
--- a/chromecast/app/cast_main_delegate.h
+++ b/chromecast/app/cast_main_delegate.h
@@ -45,8 +45,8 @@
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   void ZygoteForked() override;
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  bool ShouldCreateFeatureList() override;
-  void PostEarlyInitialization(bool is_running_tests) override;
+  bool ShouldCreateFeatureList(InvokedIn invoked_in) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
   content::ContentClient* CreateContentClient() override;
   content::ContentBrowserClient* CreateContentBrowserClient() override;
   content::ContentGpuClient* CreateContentGpuClient() override;
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 84b63cb..3f6cd46 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -2097,10 +2097,10 @@
         Google Photos
       </message>
       <message name="IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR" desc="Message for the error shown when something goes wrong in the Google Photos page in the wallpaper app.">
-        Something went wrong.
+        Couldn’t load images. Check your network connection or try loading the images again.
       </message>
-      <message name="IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_RETRY" desc="Message for the retry button shown when something goes wrong in the Google Photos page in the wallpaper app.">
-        Retry
+      <message name="IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_TRY_AGAIN" desc="Message for the try again button shown when something goes wrong in the Google Photos page in the wallpaper app.">
+        Try again
       </message>
       <message name="IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ALBUMS_TAB" desc="Label for the Albums tab in the Google Photos page in the wallpaper app.">
         Albums
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR.png.sha1
index 0a8b58d..89c20319 100644
--- a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR.png.sha1
+++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_ERROR.png.sha1
@@ -1 +1 @@
-250db3591ec84fbe90201b47549020a5ac3a24d9
\ No newline at end of file
+7bde929a4bddf71a45314482e7ddf5ff6a43b9b0
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_RETRY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_RETRY.png.sha1
deleted file mode 100644
index 0a8b58d..0000000
--- a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_RETRY.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-250db3591ec84fbe90201b47549020a5ac3a24d9
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_TRY_AGAIN.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_TRY_AGAIN.png.sha1
new file mode 100644
index 0000000..89c20319
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_GOOGLE_PHOTOS_TRY_AGAIN.png.sha1
@@ -0,0 +1 @@
+7bde929a4bddf71a45314482e7ddf5ff6a43b9b0
\ No newline at end of file
diff --git a/components/breadcrumbs/core/application_breadcrumbs_logger.cc b/components/breadcrumbs/core/application_breadcrumbs_logger.cc
index 6f31c59..577fe8fe 100644
--- a/components/breadcrumbs/core/application_breadcrumbs_logger.cc
+++ b/components/breadcrumbs/core/application_breadcrumbs_logger.cc
@@ -81,7 +81,7 @@
 
 void ApplicationBreadcrumbsLogger::OnMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
-  std::string pressure_string = "";
+  const char* pressure_string = "";
   switch (memory_pressure_level) {
     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
       pressure_string = "None";
@@ -94,7 +94,7 @@
       break;
   }
 
-  AddEvent(base::StringPrintf("Memory Pressure: %s", pressure_string.c_str()));
+  AddEvent(base::StringPrintf("Memory Pressure: %s", pressure_string));
 }
 
 bool ApplicationBreadcrumbsLogger::IsUserTriggeredAction(
diff --git a/components/browser_ui/accessibility/android/BUILD.gn b/components/browser_ui/accessibility/android/BUILD.gn
index 4c10b7f..2eed362 100644
--- a/components/browser_ui/accessibility/android/BUILD.gn
+++ b/components/browser_ui/accessibility/android/BUILD.gn
@@ -60,9 +60,6 @@
   sources = [
     "java/res/drawable/ic_zoom.xml",
     "java/res/drawable/page_zoom_background.xml",
-    "java/res/drawable/page_zoom_seekbar_progress.xml",
-    "java/res/drawable/page_zoom_seekbar_thumb.xml",
-    "java/res/drawable/page_zoom_seekbar_track.xml",
     "java/res/layout/custom_preference.xml",
     "java/res/layout/page_zoom_preference.xml",
     "java/res/layout/page_zoom_view.xml",
diff --git a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_progress.xml b/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_progress.xml
deleted file mode 100644
index 2c373a12..0000000
--- a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_progress.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item>
-        <clip>
-            <shape android:shape="rectangle">
-                <solid android:color="@macro/default_icon_color_accent1"/>
-                <corners android:bottomLeftRadius="18dp"
-                    android:topLeftRadius="18dp" />
-                <size
-                    android:width="36dp"
-                    android:height="36dp"/>
-            </shape>
-        </clip>
-    </item>
-
-</layer-list>
diff --git a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_thumb.xml b/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_thumb.xml
deleted file mode 100644
index 7cee45f..0000000
--- a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_thumb.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
-    <item>
-        <shape android:shape="rectangle" >
-            <corners android:radius="18dp"/>
-            <size
-                android:width="36dp"
-                android:height="36dp"/>
-            <solid android:color="@macro/default_icon_color_accent1"/>
-        </shape>
-    </item>
-
-    <item android:id="@+id/page_zoom_current_value_thumb_icon"
-        android:drawable="@drawable/ic_zoom"
-        android:top="4dp"
-        android:bottom="4dp"
-        android:left="4dp"
-        android:right="4dp" >
-    </item>
-
-</layer-list>
-
diff --git a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_track.xml b/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_track.xml
deleted file mode 100644
index 52d0365..0000000
--- a/components/browser_ui/accessibility/android/java/res/drawable/page_zoom_seekbar_track.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <solid android:color="@macro/divider_line_bg_color" />
-    <corners android:radius="2dp" />
-    <stroke android:color="@macro/default_bg_color" android:width="15dp" />
-</shape>
\ No newline at end of file
diff --git a/components/browser_ui/accessibility/android/java/res/layout/page_zoom_view.xml b/components/browser_ui/accessibility/android/java/res/layout/page_zoom_view.xml
index 920a732e..d40fd6d9 100644
--- a/components/browser_ui/accessibility/android/java/res/layout/page_zoom_view.xml
+++ b/components/browser_ui/accessibility/android/java/res/layout/page_zoom_view.xml
@@ -25,12 +25,6 @@
         android:id="@+id/page_zoom_slider"
         android:layout_width="0dp"
         android:layout_weight="1"
-        android:paddingStart="0dp"
-        android:paddingEnd="0dp"
-        android:background="@drawable/page_zoom_seekbar_track"
-        android:progressDrawable="@drawable/page_zoom_seekbar_progress"
-        android:thumb="@drawable/page_zoom_seekbar_thumb"
-        android:splitTrack="false"
         android:layout_height="wrap_content" />
 
     <org.chromium.ui.widget.ChromeImageButton
diff --git a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomMediator.java b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomMediator.java
index 9ec8e9d32..56491ad 100644
--- a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomMediator.java
+++ b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomMediator.java
@@ -53,7 +53,6 @@
 
         mModel.set(PageZoomProperties.DECREASE_ZOOM_CALLBACK, this::handleDecreaseClicked);
         mModel.set(PageZoomProperties.INCREASE_ZOOM_CALLBACK, this::handleIncreaseClicked);
-        mModel.set(PageZoomProperties.MAXIMUM_ZOOM, AVAILABLE_ZOOM_FACTORS.length - 1);
     }
 
     /**
diff --git a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomPreference.java b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomPreference.java
index 771cf35b..cf8eaa3 100644
--- a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomPreference.java
+++ b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomPreference.java
@@ -15,19 +15,10 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
-import org.chromium.base.MathUtils;
-
 /**
  * Custom preference for the page zoom section of Accessibility Settings.
  */
 public class PageZoomPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
-    // (Somewhat) arbitrary lower and upper bounds of seekbar to fix visual effects.
-    private static final int MINIMUM_SEEK_VALUE = 7;
-    private static final int MAXIMUM_SEEK_VALUE = 93;
-
-    private TextView mCurrentValueText;
-    private SeekBar mCurrentValueSlider;
-
     private int mInitialValue;
 
     public PageZoomPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -47,11 +38,12 @@
         container.setBackground(null);
         container.setPadding(0, top, 0, bot);
 
-        mCurrentValueText = (TextView) holder.findViewById(R.id.page_zoom_current_value_text);
+        TextView mCurrentValueText =
+                (TextView) holder.findViewById(R.id.page_zoom_current_value_text);
         mCurrentValueText.setText(
                 getContext().getResources().getString(R.string.page_zoom_factor, 100));
 
-        mCurrentValueSlider = (SeekBar) holder.findViewById(R.id.page_zoom_slider);
+        SeekBar mCurrentValueSlider = (SeekBar) holder.findViewById(R.id.page_zoom_slider);
         mCurrentValueSlider.setProgress(mInitialValue);
         mCurrentValueSlider.setOnSeekBarChangeListener(this);
     }
@@ -65,10 +57,7 @@
     }
 
     @Override
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        // Clamp progress to approved range to fix visual effects
-        seekBar.setProgress(MathUtils.clamp(progress, MINIMUM_SEEK_VALUE, MAXIMUM_SEEK_VALUE));
-    }
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
 
     @Override
     public void onStartTrackingTouch(SeekBar seekBar) {}
@@ -76,9 +65,6 @@
     @Override
     public void onStopTrackingTouch(SeekBar seekBar) {
         // When a user stops changing the slider value, record the new value in prefs.
-        // Clamp for safety.
-        int newPrefValue =
-                MathUtils.clamp(seekBar.getProgress(), MINIMUM_SEEK_VALUE, MAXIMUM_SEEK_VALUE);
-        callChangeListener(newPrefValue);
+        callChangeListener(seekBar.getProgress());
     }
 }
\ No newline at end of file
diff --git a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomProperties.java b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomProperties.java
index 32ffe15..1190b1a 100644
--- a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomProperties.java
+++ b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomProperties.java
@@ -13,12 +13,11 @@
  * Properties for the page zoom feature.
  */
 class PageZoomProperties {
-    static final WritableIntPropertyKey MAXIMUM_ZOOM = new WritableIntPropertyKey();
     static final WritableIntPropertyKey CURRENT_ZOOM = new WritableIntPropertyKey();
     static final WritableObjectPropertyKey<Callback<Void>> DECREASE_ZOOM_CALLBACK =
             new WritableObjectPropertyKey<Callback<Void>>();
     static final WritableObjectPropertyKey<Callback<Void>> INCREASE_ZOOM_CALLBACK =
             new WritableObjectPropertyKey<Callback<Void>>();
     static final PropertyKey[] ALL_KEYS = {
-            MAXIMUM_ZOOM, CURRENT_ZOOM, DECREASE_ZOOM_CALLBACK, INCREASE_ZOOM_CALLBACK};
+            CURRENT_ZOOM, DECREASE_ZOOM_CALLBACK, INCREASE_ZOOM_CALLBACK};
 }
diff --git a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomViewBinder.java b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomViewBinder.java
index e6f3bb58..a81cccc 100644
--- a/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomViewBinder.java
+++ b/components/browser_ui/accessibility/android/java/src/org/chromium/components/browser_ui/accessibility/PageZoomViewBinder.java
@@ -15,10 +15,7 @@
  */
 class PageZoomViewBinder {
     public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
-        if (PageZoomProperties.MAXIMUM_ZOOM == propertyKey) {
-            ((SeekBar) view.findViewById(R.id.page_zoom_slider))
-                    .setMax(model.get(PageZoomProperties.MAXIMUM_ZOOM));
-        } else if (PageZoomProperties.CURRENT_ZOOM == propertyKey) {
+        if (PageZoomProperties.CURRENT_ZOOM == propertyKey) {
             ((SeekBar) view.findViewById(R.id.page_zoom_slider))
                     .setProgress(model.get(PageZoomProperties.CURRENT_ZOOM));
         } else if (PageZoomProperties.DECREASE_ZOOM_CALLBACK == propertyKey) {
diff --git a/components/cronet/cronet_context.cc b/components/cronet/cronet_context.cc
index 926500f..b6517d4 100644
--- a/components/cronet/cronet_context.cc
+++ b/components/cronet/cronet_context.cc
@@ -868,15 +868,15 @@
 }
 
 base::Value CronetContext::NetworkTasks::GetNetLogInfo() const {
-  base::Value net_info(base::Value::Type::DICTIONARY);
+  base::Value::Dict net_info;
   for (auto& iter : contexts_)
-    net_info.SetKey(base::NumberToString(iter.first),
-                    net::GetNetInfo(iter.second.get()));
+    net_info.Set(base::NumberToString(iter.first),
+                 net::GetNetInfo(iter.second.get()));
   if (!effective_experimental_options_.DictEmpty()) {
-    net_info.SetKey("cronetExperimentalParams",
-                    effective_experimental_options_.Clone());
+    net_info.Set("cronetExperimentalParams",
+                 effective_experimental_options_.Clone());
   }
-  return net_info;
+  return base::Value(std::move(net_info));
 }
 
 }  // namespace cronet
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index 55e20bb..2779d0c 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -214,12 +214,12 @@
 }
 
 base::Value CronetEnvironment::GetNetLogInfo() const {
-  base::Value net_info = net::GetNetInfo(main_context_.get());
+  base::Value::Dict net_info = net::GetNetInfo(main_context_.get());
   if (!effective_experimental_options_.DictEmpty()) {
-    net_info.SetKey("cronetExperimentalParams",
-                    effective_experimental_options_.Clone());
+    net_info.Set("cronetExperimentalParams",
+                 effective_experimental_options_.Clone());
   }
-  return net_info;
+  return base::Value(std::move(net_info));
 }
 
 net::HttpNetworkSession* CronetEnvironment::GetHttpNetworkSession(
diff --git a/components/embedder_support/user_agent_utils.cc b/components/embedder_support/user_agent_utils.cc
index 6e905c33..7f9f64b 100644
--- a/components/embedder_support/user_agent_utils.cc
+++ b/components/embedder_support/user_agent_utils.cc
@@ -164,12 +164,13 @@
 // the minor position.
 // TODO(crbug.com/1290820): Remove this method along with policy.
 bool ShouldForceMajorVersionToMinorPosition(
-    ForceMajorVersionToMinorPosition force_major_to_minor = kDefault) {
+    ForceMajorVersionToMinorPosition force_major_to_minor) {
   return (
-      (force_major_to_minor != kForceDisabled &&
+      (force_major_to_minor !=
+           ForceMajorVersionToMinorPosition::kForceDisabled &&
        base::FeatureList::IsEnabled(
            blink::features::kForceMajorVersionInMinorPositionInUserAgent)) ||
-      force_major_to_minor == kForceEnabled);
+      force_major_to_minor == ForceMajorVersionToMinorPosition::kForceEnabled);
 }
 
 const std::string& GetMajorInMinorVersionNumber() {
@@ -527,7 +528,7 @@
   return GetUserAgentMetadata(nullptr);
 }
 
-blink::UserAgentMetadata GetUserAgentMetadata(PrefService* pref_service) {
+blink::UserAgentMetadata GetUserAgentMetadata(const PrefService* pref_service) {
   blink::UserAgentMetadata metadata;
   bool enable_updated_grease_by_policy = true;
   UserAgentOptions ua_options;
@@ -600,17 +601,17 @@
 
 // TODO(crbug.com/1290820): Remove this function with policy.
 embedder_support::ForceMajorVersionToMinorPosition GetMajorToMinorFromPrefs(
-    PrefService* pref_service) {
+    const PrefService* pref_service) {
   if (!pref_service->HasPrefPath(kForceMajorVersionToMinorPosition))
-    return kDefault;
+    return ForceMajorVersionToMinorPosition::kDefault;
   switch (pref_service->GetInteger(kForceMajorVersionToMinorPosition)) {
     case 1:
-      return kForceDisabled;
+      return ForceMajorVersionToMinorPosition::kForceDisabled;
     case 2:
-      return kForceEnabled;
+      return ForceMajorVersionToMinorPosition::kForceEnabled;
     case 0:
     default:
-      return kDefault;
+      return ForceMajorVersionToMinorPosition::kDefault;
   }
 }
 
diff --git a/components/embedder_support/user_agent_utils.h b/components/embedder_support/user_agent_utils.h
index c6ac743..a345622 100644
--- a/components/embedder_support/user_agent_utils.h
+++ b/components/embedder_support/user_agent_utils.h
@@ -22,10 +22,8 @@
 
 namespace embedder_support {
 
-// TODO(crbug.com/1291612): Move this enum definition to
-// chrome/browser/chrome_content_browser_client.h
 // TODO(crbug.com/1290820): Remove this enum along with policy.
-enum ForceMajorVersionToMinorPosition {
+enum class ForceMajorVersionToMinorPosition {
   kDefault = 0,
   kForceDisabled = 1,
   kForceEnabled = 2,
@@ -33,30 +31,37 @@
 
 struct UserAgentOptions {
   bool force_major_version_100 = false;
-  ForceMajorVersionToMinorPosition force_major_to_minor = kDefault;
+  ForceMajorVersionToMinorPosition force_major_to_minor =
+      ForceMajorVersionToMinorPosition::kDefault;
 };
 
 // Returns the product & version string.  Examples:
-//   "Chrome/101.0.0.0"    -  if UA reduction is enabled
-//   "Chrome/101.0.4698.0" -  if UA reduction is not enabled
+//   "Chrome/101.0.0.0"       - if UA reduction is enabled w/o major to minor
+//   "Chrome/101.0.4698.0"    - if UA reduction isn't enabled w/o major to minor
+//   "Chrome/99.101.0.0"      - if UA reduction is enabled w/ major to minor
+//   "Chrome/99.101.0.4698.0" - if UA reduction isn'n enabled w/ major to minor
+// TODO(crbug.com/1291612): modify to accept an optional PrefService*.
 std::string GetProductAndVersion(
-    ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
+    ForceMajorVersionToMinorPosition force_major_to_minor =
+        ForceMajorVersionToMinorPosition::kDefault);
 
 // Returns the user agent string for Chrome.
 // TODO(crbug.com/1291612): modify to accept an optional PrefService*.
 std::string GetFullUserAgent(
-    ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
+    ForceMajorVersionToMinorPosition force_major_to_minor =
+        ForceMajorVersionToMinorPosition::kDefault);
 
 // Returns the reduced user agent string for Chrome.
 // TODO(crbug.com/1291612): modify to accept an optional PrefService*.
 std::string GetReducedUserAgent(
-    ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
+    ForceMajorVersionToMinorPosition force_major_to_minor =
+        ForceMajorVersionToMinorPosition::kDefault);
 
 // Returns the full or "reduced" user agent string, depending on the
 // UserAgentReduction enterprise policy and blink::features::kReduceUserAgent
 // TODO(crbug.com/1291612): modify to accept an optional PrefService*.
-std::string GetUserAgent(
-    ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
+std::string GetUserAgent(ForceMajorVersionToMinorPosition force_major_to_minor =
+                             ForceMajorVersionToMinorPosition::kDefault);
 
 // Returns UserAgentMetadata per the default policy.
 // This override is currently used in fuchsia, where the enterprise policy
@@ -66,7 +71,7 @@
 // Return UserAgentMetadata, potentially overridden by policy.
 // Note that this override is likely to be removed once an enterprise
 // escape hatch is no longer needed. See https://crbug.com/1261908.
-blink::UserAgentMetadata GetUserAgentMetadata(PrefService* local_state);
+blink::UserAgentMetadata GetUserAgentMetadata(const PrefService* local_state);
 
 // Return UserAgentBrandList based on the expected output version type.
 blink::UserAgentBrandList GenerateBrandVersionList(
@@ -107,7 +112,7 @@
 // the provided integer policy value for ForceMajorVersionToMinorPosition.
 // TODO(crbug.com/1290820): Remove this function with policy.
 embedder_support::ForceMajorVersionToMinorPosition GetMajorToMinorFromPrefs(
-    PrefService* pref_service);
+    const PrefService* pref_service);
 
 }  // namespace embedder_support
 
diff --git a/components/embedder_support/user_agent_utils_unittest.cc b/components/embedder_support/user_agent_utils_unittest.cc
index 910b7ab9..d9a50f7 100644
--- a/components/embedder_support/user_agent_utils_unittest.cc
+++ b/components/embedder_support/user_agent_utils_unittest.cc
@@ -428,7 +428,8 @@
        blink::features::kForceMajorVersionInMinorPositionInUserAgent},
       {});
   {
-    std::string buffer = GetReducedUserAgent(kForceDisabled);
+    std::string buffer =
+        GetReducedUserAgent(ForceMajorVersionToMinorPosition::kForceDisabled);
     std::string device_compat = "Mobile ";
     EXPECT_EQ(buffer,
               base::StringPrintf(content::frozen_user_agent_strings::kAndroid,
@@ -465,7 +466,8 @@
        blink::features::kForceMajorVersionInMinorPositionInUserAgent},
       {});
   {
-    std::string buffer = GetReducedUserAgent(kForceDisabled);
+    std::string buffer =
+        GetReducedUserAgent(ForceMajorVersionToMinorPosition::kForceDisabled);
     EXPECT_EQ(buffer, base::StringPrintf(
                           content::frozen_user_agent_strings::kDesktop,
                           content::GetUnifiedPlatform().c_str(),
@@ -547,7 +549,8 @@
 
   // ForceMajorVersionToMinorPosition: kForceDisabled
   pref_service.registry()->RegisterIntegerPref(
-      kForceMajorVersionToMinorPosition, kForceDisabled);
+      kForceMajorVersionToMinorPosition,
+      static_cast<int>(ForceMajorVersionToMinorPosition::kForceDisabled));
   metadata = GetUserAgentMetadata(&pref_service);
   EXPECT_EQ(metadata.full_version, full_version);
   EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
@@ -569,7 +572,9 @@
                                     major_to_minor_product_brand_full_version));
 
   // ForceMajorVersionToMinorPosition: kForceEnabled
-  pref_service.SetInteger(kForceMajorVersionToMinorPosition, kForceEnabled);
+  pref_service.SetInteger(
+      kForceMajorVersionToMinorPosition,
+      static_cast<int>(ForceMajorVersionToMinorPosition::kForceEnabled));
   metadata = GetUserAgentMetadata(&pref_service);
   EXPECT_EQ(metadata.full_version, major_to_minor_full_version);
   EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
@@ -1007,7 +1012,8 @@
   EXPECT_EQ(minor_version, "0");
 
   // Ensure policy is respected if ForceMajorToMinor is force enabled
-  product = GetProductAndVersion(/*force_major_to_minor=*/kForceEnabled);
+  product =
+      GetProductAndVersion(ForceMajorVersionToMinorPosition::kForceEnabled);
   EXPECT_TRUE(re2::RE2::FullMatch(product, kChromeProductVersionRegex,
                                   &major_version, &minor_version));
   EXPECT_EQ(major_version, "99");
@@ -1038,7 +1044,8 @@
       /*enabled_features=*/{blink::features::
                                 kForceMajorVersionInMinorPositionInUserAgent},
       /*disabled_features=*/{blink::features::kReduceUserAgentMinorVersion});
-  product = GetProductAndVersion(/*force_major_to_minor=*/kForceDisabled);
+  product =
+      GetProductAndVersion(ForceMajorVersionToMinorPosition::kForceDisabled);
   EXPECT_TRUE(re2::RE2::FullMatch(product, kChromeProductVersionRegex,
                                   &major_version, &minor_version,
                                   &build_version));
diff --git a/components/enterprise/browser/controller/browser_dm_token_storage.cc b/components/enterprise/browser/controller/browser_dm_token_storage.cc
index 58f2898..db7ead3 100644
--- a/components/enterprise/browser/controller/browser_dm_token_storage.cc
+++ b/components/enterprise/browser/controller/browser_dm_token_storage.cc
@@ -104,6 +104,8 @@
   store_callback_ = std::move(callback);
 
   if (dm_token.empty()) {
+    // TODO(crbug.com/1318153): Implement DMToken deletion logic once all
+    // delegates have the required handling.
     dm_token_ = CreateEmptyToken();
     SaveDMToken("");
   } else if (dm_token == kInvalidTokenValue) {
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
index e76df99..63e90c8 100644
--- a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
+++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
@@ -272,11 +272,21 @@
   return delegate_->IsEnterpriseStartupDialogShowing();
 }
 
-void ChromeBrowserCloudManagementController::UnenrollBrowser() {
+void ChromeBrowserCloudManagementController::UnenrollBrowser(
+    bool delete_dm_token) {
+  if (delete_dm_token) {
+    DVLOG(1) << "Browser unenrollment: Attempting DMToken deletion";
+    BrowserDMTokenStorage::Get()->ClearDMToken(base::BindOnce(
+        &ChromeBrowserCloudManagementController::UnenrollCallback,
+        weak_factory_.GetWeakPtr()));
+    return;
+  }
+
   // Invalidate DM token in storage.
-  BrowserDMTokenStorage::Get()->InvalidateDMToken(base::BindOnce(
-      &ChromeBrowserCloudManagementController::InvalidateDMTokenCallback,
-      weak_factory_.GetWeakPtr()));
+  DVLOG(1) << "Browser unenrollment: Attempting DMToken invalidation";
+  BrowserDMTokenStorage::Get()->InvalidateDMToken(
+      base::BindOnce(&ChromeBrowserCloudManagementController::UnenrollCallback,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void ChromeBrowserCloudManagementController::InvalidatePolicies() {
@@ -292,17 +302,15 @@
     report_scheduler_->OnDMTokenUpdated();
 }
 
-void ChromeBrowserCloudManagementController::InvalidateDMTokenCallback(
-    bool success) {
+void ChromeBrowserCloudManagementController::UnenrollCallback(bool success) {
   UMA_HISTOGRAM_BOOLEAN(
       "Enterprise.MachineLevelUserCloudPolicyEnrollment.UnenrollSuccess",
       success);
-  if (success) {
-    DVLOG(1) << "Successfully invalidated the DM token";
+  DVLOG(1) << "Browser unenrollment: " << (success ? "Successful" : "Failed");
+
+  if (success)
     InvalidatePolicies();
-  } else {
-    DVLOG(1) << "Failed to invalidate the DM token";
-  }
+
   NotifyBrowserUnenrolled(success);
 }
 
@@ -319,9 +327,15 @@
 void ChromeBrowserCloudManagementController::OnClientError(
     CloudPolicyClient* client) {
   // DM_STATUS_SERVICE_DEVICE_NOT_FOUND being the last status implies the
-  // browser has been unenrolled.
-  if (client->status() == DM_STATUS_SERVICE_DEVICE_NOT_FOUND)
-    UnenrollBrowser();
+  // browser has been unenrolled via DMToken invalidation, so it is not expected
+  // to re-enroll automatically. DM_STATUS_SERVICE_DEVICE_NEEDS_RESET signals
+  // that the browser has been unenrolled via DMToken deletion, and that it will
+  // automatically re-enroll if a valid enrollment token has been set.
+  if (client->status() == DM_STATUS_SERVICE_DEVICE_NOT_FOUND ||
+      client->status() == DM_STATUS_SERVICE_DEVICE_NEEDS_RESET) {
+    UnenrollBrowser(/*delete_dm_token=*/client->status() ==
+                    DM_STATUS_SERVICE_DEVICE_NEEDS_RESET);
+  }
 }
 
 void ChromeBrowserCloudManagementController::OnServiceAccountSet(
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
index 4647534..38d474aa 100644
--- a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
+++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
@@ -232,7 +232,9 @@
   // Returns whether the enterprise startup dialog is being diaplayed.
   bool IsEnterpriseStartupDialogShowing();
 
-  void UnenrollBrowser();
+  // Unenrolls the browser from cloud management by either invalidating or
+  // deleting the stored DMToken.
+  void UnenrollBrowser(bool delete_dm_token);
 
   // CloudPolicyClient::Observer implementation:
   void OnPolicyFetched(CloudPolicyClient* client) override;
@@ -266,7 +268,7 @@
       const std::string& client_id);
 
   void InvalidatePolicies();
-  void InvalidateDMTokenCallback(bool success);
+  void UnenrollCallback(bool success);
 
   void CreateReportScheduler();
 
diff --git a/components/enterprise/browser/reporting/report_uploader_unittest.cc b/components/enterprise/browser/reporting/report_uploader_unittest.cc
index f526eff..741663c 100644
--- a/components/enterprise/browser/reporting/report_uploader_unittest.cc
+++ b/components/enterprise/browser/reporting/report_uploader_unittest.cc
@@ -12,6 +12,7 @@
 #include "build/chromeos_buildflags.h"
 #include "components/enterprise/browser/reporting/report_request.h"
 #include "components/enterprise/browser/reporting/report_type.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "device_management_backend.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -144,11 +145,10 @@
   EXPECT_TRUE(has_responded_);
   histogram_tester_.ExpectUniqueSample(
       kResponseMetricsName, ReportResponseMetricsStatus::kOtherError, 1);
-  ::testing::Mock::VerifyAndClearExpectations(&client_);
 }
 
 TEST_F(ReportUploaderTest, RequestTooBigError) {
-  CreateUploader(/* *retyr_count = */ 2);
+  CreateUploader(/* *retry_count = */ 2);
   EXPECT_CALL(client_, UploadReportProxy(_, _))
       .Times(2)
       .WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 100f5b3..6cf8a12 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -28,6 +28,8 @@
     "wayland_display_observer.h",
     "wayland_display_output.cc",
     "wayland_display_output.h",
+    "wayland_display_util.cc",
+    "wayland_display_util.h",
     "wayland_input_delegate.cc",
     "wayland_input_delegate.h",
     "wayland_pointer_delegate.cc",
@@ -285,6 +287,8 @@
 
   if (is_chromeos_ash) {
     sources += [
+      "wayland_display_observer_unittest.cc",
+      "wayland_display_util_unittest.cc",
       "wayland_keyboard_delegate_unittest.cc",
       "wayland_positioner_unittest.cc",
       "zaura_shell_unittest.cc",
@@ -296,6 +300,7 @@
       "//ash:test_support",
       "//ash/public/cpp",
       "//third_party/wayland-protocols:remote_shell_protocol",
+      "//third_party/wayland-protocols:xdg_output_protocol",
       "//third_party/wayland-protocols:xdg_shell_protocol",
       "//ui/compositor",
       "//ui/compositor:test_support",
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index e5f4e2aa..50f1a59f 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -155,7 +155,7 @@
         wl_registry_bind(registry, id, &wp_presentation_interface, 1)));
   } else if (strcmp(interface, "zaura_shell") == 0) {
     globals->aura_shell.reset(static_cast<zaura_shell*>(
-        wl_registry_bind(registry, id, &zaura_shell_interface, 14)));
+        wl_registry_bind(registry, id, &zaura_shell_interface, 34)));
   } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
     globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>(
         wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 2)));
@@ -923,6 +923,16 @@
     uint32_t modifier_hi,
     uint32_t modifier_lo) {}
 
+////////////////////////////////////////////////////////////////////////////////
+// zaura_output_listener
+
+void ClientBase::HandleInsets(const gfx::Insets& insets) {}
+
+void ClientBase::HandleLogicalTransform(int32_t transform) {}
+
+////////////////////////////////////////////////////////////////////////////////
+// helper functions
+
 std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
     const gfx::Size& size,
     int32_t drm_format,
@@ -1254,7 +1264,13 @@
       [](void* data, struct zaura_shell* zaura_shell, uint32_t layout_mode) {},
       [](void* data, struct zaura_shell* zaura_shell, uint32_t id) {
         CastToClientBase(data)->bug_fix_ids_.insert(id);
-      }};
+      },
+      [](void* data, struct zaura_shell* zaura_shell,
+         struct wl_array* desk_names) {},
+      [](void* data, struct zaura_shell* zaura_shell,
+         int32_t active_desk_index) {},
+      [](void* data, struct zaura_shell* zaura_shell,
+         struct wl_surface* gained_active, struct wl_surface* lost_active) {}};
   zaura_shell_add_listener(globals_.aura_shell.get(), &kAuraShellListener,
                            this);
 
@@ -1266,6 +1282,26 @@
   }
 
   zaura_surface_set_frame(aura_surface.get(), ZAURA_SURFACE_FRAME_TYPE_NORMAL);
+
+  static zaura_output_listener kAuraOutputListener = {
+      [](void* data, struct zaura_output* zaura_output, uint32_t flags,
+         uint32_t scale) {},
+      [](void* data, struct zaura_output* zaura_output, uint32_t connection) {},
+      [](void* data, struct zaura_output* zaura_output, uint32_t scale) {},
+      [](void* data, struct zaura_output* zaura_output, int32_t top,
+         int32_t left, int32_t bottom, int32_t right) {
+        CastToClientBase(data)->HandleInsets(
+            gfx::Insets::TLBR(top, left, bottom, right));
+      },
+      [](void* data, struct zaura_output* zaura_output, int32_t transform) {
+        CastToClientBase(data)->HandleLogicalTransform(transform);
+      },
+  };
+
+  std::unique_ptr<zaura_output> aura_output(zaura_shell_get_aura_output(
+      globals_.aura_shell.get(), globals_.output.get()));
+  zaura_output_add_listener(aura_output.get(), &kAuraOutputListener, this);
+  globals_.aura_output = std::move(aura_output);
 }
 
 void ClientBase::SetupPointerStylus() {
diff --git a/components/exo/wayland/clients/client_base.h b/components/exo/wayland/clients/client_base.h
index b4e47bd..8b5fb7d 100644
--- a/components/exo/wayland/clients/client_base.h
+++ b/components/exo/wayland/clients/client_base.h
@@ -15,6 +15,7 @@
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_surface.h"
@@ -85,6 +86,7 @@
     std::unique_ptr<wl_subcompositor> subcompositor;
     std::unique_ptr<wl_touch> touch;
     std::unique_ptr<zaura_shell> aura_shell;
+    std::unique_ptr<zaura_output> aura_output;
     std::unique_ptr<zxdg_shell_v6> xdg_shell_v6;
     std::unique_ptr<xdg_wm_base> xdg_wm_base;
     std::unique_ptr<zwp_fullscreen_shell_v1> fullscreen_shell;
@@ -204,6 +206,10 @@
       uint32_t modifier_hi,
       uint32_t modifier_lo);
 
+  // zaura_output_listener
+  virtual void HandleInsets(const gfx::Insets& insets);
+  virtual void HandleLogicalTransform(int32_t transform);
+
   gfx::Size size_ = gfx::Size(256, 256);
   int scale_ = 1;
   int transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
diff --git a/components/exo/wayland/clients/info.cc b/components/exo/wayland/clients/info.cc
index 1e97fac3..6e21614 100644
--- a/components/exo/wayland/clients/info.cc
+++ b/components/exo/wayland/clients/info.cc
@@ -43,6 +43,10 @@
   };
   // |next_scales| are swapped with |scales| after receiving output done event.
   std::vector<Scale> scales, next_scales;
+  struct {
+    int32_t top, left, bottom, right;
+  } insets;
+  int32_t logical_transform;
   std::unique_ptr<wl_output> output;
   std::unique_ptr<zaura_output> aura_output;
 };
@@ -155,6 +159,25 @@
   info->device_scale_factor = device_scale_factor;
 }
 
+void AuraOutputInsets(void* data,
+                      zaura_output* output,
+                      int32_t top,
+                      int32_t left,
+                      int32_t bottom,
+                      int32_t right) {
+  Info* info = static_cast<Info*>(data);
+
+  info->insets = {top, left, bottom, right};
+}
+
+void AuraOutputLogicalTransform(void* data,
+                                zaura_output* output,
+                                int32_t transform) {
+  Info* info = static_cast<Info*>(data);
+
+  info->logical_transform = transform;
+}
+
 std::string OutputSubpixelToString(int32_t subpixel) {
   switch (subpixel) {
     case WL_OUTPUT_SUBPIXEL_UNKNOWN:
@@ -293,7 +316,8 @@
                                         OutputScale};
 
   zaura_output_listener aura_output_listener = {
-      AuraOutputScale, AuraOutputConnection, AuraOutputDeviceScaleFactor};
+      AuraOutputScale, AuraOutputConnection, AuraOutputDeviceScaleFactor,
+      AuraOutputInsets, AuraOutputLogicalTransform};
   for (auto& info : globals.outputs) {
     wl_output_add_listener(info.output.get(), &output_listener, &info);
     if (globals.aura_shell) {
@@ -349,6 +373,14 @@
                   << AuraOutputScaleFlagsToString(scale.flags) << std::endl;
       }
     }
+    std::cout << "  insets:" << std::endl
+              << "    top:     " << info.insets.top << std::endl
+              << "    left:    " << info.insets.left << std::endl
+              << "    bottom:  " << info.insets.bottom << std::endl
+              << "    right:   " << info.insets.right << std::endl
+              << std::endl;
+    std::cout << "  logical_transform: "
+              << OutputTransformToString(info.logical_transform) << std::endl;
   }
 
   return 0;
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml
index 44ae6eae..cdfad46 100644
--- a/components/exo/wayland/protocol/aura-shell.xml
+++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
     DEALINGS IN THE SOFTWARE.
   </copyright>
 
-  <interface name="zaura_shell" version="32">
+  <interface name="zaura_shell" version="34">
     <description summary="aura_shell">
       The global interface exposing aura shell capabilities is used to
       instantiate an interface extension for a wl_surface object.
@@ -512,7 +512,7 @@
     </event>
   </interface>
 
-  <interface name="zaura_output" version="6">
+  <interface name="zaura_output" version="34">
     <description summary="aura shell interface to a wl_output">
       An additional interface to a wl_output object, which allows the
       client to access aura shell specific functionality for output.
@@ -614,7 +614,38 @@
       </description>
       <arg name="scale" type="uint" enum="scale_factor" summary="output device scale factor"/>
     </event>
- </interface>
+
+    <!-- Version 33 additions -->
+
+    <event name="insets" since="33">
+      <description summary="advertise the insets for the output">
+        This event describes the insets for the output in logical screen
+        coordinates, from which the work area can be calculated.
+
+        This event is sent before wl_output.done, after which the client would
+        apply the change.
+      </description>
+      <arg name="top" type="int"/>
+      <arg name="left" type="int"/>
+      <arg name="bottom" type="int"/>
+      <arg name="right" type="int"/>
+    </event>
+
+    <!-- Version 34 additions -->
+
+    <event name="logical_transform" since="34">
+      <description summary="advertise the output's logical transform">
+        This event describes the logical transform for the output. Whereas
+        wl_output.geometry's transform corresponds to the display's panel
+        rotation, the logical transform corresponds to the display's logical
+        rotation.
+
+        This event is sent before wl_output.done, after which the client would
+        apply the change.
+      </description>
+      <arg name="transform" type="int" enum="wl_output.transform"/>
+    </event>
+  </interface>
 
   <interface name="zaura_toplevel" version="32">
     <description summary="aura shell interface to the toplevel shell">
diff --git a/components/exo/wayland/wayland_display_observer.cc b/components/exo/wayland/wayland_display_observer.cc
index 24cf454..5d91b1b 100644
--- a/components/exo/wayland/wayland_display_observer.cc
+++ b/components/exo/wayland/wayland_display_observer.cc
@@ -12,6 +12,7 @@
 #include "chrome-color-management-server-protocol.h"
 #include "components/exo/wayland/server_util.h"
 #include "components/exo/wayland/wayland_display_output.h"
+#include "components/exo/wayland/wayland_display_util.h"
 #include "components/exo/wayland/zcr_color_manager.h"
 #include "components/exo/wm_helper.h"
 #include "ui/display/display_observer.h"
@@ -139,6 +140,17 @@
   color_management_output_resource_ = nullptr;
 }
 
+void WaylandDisplayHandler::XdgOutputSendLogicalPosition(
+    const gfx::Point& position) {
+  zxdg_output_v1_send_logical_position(xdg_output_resource_, position.x(),
+                                       position.y());
+}
+
+void WaylandDisplayHandler::XdgOutputSendLogicalSize(const gfx::Size& size) {
+  zxdg_output_v1_send_logical_size(xdg_output_resource_, size.width(),
+                                   size.height());
+}
+
 bool WaylandDisplayHandler::SendDisplayMetrics(const display::Display& display,
                                                uint32_t changed_metrics) {
   if (!output_resource_)
@@ -205,10 +217,8 @@
                       static_cast<int>(60000));
 
   if (xdg_output_resource_) {
-    const gfx::Size logical_size = ScaleToRoundedSize(
-        physical_size_px, 1.0f / display.device_scale_factor());
-    zxdg_output_v1_send_logical_size(xdg_output_resource_, logical_size.width(),
-                                     logical_size.height());
+    XdgOutputSendLogicalPosition(origin);
+    XdgOutputSendLogicalSize(display.bounds().size());
   } else {
     if (wl_resource_get_version(output_resource_) >=
         WL_OUTPUT_SCALE_SINCE_VERSION) {
@@ -222,24 +232,5 @@
   return true;
 }
 
-wl_output_transform WaylandDisplayHandler::OutputTransform(
-    display::Display::Rotation rotation) {
-  // Note: |rotation| describes the counter clockwise rotation that a
-  // display's output is currently adjusted for, which is the inverse
-  // of what we need to return.
-  switch (rotation) {
-    case display::Display::ROTATE_0:
-      return WL_OUTPUT_TRANSFORM_NORMAL;
-    case display::Display::ROTATE_90:
-      return WL_OUTPUT_TRANSFORM_270;
-    case display::Display::ROTATE_180:
-      return WL_OUTPUT_TRANSFORM_180;
-    case display::Display::ROTATE_270:
-      return WL_OUTPUT_TRANSFORM_90;
-  }
-  NOTREACHED();
-  return WL_OUTPUT_TRANSFORM_NORMAL;
-}
-
 }  // namespace wayland
 }  // namespace exo
diff --git a/components/exo/wayland/wayland_display_observer.h b/components/exo/wayland/wayland_display_observer.h
index ef9afc8..5796e4e 100644
--- a/components/exo/wayland/wayland_display_observer.h
+++ b/components/exo/wayland/wayland_display_observer.h
@@ -68,15 +68,15 @@
  protected:
   wl_resource* output_resource() const { return output_resource_; }
 
+  // Overridable for testing.
+  virtual void XdgOutputSendLogicalPosition(const gfx::Point& position);
+  virtual void XdgOutputSendLogicalSize(const gfx::Size& size);
+
  private:
   // Overridden from WaylandDisplayObserver:
   bool SendDisplayMetrics(const display::Display& display,
                           uint32_t changed_metrics) override;
 
-  // Returns the transform that a compositor will apply to a surface to
-  // compensate for the rotation of an output device.
-  wl_output_transform OutputTransform(display::Display::Rotation rotation);
-
   // Output.
   WaylandDisplayOutput* output_;
 
diff --git a/components/exo/wayland/wayland_display_observer_unittest.cc b/components/exo/wayland/wayland_display_observer_unittest.cc
new file mode 100644
index 0000000..0ac5f1f
--- /dev/null
+++ b/components/exo/wayland/wayland_display_observer_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/wayland/wayland_display_observer.h"
+
+#include <sys/socket.h>
+#include <wayland-server-protocol-core.h>
+#include <xdg-output-unstable-v1-server-protocol.h>
+
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/wayland/wayland_display_output.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace exo {
+namespace wayland {
+namespace {
+
+class MockWaylandDisplayHandler : public WaylandDisplayHandler {
+ public:
+  using WaylandDisplayHandler::WaylandDisplayHandler;
+  MockWaylandDisplayHandler(const MockWaylandDisplayHandler&) = delete;
+  MockWaylandDisplayHandler& operator=(const MockWaylandDisplayHandler&) =
+      delete;
+  ~MockWaylandDisplayHandler() override = default;
+
+  MOCK_METHOD(void,
+              XdgOutputSendLogicalPosition,
+              (const gfx::Point&),
+              (override));
+  MOCK_METHOD(void, XdgOutputSendLogicalSize, (const gfx::Size&), (override));
+};
+
+class WaylandDisplayObserverTest : public test::ExoTestBase {
+ protected:
+  constexpr uint32_t kAllChanges = 0xFFFFFFFF;
+
+  void SetUp() override {
+    test::ExoTestBase::SetUp();
+
+    ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds_), 0);
+    wayland_display_ = wl_display_create();
+    client_ = wl_client_create(wayland_display_, fds_[0]);
+    wl_output_resource_ =
+        wl_resource_create(client_, &wl_output_interface, 2, 0);
+    xdg_output_resource_ =
+        wl_resource_create(client_, &zxdg_output_v1_interface, 2, 0);
+    output_ = std::make_unique<WaylandDisplayOutput>(GetPrimaryDisplay().id());
+    handler_ = std::make_unique<::testing::NiceMock<MockWaylandDisplayHandler>>(
+        output_.get(), wl_output_resource_);
+    handler_->OnXdgOutputCreated(xdg_output_resource_);
+    handler_->Initialize();
+  }
+
+  void TearDown() override {
+    wl_resource_destroy(xdg_output_resource_);
+    wl_resource_destroy(wl_output_resource_);
+    wl_client_destroy(client_);
+    wl_display_destroy(wayland_display_);
+    close(fds_[1]);
+
+    test::ExoTestBase::TearDown();
+  }
+
+  int fds_[2] = {0, 0};
+  wl_display* wayland_display_ = nullptr;
+  wl_client* client_ = nullptr;
+  wl_resource* wl_output_resource_ = nullptr;
+  wl_resource* xdg_output_resource_ = nullptr;
+  std::unique_ptr<WaylandDisplayOutput> output_;
+  std::unique_ptr<MockWaylandDisplayHandler> handler_;
+};
+
+TEST_F(WaylandDisplayObserverTest, SendLogicalPositionAndSize) {
+  constexpr gfx::Point kExpectedOrigin(10, 20);
+  constexpr gfx::Size kExpectedSize(800, 600);
+  constexpr gfx::Rect kExpectedBounds(kExpectedOrigin, kExpectedSize);
+  display::Display display(GetPrimaryDisplay().id(), kExpectedBounds);
+  display.set_device_scale_factor(2);
+  display.set_rotation(display::Display::ROTATE_180);
+  display.set_panel_rotation(display::Display::ROTATE_270);
+
+  EXPECT_CALL(*handler_, XdgOutputSendLogicalPosition(kExpectedOrigin))
+      .Times(1);
+  EXPECT_CALL(*handler_, XdgOutputSendLogicalSize(kExpectedSize)).Times(1);
+  handler_->OnDisplayMetricsChanged(display, kAllChanges);
+}
+
+}  // namespace
+}  // namespace wayland
+}  // namespace exo
diff --git a/components/exo/wayland/wayland_display_util.cc b/components/exo/wayland/wayland_display_util.cc
new file mode 100644
index 0000000..a0195d98
--- /dev/null
+++ b/components/exo/wayland/wayland_display_util.cc
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/wayland/wayland_display_util.h"
+
+#include "base/notreached.h"
+
+namespace exo {
+namespace wayland {
+
+wl_output_transform OutputTransform(display::Display::Rotation rotation) {
+  // Note: |rotation| describes the counter clockwise rotation that a
+  // display's output is currently adjusted for, which is the inverse
+  // of what we need to return.
+  switch (rotation) {
+    case display::Display::ROTATE_0:
+      return WL_OUTPUT_TRANSFORM_NORMAL;
+    case display::Display::ROTATE_90:
+      return WL_OUTPUT_TRANSFORM_270;
+    case display::Display::ROTATE_180:
+      return WL_OUTPUT_TRANSFORM_180;
+    case display::Display::ROTATE_270:
+      return WL_OUTPUT_TRANSFORM_90;
+  }
+  NOTREACHED();
+  return WL_OUTPUT_TRANSFORM_NORMAL;
+}
+
+}  // namespace wayland
+}  // namespace exo
diff --git a/components/exo/wayland/wayland_display_util.h b/components/exo/wayland/wayland_display_util.h
new file mode 100644
index 0000000..c86d0213
--- /dev/null
+++ b/components/exo/wayland/wayland_display_util.h
@@ -0,0 +1,22 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_WAYLAND_WAYLAND_DISPLAY_UTIL_H_
+#define COMPONENTS_EXO_WAYLAND_WAYLAND_DISPLAY_UTIL_H_
+
+#include <wayland-server-protocol-core.h>
+
+#include "ui/display/display.h"
+
+namespace exo {
+namespace wayland {
+
+// Returns the transform that a compositor will apply to a surface to
+// compensate for the rotation of an output device.
+wl_output_transform OutputTransform(display::Display::Rotation rotation);
+
+}  // namespace wayland
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_WAYLAND_WAYLAND_DISPLAY_UTIL_H_
diff --git a/components/exo/wayland/wayland_display_util_unittest.cc b/components/exo/wayland/wayland_display_util_unittest.cc
new file mode 100644
index 0000000..d2032ec0
--- /dev/null
+++ b/components/exo/wayland/wayland_display_util_unittest.cc
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/wayland/wayland_display_util.h"
+
+#include <wayland-server-protocol-core.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/display.h"
+
+namespace exo {
+namespace wayland {
+namespace {
+
+TEST(WaylandDisplayUtilTest, OutputTransformSimple) {
+  EXPECT_EQ(OutputTransform(display::Display::ROTATE_0),
+            WL_OUTPUT_TRANSFORM_NORMAL);
+  EXPECT_EQ(OutputTransform(display::Display::ROTATE_90),
+            WL_OUTPUT_TRANSFORM_270);
+  EXPECT_EQ(OutputTransform(display::Display::ROTATE_180),
+            WL_OUTPUT_TRANSFORM_180);
+  EXPECT_EQ(OutputTransform(display::Display::ROTATE_270),
+            WL_OUTPUT_TRANSFORM_90);
+}
+
+}  // namespace
+}  // namespace wayland
+}  // namespace exo
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc
index 6b463be..1ae22aa 100644
--- a/components/exo/wayland/zaura_shell.cc
+++ b/components/exo/wayland/zaura_shell.cc
@@ -29,6 +29,7 @@
 #include "components/exo/wayland/serial_tracker.h"
 #include "components/exo/wayland/server_util.h"
 #include "components/exo/wayland/wayland_display_observer.h"
+#include "components/exo/wayland/wayland_display_util.h"
 #include "components/exo/wayland/wl_output.h"
 #include "components/exo/wm_helper.h"
 #include "ui/aura/env.h"
@@ -781,90 +782,97 @@
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-namespace {
-
 ////////////////////////////////////////////////////////////////////////////////
 // aura_output_interface:
 
-class AuraOutput : public WaylandDisplayObserver {
- public:
-  explicit AuraOutput(wl_resource* resource) : resource_(resource) {}
+AuraOutput::AuraOutput(wl_resource* resource) : resource_(resource) {}
 
-  AuraOutput(const AuraOutput&) = delete;
-  AuraOutput& operator=(const AuraOutput&) = delete;
+AuraOutput::~AuraOutput() = default;
 
-  // Overridden from WaylandDisplayObserver:
-  bool SendDisplayMetrics(const display::Display& display,
-                          uint32_t changed_metrics) override {
-    if (!(changed_metrics &
-          (display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
-           display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
-           display::DisplayObserver::DISPLAY_METRIC_ROTATION))) {
-      return false;
-    }
-
-    const WMHelper* wm_helper = WMHelper::GetInstance();
-    const display::ManagedDisplayInfo& display_info =
-        wm_helper->GetDisplayInfo(display.id());
-
-    if (wl_resource_get_version(resource_) >=
-        ZAURA_OUTPUT_SCALE_SINCE_VERSION) {
-      display::ManagedDisplayMode active_mode;
-      bool rv =
-          wm_helper->GetActiveModeForDisplayId(display.id(), &active_mode);
-      DCHECK(rv);
-      const int32_t current_output_scale =
-          std::round(display_info.zoom_factor() * 1000.f);
-      std::vector<float> zoom_factors =
-          display::GetDisplayZoomFactors(active_mode);
-
-      // Ensure that the current zoom factor is a part of the list.
-      auto it = std::find_if(
-          zoom_factors.begin(), zoom_factors.end(),
-          [&display_info](float zoom_factor) -> bool {
-            return std::abs(display_info.zoom_factor() - zoom_factor) <=
-                   std::numeric_limits<float>::epsilon();
-          });
-      if (it == zoom_factors.end())
-        zoom_factors.push_back(display_info.zoom_factor());
-
-      for (float zoom_factor : zoom_factors) {
-        int32_t output_scale = std::round(zoom_factor * 1000.f);
-        uint32_t flags = 0;
-        if (output_scale == 1000)
-          flags |= ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED;
-        if (current_output_scale == output_scale)
-          flags |= ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT;
-
-        // TODO(malaykeshav): This can be removed in the future when client
-        // has been updated.
-        if (wl_resource_get_version(resource_) < 6)
-          output_scale = std::round(1000.f / zoom_factor);
-
-        zaura_output_send_scale(resource_, flags, output_scale);
-      }
-    }
-
-    if (wl_resource_get_version(resource_) >=
-        ZAURA_OUTPUT_CONNECTION_SINCE_VERSION) {
-      zaura_output_send_connection(resource_,
-                                   display.IsInternal()
-                                       ? ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL
-                                       : ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN);
-    }
-
-    if (wl_resource_get_version(resource_) >=
-        ZAURA_OUTPUT_DEVICE_SCALE_FACTOR_SINCE_VERSION) {
-      zaura_output_send_device_scale_factor(
-          resource_, display_info.device_scale_factor() * 1000);
-    }
-
-    return true;
+bool AuraOutput::SendDisplayMetrics(const display::Display& display,
+                                    uint32_t changed_metrics) {
+  if (!(changed_metrics &
+        (display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+         display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+         display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+         display::DisplayObserver::DISPLAY_METRIC_ROTATION))) {
+    return false;
   }
 
- private:
-  wl_resource* const resource_;
-};
+  const WMHelper* wm_helper = WMHelper::GetInstance();
+  const display::ManagedDisplayInfo& display_info =
+      wm_helper->GetDisplayInfo(display.id());
+
+  if (wl_resource_get_version(resource_) >= ZAURA_OUTPUT_SCALE_SINCE_VERSION) {
+    display::ManagedDisplayMode active_mode;
+    bool rv = wm_helper->GetActiveModeForDisplayId(display.id(), &active_mode);
+    DCHECK(rv);
+    const int32_t current_output_scale =
+        std::round(display_info.zoom_factor() * 1000.f);
+    std::vector<float> zoom_factors =
+        display::GetDisplayZoomFactors(active_mode);
+
+    // Ensure that the current zoom factor is a part of the list.
+    auto it = std::find_if(
+        zoom_factors.begin(), zoom_factors.end(),
+        [&display_info](float zoom_factor) -> bool {
+          return std::abs(display_info.zoom_factor() - zoom_factor) <=
+                 std::numeric_limits<float>::epsilon();
+        });
+    if (it == zoom_factors.end())
+      zoom_factors.push_back(display_info.zoom_factor());
+
+    for (float zoom_factor : zoom_factors) {
+      int32_t output_scale = std::round(zoom_factor * 1000.f);
+      uint32_t flags = 0;
+      if (output_scale == 1000)
+        flags |= ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED;
+      if (current_output_scale == output_scale)
+        flags |= ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT;
+
+      // TODO(malaykeshav): This can be removed in the future when client
+      // has been updated.
+      if (wl_resource_get_version(resource_) < 6)
+        output_scale = std::round(1000.f / zoom_factor);
+
+      zaura_output_send_scale(resource_, flags, output_scale);
+    }
+  }
+
+  if (wl_resource_get_version(resource_) >=
+      ZAURA_OUTPUT_CONNECTION_SINCE_VERSION) {
+    zaura_output_send_connection(
+        resource_, display.IsInternal() ? ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL
+                                        : ZAURA_OUTPUT_CONNECTION_TYPE_UNKNOWN);
+  }
+
+  if (wl_resource_get_version(resource_) >=
+      ZAURA_OUTPUT_DEVICE_SCALE_FACTOR_SINCE_VERSION) {
+    zaura_output_send_device_scale_factor(
+        resource_, display_info.device_scale_factor() * 1000);
+  }
+
+  if (wl_resource_get_version(resource_) >= ZAURA_OUTPUT_INSETS_SINCE_VERSION)
+    SendInsets(display.bounds().InsetsFrom(display.work_area()));
+
+  if (wl_resource_get_version(resource_) >=
+      ZAURA_OUTPUT_LOGICAL_TRANSFORM_SINCE_VERSION) {
+    SendLogicalTransform(OutputTransform(display.rotation()));
+  }
+
+  return true;
+}
+
+void AuraOutput::SendInsets(const gfx::Insets& insets) {
+  zaura_output_send_insets(resource_, insets.top(), insets.left(),
+                           insets.bottom(), insets.right());
+}
+
+void AuraOutput::SendLogicalTransform(int32_t transform) {
+  zaura_output_send_logical_transform(resource_, transform);
+}
+
+namespace {
 
 ////////////////////////////////////////////////////////////////////////////////
 // aura_shell_interface:
diff --git a/components/exo/wayland/zaura_shell.h b/components/exo/wayland/zaura_shell.h
index 46d8cab9..dd49ec25 100644
--- a/components/exo/wayland/zaura_shell.h
+++ b/components/exo/wayland/zaura_shell.h
@@ -10,6 +10,8 @@
 #include "chromeos/ui/base/window_state_type.h"
 #include "components/exo/surface.h"
 #include "components/exo/surface_observer.h"
+#include "components/exo/wayland/wayland_display_observer.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/wm/public/activation_change_observer.h"
 
@@ -24,7 +26,7 @@
 namespace wayland {
 class SerialTracker;
 
-constexpr uint32_t kZAuraShellVersion = 32;
+constexpr uint32_t kZAuraShellVersion = 34;
 
 // Adds bindings to the Aura Shell. Normally this implies Ash on ChromeOS
 // builds. On non-ChromeOS builds the protocol provides access to Aura windowing
@@ -151,6 +153,27 @@
   ShellSurfaceBase* shell_surface_;
 };
 
+class AuraOutput : public WaylandDisplayObserver {
+ public:
+  explicit AuraOutput(wl_resource* resource);
+
+  AuraOutput(const AuraOutput&) = delete;
+  AuraOutput& operator=(const AuraOutput&) = delete;
+
+  ~AuraOutput() override;
+
+  // Overridden from WaylandDisplayObserver:
+  bool SendDisplayMetrics(const display::Display& display,
+                          uint32_t changed_metrics) override;
+
+ protected:
+  virtual void SendInsets(const gfx::Insets& insets);
+  virtual void SendLogicalTransform(int32_t transform);
+
+ private:
+  wl_resource* const resource_;
+};
+
 }  // namespace wayland
 }  // namespace exo
 
diff --git a/components/exo/wayland/zaura_shell_unittest.cc b/components/exo/wayland/zaura_shell_unittest.cc
index 2e51f32..b055ae5 100644
--- a/components/exo/wayland/zaura_shell_unittest.cc
+++ b/components/exo/wayland/zaura_shell_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <aura-shell-server-protocol.h>
 
+#include <sys/socket.h>
 #include <memory>
 
 #include "ash/session/session_controller_impl.h"
@@ -15,6 +16,8 @@
 #include "base/time/time.h"
 #include "components/exo/buffer.h"
 #include "components/exo/test/exo_test_base.h"
+#include "components/exo/wayland/scoped_wl.h"
+#include "components/exo/wayland/wayland_display_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window_occlusion_tracker.h"
@@ -403,5 +406,101 @@
   aura_surface().SetFullscreenMode(ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE);
 }
 
+class MockAuraOutput : public AuraOutput {
+ public:
+  using AuraOutput::AuraOutput;
+
+  MOCK_METHOD(void, SendInsets, (const gfx::Insets&), (override));
+  MOCK_METHOD(void, SendLogicalTransform, (int32_t), (override));
+};
+
+class ZAuraOutputTest : public test::ExoTestBase {
+ protected:
+  ZAuraOutputTest() = default;
+  ZAuraOutputTest(const ZAuraOutputTest&) = delete;
+  ZAuraOutputTest& operator=(const ZAuraOutputTest&) = delete;
+  // test::ExxoTestBase:
+  ~ZAuraOutputTest() override = default;
+
+  void SetUp() override {
+    test::ExoTestBase::SetUp();
+
+    int fds[2];
+    ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds), 0);
+    wayland_display_.reset(wl_display_create());
+    client_ = wl_client_create(wayland_display_.get(), fds[0]);
+  }
+
+  std::unique_ptr<MockAuraOutput> CreateAuraOutput(int version) {
+    return std::make_unique<::testing::NiceMock<MockAuraOutput>>(
+        wl_resource_create(client_, &zaura_output_interface, version, 0));
+  }
+
+  std::unique_ptr<wl_display, WlDisplayDeleter> wayland_display_;
+  wl_client* client_ = nullptr;
+};
+
+TEST_F(ZAuraOutputTest, SendInsets) {
+  auto mock_aura_output = CreateAuraOutput(ZAURA_OUTPUT_INSETS_SINCE_VERSION);
+
+  UpdateDisplay("800x600");
+  display::Display display =
+      display_manager()->GetDisplayForId(display_manager()->first_display_id());
+  const gfx::Rect initial_bounds{800, 600};
+  EXPECT_EQ(display.bounds(), initial_bounds);
+  const gfx::Rect new_work_area{10, 20, 500, 400};
+  EXPECT_NE(display.work_area(), new_work_area);
+  display.set_work_area(new_work_area);
+
+  const gfx::Insets expected_insets = initial_bounds.InsetsFrom(new_work_area);
+  EXPECT_CALL(*mock_aura_output, SendInsets(expected_insets)).Times(1);
+  mock_aura_output->SendDisplayMetrics(
+      display, display::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
+}
+
+TEST_F(ZAuraOutputTest, SendLogicalTransform) {
+  auto mock_aura_output =
+      CreateAuraOutput(ZAURA_OUTPUT_LOGICAL_TRANSFORM_SINCE_VERSION);
+
+  UpdateDisplay("800x600");
+  display::Display display =
+      display_manager()->GetDisplayForId(display_manager()->first_display_id());
+
+  // Make sure the expected calls happen in order.
+  ::testing::InSequence seq;
+
+  EXPECT_EQ(display.rotation(), display::Display::ROTATE_0);
+  EXPECT_EQ(display.panel_rotation(), display::Display::ROTATE_0);
+  EXPECT_CALL(*mock_aura_output,
+              SendLogicalTransform(OutputTransform(display.rotation())))
+      .Times(1);
+  mock_aura_output->SendDisplayMetrics(
+      display, display::DisplayObserver::DISPLAY_METRIC_ROTATION);
+
+  display.set_rotation(display::Display::ROTATE_270);
+  display.set_panel_rotation(display::Display::ROTATE_180);
+  EXPECT_CALL(*mock_aura_output,
+              SendLogicalTransform(OutputTransform(display.rotation())))
+      .Times(1);
+  mock_aura_output->SendDisplayMetrics(
+      display, display::DisplayObserver::DISPLAY_METRIC_ROTATION);
+
+  display.set_rotation(display::Display::ROTATE_90);
+  display.set_panel_rotation(display::Display::ROTATE_180);
+  EXPECT_CALL(*mock_aura_output,
+              SendLogicalTransform(OutputTransform(display.rotation())))
+      .Times(1);
+  mock_aura_output->SendDisplayMetrics(
+      display, display::DisplayObserver::DISPLAY_METRIC_ROTATION);
+
+  display.set_rotation(display::Display::ROTATE_270);
+  display.set_panel_rotation(display::Display::ROTATE_270);
+  EXPECT_CALL(*mock_aura_output,
+              SendLogicalTransform(OutputTransform(display.rotation())))
+      .Times(1);
+  mock_aura_output->SendDisplayMetrics(
+      display, display::DisplayObserver::DISPLAY_METRIC_ROTATION);
+}
+
 }  // namespace wayland
 }  // namespace exo
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc
index 5074d98..fe43388d 100644
--- a/components/feed/feed_feature_list.cc
+++ b/components/feed/feed_feature_list.cc
@@ -118,4 +118,12 @@
 
 const base::Feature kIsAblated{"FeedAblation",
                                base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kFeedCloseRefresh{"FeedCloseRefresh",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+const base::FeatureParam<int> kFeedCloseRefreshDelayMinutes{
+    &kFeedCloseRefresh, "delay_minutes", 30};
+const base::FeatureParam<bool> kFeedCloseRefreshRequireInteraction{
+    &kFeedCloseRefresh, "require_interaction", false};
+
 }  // namespace feed
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index b7372eb..bfd89f1 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -119,6 +119,16 @@
 // Feature that when enabled completely removes all Feeds from chrome.
 extern const base::Feature kIsAblated;
 
+// When enabled, schedule a background refresh for a feed sometime after the
+// last user engagement with that feed.
+extern const base::Feature kFeedCloseRefresh;
+// On each qualifying user engagement, schedule a background refresh this many
+// minutes out.
+extern const base::FeatureParam<int> kFeedCloseRefreshDelayMinutes;
+// If true, schedule the refresh only when the user scrolls or interacts. If
+// false, schedule only when the feed surface is opened to content.
+extern const base::FeatureParam<bool> kFeedCloseRefreshRequireInteraction;
+
 }  // namespace feed
 
 #endif  // COMPONENTS_FEED_FEED_FEATURE_LIST_H_
diff --git a/components/mirroring/service/remoting_sender_unittest.cc b/components/mirroring/service/remoting_sender_unittest.cc
index 1fdf403..cad77cd5 100644
--- a/components/mirroring/service/remoting_sender_unittest.cc
+++ b/components/mirroring/service/remoting_sender_unittest.cc
@@ -92,7 +92,7 @@
       const media::cast::ReceiverRtcpEventSubscriber::RtcpEvents& e) override {}
   void AddRtpReceiverReport(const media::cast::RtcpReportBlock& b) override {}
   void SendRtcpFromRtpReceiver() override {}
-  void SetOptions(const base::DictionaryValue& options) override {}
+  void SetOptions(const base::Value::Dict& options) override {}
 
  private:
   std::vector<media::cast::EncodedFrame> sent_frames_;
diff --git a/components/net_log/chrome_net_log.cc b/components/net_log/chrome_net_log.cc
index bb46509..d3a8da14 100644
--- a/components/net_log/chrome_net_log.cc
+++ b/components/net_log/chrome_net_log.cc
@@ -16,34 +16,34 @@
 
 namespace net_log {
 
-std::unique_ptr<base::DictionaryValue> GetPlatformConstantsForNetLog(
+base::Value::Dict GetPlatformConstantsForNetLog(
     const base::CommandLine::StringType& command_line_string,
     const std::string& channel_string) {
-  auto constants_dict = std::make_unique<base::DictionaryValue>();
+  base::Value::Dict constants_dict;
 
   // Add a dictionary with the version of the client and its command line
   // arguments.
-  base::DictionaryValue dict;
+  base::Value::Dict dict;
 
   // We have everything we need to send the right values.
-  dict.SetStringKey("name", version_info::GetProductName());
-  dict.SetStringKey("version", version_info::GetVersionNumber());
-  dict.SetStringKey("cl", version_info::GetLastChange());
-  dict.SetStringKey("version_mod", channel_string);
-  dict.SetStringKey(
-      "official", version_info::IsOfficialBuild() ? "official" : "unofficial");
+  dict.Set("name", version_info::GetProductName());
+  dict.Set("version", version_info::GetVersionNumber());
+  dict.Set("cl", version_info::GetLastChange());
+  dict.Set("version_mod", channel_string);
+  dict.Set("official",
+           version_info::IsOfficialBuild() ? "official" : "unofficial");
   std::string os_type = base::StringPrintf(
       "%s: %s (%s)", base::SysInfo::OperatingSystemName().c_str(),
       base::SysInfo::OperatingSystemVersion().c_str(),
       base::SysInfo::OperatingSystemArchitecture().c_str());
-  dict.SetStringKey("os_type", os_type);
+  dict.Set("os_type", os_type);
 #if BUILDFLAG(IS_WIN)
-  dict.SetStringKey("command_line", base::WideToUTF8(command_line_string));
+  dict.Set("command_line", base::WideToUTF8(command_line_string));
 #else
-  dict.SetStringKey("command_line", command_line_string);
+  dict.Set("command_line", command_line_string);
 #endif
 
-  constants_dict->SetKey("clientInfo", std::move(dict));
+  constants_dict.Set("clientInfo", std::move(dict));
 
   return constants_dict;
 }
diff --git a/components/net_log/chrome_net_log.h b/components/net_log/chrome_net_log.h
index d09324f0..68e7257 100644
--- a/components/net_log/chrome_net_log.h
+++ b/components/net_log/chrome_net_log.h
@@ -9,10 +9,7 @@
 #include <string>
 
 #include "base/command_line.h"
-
-namespace base {
-class DictionaryValue;
-}
+#include "base/values.h"
 
 namespace net_log {
 
@@ -23,7 +20,7 @@
 //  * The operating system version
 //
 //  Safe to call on any thread.
-std::unique_ptr<base::DictionaryValue> GetPlatformConstantsForNetLog(
+base::Value::Dict GetPlatformConstantsForNetLog(
     const base::CommandLine::StringType& command_line_string,
     const std::string& channel_string);
 
diff --git a/components/net_log/net_export_file_writer.cc b/components/net_log/net_export_file_writer.cc
index d3e0659d..c21c4959 100644
--- a/components/net_log/net_export_file_writer.cc
+++ b/components/net_log/net_export_file_writer.cc
@@ -84,8 +84,7 @@
 
 NetExportFileWriter::~NetExportFileWriter() {
   if (net_log_exporter_) {
-    net_log_exporter_->Stop(base::Value(base::Value::Type::DICTIONARY),
-                            base::DoNothing());
+    net_log_exporter_->Stop(base::Value::Dict(), base::DoNothing());
   }
 }
 
@@ -142,8 +141,8 @@
 
   network_context->CreateNetLogExporter(
       net_log_exporter_.BindNewPipeAndPassReceiver());
-  base::Value custom_constants = base::Value::FromUniquePtrValue(
-      GetPlatformConstantsForNetLog(command_line_string, channel_string));
+  base::Value::Dict custom_constants =
+      GetPlatformConstantsForNetLog(command_line_string, channel_string);
 
   net_log_exporter_.set_disconnect_handler(base::BindOnce(
       &NetExportFileWriter::OnConnectionError, base::Unretained(this)));
@@ -159,7 +158,7 @@
 void NetExportFileWriter::StartNetLogAfterCreateFile(
     net::NetLogCaptureMode capture_mode,
     uint64_t max_file_size,
-    base::Value custom_constants,
+    base::Value::Dict custom_constants,
     base::File output_file) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(STATE_STARTING_LOG, state_);
@@ -201,8 +200,7 @@
   }
 }
 
-void NetExportFileWriter::StopNetLog(
-    std::unique_ptr<base::DictionaryValue> polled_data) {
+void NetExportFileWriter::StopNetLog(base::Value::Dict polled_data) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (state_ != STATE_LOGGING)
@@ -212,13 +210,10 @@
 
   NotifyStateObserversAsync();
 
-  base::Value polled_data_value(base::Value::Type::DICTIONARY);
-  if (polled_data)
-    polled_data_value = base::Value::FromUniquePtrValue(std::move(polled_data));
   // base::Unretained(this) is safe here since |net_log_exporter_| is owned by
   // |this| and is a mojo InterfacePtr, which guarantees callback cancellation
   // upon its destruction.
-  net_log_exporter_->Stop(std::move(polled_data_value),
+  net_log_exporter_->Stop(std::move(polled_data),
                           base::BindOnce(&NetExportFileWriter::OnStopResult,
                                          base::Unretained(this)));
 }
diff --git a/components/net_log/net_export_file_writer.h b/components/net_log/net_export_file_writer.h
index 0bee7fe..92c6158 100644
--- a/components/net_log/net_export_file_writer.h
+++ b/components/net_log/net_export_file_writer.h
@@ -124,7 +124,7 @@
   //
   // |polled_data| is a JSON dictionary that will be appended to the end of the
   // log; it's for adding additional info to the log that aren't events.
-  void StopNetLog(std::unique_ptr<base::DictionaryValue> polled_data);
+  void StopNetLog(base::Value::Dict polled_data = base::Value::Dict());
 
   // Creates a DictionaryValue summary of the state of the NetExportFileWriter
   std::unique_ptr<base::DictionaryValue> GetState() const;
@@ -183,7 +183,7 @@
   // logging after the output file has been created.
   void StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode,
                                   uint64_t max_file_size,
-                                  base::Value custom_constants,
+                                  base::Value::Dict custom_constants,
                                   base::File log_file);
 
   void OnStartResult(net::NetLogCaptureMode capture_mode, int result);
diff --git a/components/net_log/net_export_file_writer_unittest.cc b/components/net_log/net_export_file_writer_unittest.cc
index bf43d70..23244ff 100644
--- a/components/net_log/net_export_file_writer_unittest.cc
+++ b/components/net_log/net_export_file_writer_unittest.cc
@@ -70,14 +70,14 @@
   ~FakeNetLogExporter() override {}
 
   void Start(base::File destination,
-             base::Value extra_constants,
+             base::Value::Dict extra_constants,
              net::NetLogCaptureMode capture_mode,
              uint64_t max_file_size,
              StartCallback callback) override {
     std::move(callback).Run(net::OK);
   }
 
-  void Stop(base::Value polled_values, StopCallback callback) override {
+  void Stop(base::Value::Dict polled_values, StopCallback callback) override {
     std::move(callback).Run(net::OK);
   }
 };
@@ -412,7 +412,7 @@
   // |default_log_path_|.
   [[nodiscard]] ::testing::AssertionResult StopThenVerifyNewStateAndFile(
       const base::FilePath& custom_log_path,
-      std::unique_ptr<base::DictionaryValue> polled_data,
+      base::Value::Dict polled_data,
       const std::string& expected_capture_mode_string) {
     file_writer_.StopNetLog(std::move(polled_data));
     std::unique_ptr<base::DictionaryValue> state =
@@ -570,11 +570,11 @@
     // StopNetLog(), should result in state change. The capture mode should
     // match that of the first StartNetLog() call (called by
     // StartThenVerifyNewState()).
-    ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                              capture_mode_strings[i]));
+    ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+        base::FilePath(), base::Value::Dict(), capture_mode_strings[i]));
 
     // Stopping a second time should be a no-op.
-    file_writer()->StopNetLog(nullptr);
+    file_writer()->StopNetLog();
   }
 
   // Start and stop one more time just to make sure the last StopNetLog() call
@@ -583,8 +583,8 @@
                                       capture_mode_strings[0],
                                       network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            capture_mode_strings[0]));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), capture_mode_strings[0]));
 }
 
 // Verify the file sizes after two consecutive starts/stops are the same (even
@@ -596,8 +596,8 @@
       base::FilePath(), net::NetLogCaptureMode::kDefault,
       kCaptureModeDefaultString, network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), kCaptureModeDefaultString));
 
   int64_t stop_file_size;
   EXPECT_TRUE(base::GetFileSize(default_log_path(), &stop_file_size));
@@ -616,8 +616,8 @@
       base::FilePath(), net::NetLogCaptureMode::kDefault,
       kCaptureModeDefaultString, network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), kCaptureModeDefaultString));
 
   int64_t new_stop_file_size;
   EXPECT_TRUE(base::GetFileSize(default_log_path(), &new_stop_file_size));
@@ -634,8 +634,8 @@
       base::FilePath(), net::NetLogCaptureMode::kDefault,
       kCaptureModeDefaultString, network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), kCaptureModeDefaultString));
 
   // Get file size without the event.
   int64_t stop_file_size;
@@ -647,8 +647,8 @@
 
   net_log()->AddGlobalEntry(net::NetLogEventType::CANCELLED);
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), kCaptureModeDefaultString));
 
   // Get file size after adding the event and make sure it's larger than before.
   int64_t new_stop_file_size;
@@ -672,8 +672,8 @@
       StartThenVerifyNewState(custom_log_path, net::NetLogCaptureMode::kDefault,
                               kCaptureModeDefaultString, network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      custom_log_path, base::Value::Dict(), kCaptureModeDefaultString));
 
   // Get file size without the event.
   int64_t stop_file_size;
@@ -685,8 +685,8 @@
 
   net_log()->AddGlobalEntry(net::NetLogEventType::CANCELLED);
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      custom_log_path, base::Value::Dict(), kCaptureModeDefaultString));
 
   // Get file size after adding the event and make sure it's larger than before.
   int64_t new_stop_file_size;
@@ -700,9 +700,8 @@
   // Create dummy polled data
   const char kDummyPolledDataPath[] = "dummy_path";
   const char kDummyPolledDataString[] = "dummy_info";
-  std::unique_ptr<base::DictionaryValue> dummy_polled_data =
-      std::make_unique<base::DictionaryValue>();
-  dummy_polled_data->SetStringKey(kDummyPolledDataPath, kDummyPolledDataString);
+  base::Value::Dict dummy_polled_data;
+  dummy_polled_data.Set(kDummyPolledDataPath, kDummyPolledDataString);
 
   ASSERT_TRUE(StartThenVerifyNewState(
       base::FilePath(), net::NetLogCaptureMode::kDefault,
@@ -793,8 +792,8 @@
       base::FilePath(), net::NetLogCaptureMode::kDefault,
       kCaptureModeDefaultString, network_context()));
 
-  ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
-                                            kCaptureModeDefaultString));
+  ASSERT_TRUE(StopThenVerifyNewStateAndFile(
+      base::FilePath(), base::Value::Dict(), kCaptureModeDefaultString));
   // Read events from log file.
   std::unique_ptr<base::DictionaryValue> root;
   ASSERT_TRUE(ReadCompleteLogFile(default_log_path(), &root));
@@ -850,7 +849,7 @@
       kCaptureModeIncludeEverythingString, network_context()));
 
   // Tell |file_writer_| to stop logging.
-  file_writer()->StopNetLog(nullptr);
+  file_writer()->StopNetLog();
 
   // Before running the main message loop, tell |file_writer_| to start
   // logging. Not running the main message loop prevents the stopping process
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 02dc333..577e3bd6 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -950,7 +950,9 @@
         if (template_url) {
           if (OmniboxFieldTrial::IsSiteSearchStarterPackEnabled() &&
               template_url->starter_pack_id() > 0) {
-            i->description = base::UTF8ToUTF16(template_url->url());
+            i->description =
+                TemplateURLStarterPackData::GetDestinationUrlForStarterPackID(
+                    template_url->starter_pack_id());
           } else {
             // For extension keywords, just make the description the extension
             // name -- don't assume that the normal search keyword description
diff --git a/components/omnibox/browser/builtin_provider.cc b/components/omnibox/browser/builtin_provider.cc
index 4510287..41a14cc 100644
--- a/components/omnibox/browser/builtin_provider.cc
+++ b/components/omnibox/browser/builtin_provider.cc
@@ -21,6 +21,7 @@
 #include "components/search_engines/omnibox_focus_type.h"
 #include "components/search_engines/template_url_data.h"
 #include "components/search_engines/template_url_service.h"
+#include "components/search_engines/template_url_starter_pack_data.h"
 #include "components/url_formatter/url_fixer.h"
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
 #include "ui/base/page_transition_types.h"
@@ -205,7 +206,9 @@
       false, AutocompleteMatchType::SEARCH_OTHER_ENGINE);
 
   match.fill_into_edit = template_url.keyword();
-  match.destination_url = GURL(template_url.url());
+  match.destination_url =
+      GURL(TemplateURLStarterPackData::GetDestinationUrlForStarterPackID(
+          template_url.starter_pack_id()));
   match.contents = template_url.short_name();
   match.contents_class.emplace_back(0, ACMatchClassification::NONE);
   match.transition = ui::PAGE_TRANSITION_GENERATED;
diff --git a/components/omnibox/browser/builtin_provider_unittest.cc b/components/omnibox/browser/builtin_provider_unittest.cc
index 1209e6e6a..7df7343b 100644
--- a/components/omnibox/browser/builtin_provider_unittest.cc
+++ b/components/omnibox/browser/builtin_provider_unittest.cc
@@ -344,8 +344,9 @@
   feature_list.InitAndEnableFeature(omnibox::kSiteSearchStarterPack);
 
   const GURL kBookmarksUrl =
-      GURL(TemplateURLStarterPackData::bookmarks.search_url);
-  const GURL kHistoryUrl = GURL(TemplateURLStarterPackData::history.search_url);
+      GURL(TemplateURLStarterPackData::bookmarks.destination_url);
+  const GURL kHistoryUrl =
+      GURL(TemplateURLStarterPackData::history.destination_url);
 
   const std::u16string kBookmarksKeyword = u"@bookmarks";
   const std::u16string kHistoryKeyword = u"@history";
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index e1051cc..cd98b01 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -377,6 +377,8 @@
           TimingField::kRequestAnimationFrameAfterBackForwardCacheRestore);
     }
   }
+  if (timing.interactive_timing->first_scroll_delay)
+    matched_bits.Set(TimingField::kFirstScrollDelay);
 
   if (render_data) {
     double layout_shift_score = render_data->layout_shift_score;
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
index 078fa82..3853bb2 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
@@ -40,6 +40,7 @@
     kFirstInputDelayAfterBackForwardCacheRestore = 1 << 10,
     kLayoutShift = 1 << 11,
     kRequestAnimationFrameAfterBackForwardCacheRestore = 1 << 12,
+    kFirstScrollDelay = 1 << 13,
   };
   using FrameTreeNodeId =
       page_load_metrics::PageLoadMetricsObserver::FrameTreeNodeId;
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 2550bfe..1c3d092 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -1296,7 +1296,8 @@
 
     VLOG(2) << "Policy fetch error: " << status;
 
-    if (status == DM_STATUS_SERVICE_DEVICE_NOT_FOUND) {
+    if (status == DM_STATUS_SERVICE_DEVICE_NOT_FOUND ||
+        status == DM_STATUS_SERVICE_DEVICE_NEEDS_RESET) {
       // Mark as unregistered and initialize re-registration flow.
       reregistration_dm_token_ = dm_token_;
       dm_token_.clear();
diff --git a/components/policy/core/common/cloud/cloud_policy_client.h b/components/policy/core/common/cloud/cloud_policy_client.h
index 859add5..c4a726a 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.h
+++ b/components/policy/core/common/cloud/cloud_policy_client.h
@@ -899,9 +899,10 @@
   void CreateUniqueRequestJob(
       std::unique_ptr<RegistrationJobConfiguration> config);
 
-  // Used to store a copy of the previously used |dm_token_|. This is used
+  // Used to store a copy of the previously used `dm_token_`. This is used
   // during re-registration, which gets triggered by a failed policy fetch with
-  // error |DM_STATUS_SERVICE_DEVICE_NOT_FOUND|.
+  // errors `DM_STATUS_SERVICE_DEVICE_NOT_FOUND` and
+  // `DM_STATUS_SERVICE_DEVICE_NEEDS_RESET`.
   std::string reregistration_dm_token_;
 
   // Whether extra enterprise connectors URL parameters should be included
diff --git a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
index 793bb0ae..b39a69c 100644
--- a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
@@ -2526,6 +2526,57 @@
   EXPECT_EQ(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID, client_->status());
 }
 
+#if !BUILDFLAG(IS_CHROMEOS)
+TEST_F(CloudPolicyClientTest, PolicyReregistrationAfterDMTokenDeletion) {
+  RegisterClient();
+
+  // Handle 410 (device needs reset) on policy fetch.
+  EXPECT_TRUE(client_->is_registered());
+  EXPECT_FALSE(client_->requires_reregistration());
+  DeviceManagementService::JobConfiguration::JobType upload_type;
+  em::DeviceManagementResponse response;
+  response.add_error_detail(em::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN);
+  EXPECT_CALL(job_creation_handler_, OnJobCreation)
+      .WillOnce(DoAll(
+          service_.CaptureJobType(&upload_type),
+          service_.SendJobResponseAsync(
+              net::OK, DeviceManagementService::kDeviceNotFound, response)));
+  EXPECT_CALL(observer_, OnRegistrationStateChanged);
+  EXPECT_CALL(observer_, OnClientError);
+  client_->FetchPolicy();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(DM_STATUS_SERVICE_DEVICE_NEEDS_RESET, client_->status());
+  EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string()));
+  EXPECT_FALSE(client_->is_registered());
+  EXPECT_TRUE(client_->requires_reregistration());
+
+  // Re-register.
+  ExpectAndCaptureJob(GetRegistrationResponse());
+  EXPECT_CALL(observer_, OnRegistrationStateChanged);
+  EXPECT_CALL(device_dmtoken_callback_observer_,
+              OnDeviceDMTokenRequested(
+                  /*user_affiliation_ids=*/std::vector<std::string>()))
+      .WillOnce(Return(kDeviceDMToken));
+  CloudPolicyClient::RegistrationParameters user_recovery(
+      em::DeviceRegisterRequest::USER,
+      em::DeviceRegisterRequest::FLAVOR_ENROLLMENT_RECOVERY);
+  client_->Register(user_recovery, client_id_, kOAuthToken);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_POLICY_FETCH,
+            upload_type);
+  EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_REGISTRATION,
+            job_type_);
+  EXPECT_EQ(auth_data_, DMAuth::NoAuth());
+  VerifyQueryParameter();
+  EXPECT_EQ(job_request_.SerializePartialAsString(),
+            GetReregistrationRequest().SerializePartialAsString());
+  EXPECT_TRUE(client_->is_registered());
+  EXPECT_FALSE(client_->requires_reregistration());
+  EXPECT_FALSE(client_->GetPolicyFor(policy_type_, std::string()));
+  EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
+}
+#endif  // !BUILDFLAG(IS_CHROMEOS)
+
 TEST_F(CloudPolicyClientTest, RequestFetchRobotAuthCodes) {
   RegisterClient();
 
diff --git a/components/policy/core/common/cloud/device_management_service_unittest.cc b/components/policy/core/common/cloud/device_management_service_unittest.cc
index 02344b32..75e128f 100644
--- a/components/policy/core/common/cloud/device_management_service_unittest.cc
+++ b/components/policy/core/common/cloud/device_management_service_unittest.cc
@@ -62,6 +62,15 @@
 const char kOAuthAuthorizationHeaderPrefix[] = "OAuth ";
 #endif
 
+// Helper function which generates a DMServer response and populates the
+// `error_detail` field.
+std::string GenerateResponseWithErrorDetail(
+    em::DeviceManagementErrorDetail error_detail) {
+  em::DeviceManagementResponse response;
+  response.add_error_detail(error_detail);
+  return response.SerializeAsString();
+}
+
 // Unit tests for the device management policy service. The tests are run
 // against a TestURLLoaderFactory that is used to short-circuit the request
 // without calling into the actual network stack.
@@ -474,6 +483,22 @@
                             net::OK,
                             410,
                             PROTO_STRING(kResponseEmpty)),
+        FailedRequestParams(
+            DM_STATUS_SERVICE_DEVICE_NOT_FOUND,
+            net::OK,
+            410,
+            GenerateResponseWithErrorDetail(
+                em::CBCM_DELETION_POLICY_PREFERENCE_INVALIDATE_TOKEN)),
+        FailedRequestParams(
+#if BUILDFLAG(IS_CHROMEOS)
+            DM_STATUS_SERVICE_DEVICE_NOT_FOUND,
+#else   // BUILDFLAG(IS_CHROMEOS)
+            DM_STATUS_SERVICE_DEVICE_NEEDS_RESET,
+#endif  // BUILDFLAG(IS_CHROMEOS)
+            net::OK,
+            410,
+            GenerateResponseWithErrorDetail(
+                em::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN)),
         FailedRequestParams(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID,
                             net::OK,
                             401,
diff --git a/components/policy/core/common/cloud/dmserver_job_configurations.cc b/components/policy/core/common/cloud/dmserver_job_configurations.cc
index 7f46c67..fb1666f 100644
--- a/components/policy/core/common/cloud/dmserver_job_configurations.cc
+++ b/components/policy/core/common/cloud/dmserver_job_configurations.cc
@@ -151,87 +151,77 @@
 DMServerJobConfiguration::~DMServerJobConfiguration() {}
 
 DeviceManagementStatus
-DMServerJobConfiguration::MapNetErrorAndResponseCodeToDMStatus(
+DMServerJobConfiguration::MapNetErrorAndResponseToDMStatus(
     int net_error,
-    int response_code) {
-  DeviceManagementStatus code;
-  if (net_error != net::OK) {
-    code = DM_STATUS_REQUEST_FAILED;
-  } else {
-    switch (response_code) {
-      case DeviceManagementService::kSuccess:
-        code = DM_STATUS_SUCCESS;
-        break;
-      case DeviceManagementService::kInvalidArgument:
-        code = DM_STATUS_REQUEST_INVALID;
-        break;
-      case DeviceManagementService::kInvalidAuthCookieOrDMToken:
-        code = DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID;
-        break;
-      case DeviceManagementService::kMissingLicenses:
-        code = DM_STATUS_SERVICE_MISSING_LICENSES;
-        break;
-      case DeviceManagementService::kDeviceManagementNotAllowed:
-        code = DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED;
-        break;
-      case DeviceManagementService::kPendingApproval:
-        code = DM_STATUS_SERVICE_ACTIVATION_PENDING;
-        break;
-      case DeviceManagementService::kRequestTooLarge:
-        code = DM_STATUS_REQUEST_TOO_LARGE;
-        break;
-      case DeviceManagementService::kConsumerAccountWithPackagedLicense:
-        code = DM_STATUS_SERVICE_CONSUMER_ACCOUNT_WITH_PACKAGED_LICENSE;
-        break;
-      case DeviceManagementService::kInvalidURL:
-      case DeviceManagementService::kInternalServerError:
-      case DeviceManagementService::kServiceUnavailable:
-        code = DM_STATUS_TEMPORARY_UNAVAILABLE;
-        break;
-      case DeviceManagementService::kDeviceNotFound:
-        code = DM_STATUS_SERVICE_DEVICE_NOT_FOUND;
-        break;
-      case DeviceManagementService::kPolicyNotFound:
-        code = DM_STATUS_SERVICE_POLICY_NOT_FOUND;
-        break;
-      case DeviceManagementService::kInvalidSerialNumber:
-        code = DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER;
-        break;
-      case DeviceManagementService::kTooManyRequests:
-        code = DM_STATUS_SERVICE_TOO_MANY_REQUESTS;
-        break;
-      case DeviceManagementService::kDomainMismatch:
-        code = DM_STATUS_SERVICE_DOMAIN_MISMATCH;
-        break;
-      case DeviceManagementService::kDeprovisioned:
-        code = DM_STATUS_SERVICE_DEPROVISIONED;
-        break;
-      case DeviceManagementService::kDeviceIdConflict:
-        code = DM_STATUS_SERVICE_DEVICE_ID_CONFLICT;
-        break;
-      case DeviceManagementService::kArcDisabled:
-        code = DM_STATUS_SERVICE_ARC_DISABLED;
-        break;
-      case DeviceManagementService::kInvalidDomainlessCustomer:
-        code = DM_STATUS_SERVICE_ENTERPRISE_ACCOUNT_IS_NOT_ELIGIBLE_TO_ENROLL;
-        break;
-      case DeviceManagementService::kTosHasNotBeenAccepted:
-        code = DM_STATUS_SERVICE_ENTERPRISE_TOS_HAS_NOT_BEEN_ACCEPTED;
-        break;
-      case DeviceManagementService::kIllegalAccountForPackagedEDULicense:
-        code = DM_STATUS_SERVICE_ILLEGAL_ACCOUNT_FOR_PACKAGED_EDU_LICENSE;
-        break;
-      default:
-        // Handle all unknown 5xx HTTP error codes as temporary and any other
-        // unknown error as one that needs more time to recover.
-        if (response_code >= 500 && response_code <= 599)
-          code = DM_STATUS_TEMPORARY_UNAVAILABLE;
-        else
-          code = DM_STATUS_HTTP_STATUS_ERROR;
-        break;
+    int response_code,
+    const std::string& response_body) {
+  if (net_error != net::OK)
+    return DM_STATUS_REQUEST_FAILED;
+
+  switch (response_code) {
+    case DeviceManagementService::kSuccess:
+      return DM_STATUS_SUCCESS;
+    case DeviceManagementService::kInvalidArgument:
+      return DM_STATUS_REQUEST_INVALID;
+    case DeviceManagementService::kInvalidAuthCookieOrDMToken:
+      return DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID;
+    case DeviceManagementService::kMissingLicenses:
+      return DM_STATUS_SERVICE_MISSING_LICENSES;
+    case DeviceManagementService::kDeviceManagementNotAllowed:
+      return DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED;
+    case DeviceManagementService::kPendingApproval:
+      return DM_STATUS_SERVICE_ACTIVATION_PENDING;
+    case DeviceManagementService::kRequestTooLarge:
+      return DM_STATUS_REQUEST_TOO_LARGE;
+    case DeviceManagementService::kConsumerAccountWithPackagedLicense:
+      return DM_STATUS_SERVICE_CONSUMER_ACCOUNT_WITH_PACKAGED_LICENSE;
+    case DeviceManagementService::kInvalidURL:
+    case DeviceManagementService::kInternalServerError:
+    case DeviceManagementService::kServiceUnavailable:
+      return DM_STATUS_TEMPORARY_UNAVAILABLE;
+    case DeviceManagementService::kDeviceNotFound: {
+#if !BUILDFLAG(IS_CHROMEOS)
+      // The `kDeviceNotFound` response code can correspond to different DM
+      // statuses depending on the contents of the response body.
+      em::DeviceManagementResponse response;
+      if (response.ParseFromString(response_body) &&
+          std::find(response.error_detail().begin(),
+                    response.error_detail().end(),
+                    em::CBCM_DELETION_POLICY_PREFERENCE_DELETE_TOKEN) !=
+              response.error_detail().end()) {
+        return DM_STATUS_SERVICE_DEVICE_NEEDS_RESET;
+      }
+#endif  // !BUILDFLAG(IS_CHROMEOS)
+      return DM_STATUS_SERVICE_DEVICE_NOT_FOUND;
     }
+    case DeviceManagementService::kPolicyNotFound:
+      return DM_STATUS_SERVICE_POLICY_NOT_FOUND;
+    case DeviceManagementService::kInvalidSerialNumber:
+      return DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER;
+    case DeviceManagementService::kTooManyRequests:
+      return DM_STATUS_SERVICE_TOO_MANY_REQUESTS;
+    case DeviceManagementService::kDomainMismatch:
+      return DM_STATUS_SERVICE_DOMAIN_MISMATCH;
+    case DeviceManagementService::kDeprovisioned:
+      return DM_STATUS_SERVICE_DEPROVISIONED;
+    case DeviceManagementService::kDeviceIdConflict:
+      return DM_STATUS_SERVICE_DEVICE_ID_CONFLICT;
+    case DeviceManagementService::kArcDisabled:
+      return DM_STATUS_SERVICE_ARC_DISABLED;
+    case DeviceManagementService::kInvalidDomainlessCustomer:
+      return DM_STATUS_SERVICE_ENTERPRISE_ACCOUNT_IS_NOT_ELIGIBLE_TO_ENROLL;
+    case DeviceManagementService::kTosHasNotBeenAccepted:
+      return DM_STATUS_SERVICE_ENTERPRISE_TOS_HAS_NOT_BEEN_ACCEPTED;
+    case DeviceManagementService::kIllegalAccountForPackagedEDULicense:
+      return DM_STATUS_SERVICE_ILLEGAL_ACCOUNT_FOR_PACKAGED_EDU_LICENSE;
+    default:
+      // Handle all unknown 5xx HTTP error codes as temporary and any other
+      // unknown error as one that needs more time to recover.
+      if (response_code >= 500 && response_code <= 599)
+        return DM_STATUS_TEMPORARY_UNAVAILABLE;
+
+      return DM_STATUS_HTTP_STATUS_ERROR;
   }
-  return code;
 }
 
 std::string DMServerJobConfiguration::GetPayload() {
@@ -250,7 +240,7 @@
     int response_code,
     const std::string& response_body) {
   DeviceManagementStatus code =
-      MapNetErrorAndResponseCodeToDMStatus(net_error, response_code);
+      MapNetErrorAndResponseToDMStatus(net_error, response_code, response_body);
 
   em::DeviceManagementResponse response;
   if (code == DM_STATUS_SUCCESS && !response.ParseFromString(response_body)) {
diff --git a/components/policy/core/common/cloud/dmserver_job_configurations.h b/components/policy/core/common/cloud/dmserver_job_configurations.h
index 4ff0a58c..9663e97d 100644
--- a/components/policy/core/common/cloud/dmserver_job_configurations.h
+++ b/components/policy/core/common/cloud/dmserver_job_configurations.h
@@ -66,9 +66,10 @@
   }
 
  protected:
-  DeviceManagementStatus MapNetErrorAndResponseCodeToDMStatus(
+  DeviceManagementStatus MapNetErrorAndResponseToDMStatus(
       int net_error,
-      int response_code);
+      int response_code,
+      const std::string& response_body);
 
  private:
   // JobConfiguration interface.
diff --git a/components/policy/core/common/cloud/mock_device_management_service.cc b/components/policy/core/common/cloud/mock_device_management_service.cc
index c2479584..0a8d5644 100644
--- a/components/policy/core/common/cloud/mock_device_management_service.cc
+++ b/components/policy/core/common/cloud/mock_device_management_service.cc
@@ -302,7 +302,7 @@
                                              int response_code,
                                              const std::string& response_body) {
   DeviceManagementStatus status =
-      MapNetErrorAndResponseCodeToDMStatus(net_error, response_code);
+      MapNetErrorAndResponseToDMStatus(net_error, response_code, response_body);
   std::move(callback_).Run(job, status, net_error, response_body);
 }
 
diff --git a/components/policy/test_support/policy_storage.h b/components/policy/test_support/policy_storage.h
index bbb83186..06edb0a09 100644
--- a/components/policy/test_support/policy_storage.h
+++ b/components/policy/test_support/policy_storage.h
@@ -157,6 +157,15 @@
   std::vector<std::string> GetMatchingSerialHashes(uint64_t modulus,
                                                    uint64_t remainder) const;
 
+  void set_error_detail(
+      enterprise_management::DeviceManagementErrorDetail error_detail) {
+    error_detail_ = error_detail;
+  }
+
+  enterprise_management::DeviceManagementErrorDetail error_detail() const {
+    return error_detail_;
+  }
+
  private:
   // Maps policy keys to a serialized proto representing the policies to be
   // applied for the type (e.g. CloudPolicySettings, ChromeDeviceSettingsProto).
@@ -193,6 +202,11 @@
   // Maps brand serial ID to InitialEnrollmentState.
   base::flat_map<std::string, InitialEnrollmentState>
       initial_enrollment_states_;
+
+  // Determines whether the DMToken should be invalidated or deleted during
+  // browser unenrollment.
+  enterprise_management::DeviceManagementErrorDetail error_detail_ =
+      enterprise_management::CBCM_DELETION_POLICY_PREFERENCE_INVALIDATE_TOKEN;
 };
 
 }  // namespace policy
diff --git a/components/policy/test_support/request_handler_for_policy.cc b/components/policy/test_support/request_handler_for_policy.cc
index 569d98b6..dbc94bb 100644
--- a/components/policy/test_support/request_handler_for_policy.cc
+++ b/components/policy/test_support/request_handler_for_policy.cc
@@ -59,11 +59,16 @@
   if (!GetDeviceTokenFromRequest(request, &request_device_token))
     return CreateHttpResponse(net::HTTP_UNAUTHORIZED, "Invalid device token.");
 
+  em::DeviceManagementResponse device_management_response;
   const ClientStorage::ClientInfo* client_info =
       client_storage()->GetClientOrNull(
           KeyValueFromUrl(request.GetURL(), dm_protocol::kParamDeviceID));
-  if (!client_info || client_info->device_token != request_device_token)
-    return CreateHttpResponse(net::HTTP_GONE, "Invalid device token.");
+  if (!client_info || client_info->device_token != request_device_token) {
+    device_management_response.add_error_detail(
+        policy_storage()->error_detail());
+    return CreateHttpResponse(net::HTTP_GONE,
+                              device_management_response.SerializeAsString());
+  }
 
   em::DeviceManagementRequest device_management_request;
   device_management_request.ParseFromString(request.content);
@@ -82,7 +87,6 @@
     }
   }
 
-  em::DeviceManagementResponse device_management_response;
   for (const auto& fetch_request :
        device_management_request.policy_request().requests()) {
     const std::string& policy_type = fetch_request.policy_type();
diff --git a/components/reporting/client/mock_report_queue.cc b/components/reporting/client/mock_report_queue.cc
index 9d8f8127..142fd46 100644
--- a/components/reporting/client/mock_report_queue.cc
+++ b/components/reporting/client/mock_report_queue.cc
@@ -4,10 +4,32 @@
 
 #include "components/reporting/client/mock_report_queue.h"
 
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::Invoke;
+
 namespace reporting {
 
-MockReportQueueStrict::MockReportQueueStrict() = default;
+MockReportQueueStrict::MockReportQueueStrict() {
+  // Default action makes a synchronous call to record_producer and passes the
+  // result over to plain-text mock AddRecord. Can be overridden, if necessary.
+  ON_CALL(*this, AddProducedRecord)
+      .WillByDefault(
+          Invoke(this, &MockReportQueueStrict::ForwardProducedRecord));
+}
 
 MockReportQueueStrict::~MockReportQueueStrict() = default;
 
+void MockReportQueueStrict::ForwardProducedRecord(
+    RecordProducer record_producer,
+    Priority priority,
+    EnqueueCallback callback) {
+  auto record_result = std::move(record_producer).Run();
+  if (!record_result.ok()) {
+    std::move(callback).Run(record_result.status());
+    return;
+  }
+  AddRecord(std::move(record_result.ValueOrDie()), priority,
+            std::move(callback));
+}
 }  // namespace reporting
diff --git a/components/reporting/client/mock_report_queue.h b/components/reporting/client/mock_report_queue.h
index 99e1c43..70b63c5 100644
--- a/components/reporting/client/mock_report_queue.h
+++ b/components/reporting/client/mock_report_queue.h
@@ -23,6 +23,13 @@
   MockReportQueueStrict();
   ~MockReportQueueStrict() override;
 
+  // Mock AddRecord with record producer.
+  // Rarely used, by default calls plain-text AddRecord.
+  MOCK_METHOD(void,
+              AddProducedRecord,
+              (RecordProducer, Priority, EnqueueCallback),
+              (const override));
+
   MOCK_METHOD(void,
               AddRecord,
               (std::string, Priority, EnqueueCallback),
@@ -35,6 +42,14 @@
       PrepareToAttachActualQueue,
       (),
       (const override));
+
+ private:
+  // Helper method that executes |record_producer| and in case of success
+  // forwards the result to |AddRecord|. In case of failure passes Status to
+  // |callback|.
+  void ForwardProducedRecord(RecordProducer record_producer,
+                             Priority priority,
+                             EnqueueCallback callback);
 };
 
 // Most of the time no need to log uninterested calls.
diff --git a/components/reporting/client/report_queue.cc b/components/reporting/client/report_queue.cc
index cb1c346..6fcb9cac 100644
--- a/components/reporting/client/report_queue.cc
+++ b/components/reporting/client/report_queue.cc
@@ -53,24 +53,27 @@
 void ReportQueue::Enqueue(std::string record,
                           Priority priority,
                           ReportQueue::EnqueueCallback callback) const {
-  AddRecord(std::move(record), priority, std::move(callback));
+  AddProducedRecord(base::BindOnce(
+                        [](std::string record) -> StatusOr<std::string> {
+                          return std::move(record);
+                        },
+                        std::move(record)),
+                    priority, std::move(callback));
 }
 
 void ReportQueue::Enqueue(base::Value::Dict record,
                           Priority priority,
                           ReportQueue::EnqueueCallback callback) const {
-  ASSIGN_OR_ONCE_CALLBACK_AND_RETURN(std::string json_record, callback,
-                                     ValueToJson(std::move(record)));
-  AddRecord(json_record, priority, std::move(callback));
+  AddProducedRecord(base::BindOnce(&ValueToJson, std::move(record)), priority,
+                    std::move(callback));
 }
 
 void ReportQueue::Enqueue(
     std::unique_ptr<const google::protobuf::MessageLite> record,
     Priority priority,
     ReportQueue::EnqueueCallback callback) const {
-  ASSIGN_OR_ONCE_CALLBACK_AND_RETURN(std::string protobuf_record, callback,
-                                     ProtoToString(std::move(record)));
-  AddRecord(protobuf_record, priority, std::move(callback));
+  AddProducedRecord(base::BindOnce(&ProtoToString, std::move(record)), priority,
+                    std::move(callback));
 }
 
 }  // namespace reporting
diff --git a/components/reporting/client/report_queue.h b/components/reporting/client/report_queue.h
index 29d2b184..fb16d88f 100644
--- a/components/reporting/client/report_queue.h
+++ b/components/reporting/client/report_queue.h
@@ -104,6 +104,9 @@
 
 class ReportQueue {
  public:
+  // A callback to asynchronously generate data to be added to |Storage|.
+  using RecordProducer = base::OnceCallback<StatusOr<std::string>()>;
+
   // An EnqueueCallback is called on the completion of any |Enqueue| call.
   using EnqueueCallback = base::OnceCallback<void(Status)>;
 
@@ -152,10 +155,10 @@
       void(StatusOr<std::unique_ptr<ReportQueue>>)>
   PrepareToAttachActualQueue() const = 0;
 
- protected:
-  virtual void AddRecord(std::string record,
-                         Priority priority,
-                         EnqueueCallback callback) const = 0;
+ private:
+  virtual void AddProducedRecord(RecordProducer record_producer,
+                                 Priority priority,
+                                 EnqueueCallback callback) const = 0;
 };
 
 }  // namespace reporting
diff --git a/components/reporting/client/report_queue_impl.cc b/components/reporting/client/report_queue_impl.cc
index 16993eb..33240496 100644
--- a/components/reporting/client/report_queue_impl.cc
+++ b/components/reporting/client/report_queue_impl.cc
@@ -28,10 +28,49 @@
 #include "components/reporting/proto/synced/record_constants.pb.h"
 #include "components/reporting/storage/storage_module_interface.h"
 #include "components/reporting/util/status.h"
-#include "components/reporting/util/status_macros.h"
 #include "components/reporting/util/statusor.h"
 
 namespace reporting {
+namespace {
+// Calls |record_producer|, checks the result and in case of success, forwards
+// it to the storage. In production code should be invoked asynchronously, on a
+// thread pool (no synchronization expected).
+void AddRecordToStorage(scoped_refptr<StorageModuleInterface> storage,
+                        Priority priority,
+                        std::string dm_token,
+                        Destination destination,
+                        ReportQueue::RecordProducer record_producer,
+                        StorageModuleInterface::EnqueueCallback callback) {
+  // Generates record data.
+  auto record_result = std::move(record_producer).Run();
+  if (!record_result.ok()) {
+    std::move(callback).Run(record_result.status());
+    return;
+  }
+
+  // Augment data.
+  Record record;
+  *record.mutable_data() = std::move(record_result.ValueOrDie());
+  record.set_destination(destination);
+
+  // record with no DM token is assumed to be associated with device DM token
+  if (!dm_token.empty()) {
+    *record.mutable_dm_token() = std::move(dm_token);
+  }
+
+  // Calculate timestamp in microseconds - to match Spanner expectations.
+  const int64_t time_since_epoch_us =
+      base::Time::Now().ToJavaTime() * base::Time::kMicrosecondsPerMillisecond;
+  record.set_timestamp_us(time_since_epoch_us);
+  if (!record_result.ok()) {
+    std::move(callback).Run(record_result.status());
+    return;
+  }
+
+  // Add resulting Record to the storage.
+  storage->AddRecord(priority, std::move(record), std::move(callback));
+}
+}  // namespace
 
 void ReportQueueImpl::Create(
     std::unique_ptr<ReportQueueConfiguration> config,
@@ -41,21 +80,16 @@
       new ReportQueueImpl(std::move(config), storage)));
 }
 
-ReportQueueImpl::~ReportQueueImpl() = default;
-
 ReportQueueImpl::ReportQueueImpl(
     std::unique_ptr<ReportQueueConfiguration> config,
     scoped_refptr<StorageModuleInterface> storage)
-    : config_(std::move(config)),
-      storage_(storage),
-      sequenced_task_runner_(
-          base::ThreadPool::CreateSequencedTaskRunner(base::TaskTraits())) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
+    : config_(std::move(config)), storage_(storage) {}
 
-void ReportQueueImpl::AddRecord(std::string record,
-                                Priority priority,
-                                EnqueueCallback callback) const {
+ReportQueueImpl::~ReportQueueImpl() = default;
+
+void ReportQueueImpl::AddProducedRecord(RecordProducer record_producer,
+                                        Priority priority,
+                                        EnqueueCallback callback) const {
   const Status status = config_->CheckPolicy();
   if (!status.ok()) {
     std::move(callback).Run(status);
@@ -68,34 +102,13 @@
     return;
   }
 
-  sequenced_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&ReportQueueImpl::SendRecordToStorage,
-                                base::Unretained(this), std::move(record),
-                                priority, std::move(callback)));
-}
-
-void ReportQueueImpl::SendRecordToStorage(std::string record_data,
-                                          Priority priority,
-                                          EnqueueCallback callback) const {
-  storage_->AddRecord(priority, AugmentRecord(std::move(record_data)),
-                      std::move(callback));
-}
-
-Record ReportQueueImpl::AugmentRecord(std::string record_data) const {
-  Record record;
-  *record.mutable_data() = std::move(record_data);
-  record.set_destination(config_->destination());
-
-  // record with no DM token is assumed to be associated with device DM token
-  if (!config_->dm_token().empty()) {
-    record.set_dm_token(config_->dm_token());
-  }
-
-  // Calculate timestamp in microseconds - to match Spanner expectations.
-  const int64_t time_since_epoch_us =
-      base::Time::Now().ToJavaTime() * base::Time::kMicrosecondsPerMillisecond;
-  record.set_timestamp_us(time_since_epoch_us);
-  return record;
+  // Execute |record_producer| on arbitrary thread, analyze the result and send
+  // it to the Storage, returning with the callback.
+  base::ThreadPool::PostTask(
+      FROM_HERE, {base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&AddRecordToStorage, storage_, priority,
+                     config_->dm_token(), config_->destination(),
+                     std::move(record_producer), std::move(callback)));
 }
 
 void ReportQueueImpl::Flush(Priority priority, FlushCallback callback) {
@@ -153,25 +166,41 @@
           priority, std::move(callback), weak_ptr_factory_.GetWeakPtr()));
 }
 
-void SpeculativeReportQueueImpl::AddRecord(std::string record,
-                                           Priority priority,
-                                           EnqueueCallback callback) const {
-  sequenced_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SpeculativeReportQueueImpl::MaybeEnqueueRecord,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(record),
-                     priority, std::move(callback)));
+void SpeculativeReportQueueImpl::AddProducedRecord(
+    RecordProducer record_producer,
+    Priority priority,
+    EnqueueCallback callback) const {
+  // Invoke producer on a thread pool, then enqueue record on sequenced task
+  // runner.
+  base::ThreadPool::PostTask(
+      FROM_HERE, {},
+      base::BindOnce(
+          [](RecordProducer record_producer,
+             base::OnceCallback<void(StatusOr<std::string>)> callback) {
+            std::move(callback).Run(std::move(record_producer).Run());
+          },
+          std::move(record_producer),
+          base::BindPostTask(
+              sequenced_task_runner_,
+              base::BindOnce(&SpeculativeReportQueueImpl::MaybeEnqueueRecord,
+                             weak_ptr_factory_.GetWeakPtr(), priority,
+                             std::move(callback)))));
 }
 
 void SpeculativeReportQueueImpl::MaybeEnqueueRecord(
-    std::string record,
     Priority priority,
-    EnqueueCallback callback) const {
+    EnqueueCallback callback,
+    StatusOr<std::string> record_or_error) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!record_or_error.ok()) {
+    std::move(callback).Run(record_or_error.status());
+    return;
+  }
+  auto record = std::move(record_or_error.ValueOrDie());
   if (!report_queue_) {
     // Queue is not ready yet, store the record in the memory
     // queue.
-    pending_records_.emplace(record, priority);
+    pending_records_.emplace(std::move(record), priority);
     std::move(callback).Run(Status::StatusOK());
     return;
   }
@@ -201,11 +230,11 @@
   pending_records_.pop();
   if (pending_records_.empty()) {
     // Last of the pending records.
-    report_queue_->Enqueue(record, priority, std::move(callback));
+    report_queue_->Enqueue(std::move(record), priority, std::move(callback));
     return;
   }
   report_queue_->Enqueue(
-      record, priority,
+      std::move(record), priority,
       base::BindPostTask(
           sequenced_task_runner_,
           base::BindOnce(
diff --git a/components/reporting/client/report_queue_impl.h b/components/reporting/client/report_queue_impl.h
index 4f4ffcd..a9d3f6fb 100644
--- a/components/reporting/client/report_queue_impl.h
+++ b/components/reporting/client/report_queue_impl.h
@@ -62,21 +62,12 @@
                   scoped_refptr<StorageModuleInterface> storage);
 
  private:
-  void AddRecord(std::string record,
-                 Priority priority,
-                 EnqueueCallback callback) const override;
+  void AddProducedRecord(RecordProducer record_producer,
+                         Priority priority,
+                         EnqueueCallback callback) const override;
 
-  void SendRecordToStorage(std::string record,
-                           Priority priority,
-                           EnqueueCallback callback) const;
-
-  [[nodiscard]] reporting::Record AugmentRecord(std::string record_data) const;
-
-  std::unique_ptr<ReportQueueConfiguration> config_;
-  scoped_refptr<StorageModuleInterface> storage_;
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
+  const std::unique_ptr<ReportQueueConfiguration> config_;
+  const scoped_refptr<StorageModuleInterface> storage_;
 };
 
 class SpeculativeReportQueueImpl : public ReportQueue {
@@ -100,14 +91,13 @@
   // Initiates processesing of all pending records.
   void AttachActualQueue(std::unique_ptr<ReportQueue> actual_queue);
 
- protected:
-  // Forwards |AddRecord| to |ReportQueue|, if already created.
-  // Records the record internally otherwise.
-  void AddRecord(std::string record,
-                 Priority priority,
-                 EnqueueCallback callback) const override;
-
  private:
+  // Forwards |AddProducedRecord| to |ReportQueue|, if already created.
+  // Records the record internally otherwise.
+  void AddProducedRecord(RecordProducer record_producer,
+                         Priority priority,
+                         EnqueueCallback callback) const override;
+
   // Private constructor, used by the factory method  only.
   explicit SpeculativeReportQueueImpl(
       scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner);
@@ -117,9 +107,9 @@
 
   // Optionally enqueues |record| (owned) to actual queue, if ready.
   // Otherwise adds it to the end of |pending_records_|.
-  void MaybeEnqueueRecord(std::string record,
-                          Priority priority,
-                          EnqueueCallback callback) const;
+  void MaybeEnqueueRecord(Priority priority,
+                          EnqueueCallback callback,
+                          StatusOr<std::string> record) const;
 
   // Task runner that protects |report_queue_| and |pending_records_|
   // and allows to synchronize the initialization.
@@ -127,12 +117,13 @@
   SEQUENCE_CHECKER(sequence_checker_);
 
   // Actual |ReportQueue|, once created.
-  std::unique_ptr<ReportQueue> report_queue_;
+  std::unique_ptr<ReportQueue> report_queue_
+      GUARDED_BY_CONTEXT(sequence_checker_);
 
   // Queue of the pending records, collected before actual queue has been
   // created. Declared 'mutable', because it is accessed by 'const' methods.
   mutable std::queue<std::pair<std::string /*record*/, Priority /*priority*/>>
-      pending_records_;
+      pending_records_ GUARDED_BY_CONTEXT(sequence_checker_);
 
   // Weak pointer factory.
   base::WeakPtrFactory<SpeculativeReportQueueImpl> weak_ptr_factory_{this};
diff --git a/components/reporting/client/report_queue_impl_unittest.cc b/components/reporting/client/report_queue_impl_unittest.cc
index ba28fdd..d369f228 100644
--- a/components/reporting/client/report_queue_impl_unittest.cc
+++ b/components/reporting/client/report_queue_impl_unittest.cc
@@ -358,5 +358,74 @@
   EXPECT_EQ(result.error_code(), error::FAILED_PRECONDITION);
 }
 
+TEST_F(ReportQueueImplTest, AsyncProcessingReportQueue) {
+  auto mock_queue = std::make_unique<MockReportQueue>();
+  EXPECT_CALL(*mock_queue, AddProducedRecord)
+      .Times(3)
+      .WillRepeatedly([](ReportQueue::RecordProducer record_producer,
+                         Priority event_priority,
+                         ReportQueue::EnqueueCallback cb) {
+        std::move(cb).Run(Status::StatusOK());
+      });
+
+  test::TestEvent<Status> a_string;
+  mock_queue->Enqueue(std::string(kTestMessage), priority_, a_string.cb());
+
+  test::TestEvent<Status> a_proto;
+  test::TestMessage test_message;
+  test_message.set_test(kTestMessage);
+  mock_queue->Enqueue(std::make_unique<test::TestMessage>(test_message),
+                      priority_, a_proto.cb());
+
+  test::TestEvent<Status> a_json;
+  constexpr char kTestKey[] = "TEST_KEY";
+  constexpr char kTestValue[] = "TEST_VALUE";
+  base::Value::Dict test_dict;
+  test_dict.Set(kTestKey, kTestValue);
+  mock_queue->Enqueue(std::move(test_dict), priority_, a_json.cb());
+
+  EXPECT_OK(a_string.result());
+  EXPECT_OK(a_proto.result());
+  EXPECT_OK(a_json.result());
+}
+
+TEST_F(ReportQueueImplTest, AsyncProcessingSpeculativeReportQueue) {
+  auto speculative_report_queue = SpeculativeReportQueueImpl::Create();
+
+  test::TestEvent<Status> a_string;
+  speculative_report_queue->Enqueue(std::string(kTestMessage), priority_,
+                                    a_string.cb());
+
+  test::TestEvent<Status> a_proto;
+  test::TestMessage test_message;
+  test_message.set_test(kTestMessage);
+  speculative_report_queue->Enqueue(
+      std::make_unique<test::TestMessage>(test_message), priority_,
+      a_proto.cb());
+
+  test::TestEvent<Status> a_json;
+  constexpr char kTestKey[] = "TEST_KEY";
+  constexpr char kTestValue[] = "TEST_VALUE";
+  base::Value::Dict test_dict;
+  test_dict.Set(kTestKey, kTestValue);
+  speculative_report_queue->Enqueue(std::move(test_dict), priority_,
+                                    a_json.cb());
+
+  EXPECT_OK(a_string.result());
+  EXPECT_OK(a_proto.result());
+  EXPECT_OK(a_json.result());
+
+  auto mock_queue = std::make_unique<MockReportQueue>();
+  EXPECT_CALL(*mock_queue, AddProducedRecord)
+      .Times(3)
+      .WillRepeatedly([](ReportQueue::RecordProducer record_producer,
+                         Priority event_priority,
+                         ReportQueue::EnqueueCallback cb) {
+        std::move(cb).Run(Status::StatusOK());
+      });
+  speculative_report_queue->AttachActualQueue(std::move(mock_queue));
+  // Let everything ongoing to finish.
+  task_environment_.RunUntilIdle();
+}
 }  // namespace
 }  // namespace reporting
diff --git a/components/search_engines/template_url_starter_pack_data.cc b/components/search_engines/template_url_starter_pack_data.cc
index d989fc8..f74af1e 100644
--- a/components/search_engines/template_url_starter_pack_data.cc
+++ b/components/search_engines/template_url_starter_pack_data.cc
@@ -4,6 +4,7 @@
 
 #include "components/search_engines/template_url_starter_pack_data.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "components/search_engines/search_engine_type.h"
 #include "components/search_engines/template_url_data.h"
 #include "components/search_engines/template_url_data_util.h"
@@ -15,21 +16,23 @@
 const int kCurrentDataVersion = 1;
 
 const StarterPackEngine bookmarks = {
-    IDS_SEARCH_ENGINES_STARTER_PACK_BOOKMARKS_NAME,
-    IDS_SEARCH_ENGINES_STARTER_PACK_BOOKMARKS_KEYWORD,
-    nullptr,
-    "chrome://bookmarks/?q={searchTerms}",
-    StarterPackID::kBookmarks,
-    SEARCH_ENGINE_STARTER_PACK_BOOKMARKS,
+    .name_message_id = IDS_SEARCH_ENGINES_STARTER_PACK_BOOKMARKS_NAME,
+    .keyword_message_id = IDS_SEARCH_ENGINES_STARTER_PACK_BOOKMARKS_KEYWORD,
+    .favicon_url = nullptr,
+    .search_url = "chrome://bookmarks/?q={searchTerms}",
+    .destination_url = "chrome://bookmarks",
+    .id = StarterPackID::kBookmarks,
+    .type = SEARCH_ENGINE_STARTER_PACK_BOOKMARKS,
 };
 
 const StarterPackEngine history = {
-    IDS_SEARCH_ENGINES_STARTER_PACK_HISTORY_NAME,
-    IDS_SEARCH_ENGINES_STARTER_PACK_HISTORY_KEYWORD,
-    nullptr,
-    "chrome://history/?q={searchTerms}",
-    StarterPackID::kHistory,
-    SEARCH_ENGINE_STARTER_PACK_HISTORY,
+    .name_message_id = IDS_SEARCH_ENGINES_STARTER_PACK_HISTORY_NAME,
+    .keyword_message_id = IDS_SEARCH_ENGINES_STARTER_PACK_HISTORY_KEYWORD,
+    .favicon_url = nullptr,
+    .search_url = "chrome://history/?q={searchTerms}",
+    .destination_url = "chrome://history",
+    .id = StarterPackID::kHistory,
+    .type = SEARCH_ENGINE_STARTER_PACK_HISTORY,
 };
 
 const StarterPackEngine* engines[] = {
@@ -50,4 +53,14 @@
   return t_urls;
 }
 
+std::u16string GetDestinationUrlForStarterPackID(int id) {
+  for (auto* engine : engines) {
+    if (engine->id == id) {
+      return base::UTF8ToUTF16(engine->destination_url);
+    }
+  }
+
+  return u"";
+}
+
 }  // namespace TemplateURLStarterPackData
diff --git a/components/search_engines/template_url_starter_pack_data.h b/components/search_engines/template_url_starter_pack_data.h
index a7d3cd2..db019de 100644
--- a/components/search_engines/template_url_starter_pack_data.h
+++ b/components/search_engines/template_url_starter_pack_data.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SEARCH_ENGINES_TEMPLATE_URL_STARTER_PACK_DATA_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "components/search_engines/search_engine_type.h"
@@ -32,6 +33,7 @@
   int keyword_message_id;
   const char* const favicon_url;
   const char* const search_url;
+  const char* const destination_url;
   const StarterPackID id;
   const SearchEngineType type;
 };
@@ -49,6 +51,10 @@
 // Returns a vector of all starter pack engines, in TemplateURLData format.
 std::vector<std::unique_ptr<TemplateURLData>> GetStarterPackEngines();
 
+// Returns the destination url for the starter pack engine associated with a
+// given starter pack id.
+std::u16string GetDestinationUrlForStarterPackID(int id);
+
 }  // namespace TemplateURLStarterPackData
 
 #endif  // COMPONENTS_SEARCH_ENGINES_TEMPLATE_URL_STARTER_PACK_DATA_H_
diff --git a/components/services/screen_ai/DEPS b/components/services/screen_ai/DEPS
index c12b2ff5e..7a6bb31 100644
--- a/components/services/screen_ai/DEPS
+++ b/components/services/screen_ai/DEPS
@@ -1,4 +1,8 @@
 include_rules = [
-  "+ui/accessibility",
+  "+ui/accessibility/accessibility_features.h",
+  "+ui/accessibility/ax_enum_util.h",
+  "+ui/accessibility/ax_enums.mojom.h",
+  "+ui/accessibility/ax_node_data.h",
+  "+ui/accessibility/ax_tree_update.h",
   "+ui/gfx/geometry",
 ]
diff --git a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.cc b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.cc
index c95e6d82..faa6c5c 100644
--- a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.cc
+++ b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.cc
@@ -105,6 +105,36 @@
   return true;
 }
 
+DisjointRangeLockManager::TestLockResult DisjointRangeLockManager::TestLock(
+    LeveledLockRequest request) {
+  if (request.level < 0 || static_cast<size_t>(request.level) >= locks_.size())
+    return TestLockResult::kInvalid;
+  if (request.range.begin >= request.range.end)
+    return TestLockResult::kInvalid;
+
+  auto& level_locks = locks_[request.level];
+
+  // TODO(dmurph): Remove this weird juggling we do here to support disjoint
+  // ranges once we remove range support. https://crbug.com/1322109
+  auto it = level_locks.find(request.range);
+  if (it == level_locks.end()) {
+    it = level_locks
+             .emplace(std::piecewise_construct,
+                      std::forward_as_tuple(request.range),
+                      std::forward_as_tuple())
+             .first;
+  }
+
+  if (!IsRangeDisjointFromNeighbors(level_locks, request.range)) {
+    level_locks.erase(it);
+    return TestLockResult::kInvalid;
+  }
+
+  Lock& lock = it->second;
+  return lock.CanBeAcquired(request.type) ? TestLockResult::kFree
+                                          : TestLockResult::kLocked;
+}
+
 void DisjointRangeLockManager::RemoveLockRange(int level,
                                                const LeveledLockRange& range) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -129,6 +159,8 @@
 
   auto& level_locks = locks_[request.level];
 
+  // TODO(dmurph): Remove this weird juggling we do here to support disjoint
+  // ranges once we remove range support. https://crbug.com/1322109
   auto it = level_locks.find(request.range);
   if (it == level_locks.end()) {
     it = level_locks
diff --git a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.h b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.h
index 23bf8d0..b680cd4df 100644
--- a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.h
+++ b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager.h
@@ -58,6 +58,10 @@
                     base::WeakPtr<LeveledLockHolder> locks_holder,
                     LocksAcquiredCallback callback) override;
 
+  enum class TestLockResult { kInvalid, kLocked, kFree };
+  // Tests to see if the given lock request can be acquired.
+  TestLockResult TestLock(LeveledLockRequest lock_requests);
+
   // Remove the given lock range at the given level. The lock range must not be
   // in use. Use this if the lock will never be used again.
   void RemoveLockRange(int level, const LeveledLockRange& range);
diff --git a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager_unittest.cc b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager_unittest.cc
index 78276b45..c564ba2 100644
--- a/components/services/storage/indexed_db/locks/disjoint_range_lock_manager_unittest.cc
+++ b/components/services/storage/indexed_db/locks/disjoint_range_lock_manager_unittest.cc
@@ -138,9 +138,15 @@
   base::RunLoop loop;
   {
     BarrierBuilder barrier(loop.QuitClosure());
+    EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kFree,
+              lock_manager.TestLock(
+                  {0, range, LeveledLockManager::LockType::kShared}));
     EXPECT_TRUE(lock_manager.AcquireLocks(
         {{0, range, LeveledLockManager::LockType::kShared}},
         locks_holder1.AsWeakPtr(), barrier.AddClosure()));
+    EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kFree,
+              lock_manager.TestLock(
+                  {0, range, LeveledLockManager::LockType::kShared}));
     EXPECT_TRUE(lock_manager.AcquireLocks(
         {{0, range, LeveledLockManager::LockType::kShared}},
         locks_holder2.AsWeakPtr(), barrier.AddClosure()));
@@ -180,6 +186,14 @@
   EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
   EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
 
+  // Exclusive request is blocked, shared is free.
+  EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kLocked,
+            lock_manager.TestLock(
+                {0, range, LeveledLockManager::LockType::kExclusive}));
+  EXPECT_EQ(
+      DisjointRangeLockManager::TestLockResult::kFree,
+      lock_manager.TestLock({0, range, LeveledLockManager::LockType::kShared}));
+
   // Both of the following locks should be queued - the exclusive is next in
   // line, then the shared lock will come after it.
   EXPECT_TRUE(lock_manager.AcquireLocks(
@@ -217,6 +231,14 @@
   EXPECT_EQ(1ll, lock_manager.LocksHeldForTesting());
   EXPECT_EQ(1ll, lock_manager.RequestsWaitingForTesting());
 
+  // Both exclusive and shared requests are blocked.
+  EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kLocked,
+            lock_manager.TestLock(
+                {0, range, LeveledLockManager::LockType::kExclusive}));
+  EXPECT_EQ(
+      DisjointRangeLockManager::TestLockResult::kLocked,
+      lock_manager.TestLock({0, range, LeveledLockManager::LockType::kShared}));
+
   exclusive_lock3_holder.locks.clear();
 
   // Flush the task queue to propagate the lock releases and grant the exclusive
@@ -240,9 +262,15 @@
   {
     BarrierBuilder barrier(loop.QuitClosure());
     LeveledLockRange range = {IntegerKey(0), IntegerKey(1)};
+    EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kFree,
+              lock_manager.TestLock(
+                  {0, range, LeveledLockManager::LockType::kExclusive}));
     EXPECT_TRUE(lock_manager.AcquireLocks(
         {{0, range, LeveledLockManager::LockType::kExclusive}},
         l0_lock_holder.AsWeakPtr(), barrier.AddClosure()));
+    EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kFree,
+              lock_manager.TestLock(
+                  {1, range, LeveledLockManager::LockType::kExclusive}));
     EXPECT_TRUE(lock_manager.AcquireLocks(
         {{1, range, LeveledLockManager::LockType::kExclusive}},
         l1_lock_holder.AsWeakPtr(), barrier.AddClosure()));
@@ -276,6 +304,9 @@
   EXPECT_FALSE(lock_manager.AcquireLocks(
       {{-1, range1, LeveledLockManager::LockType::kShared}},
       locks_holder.AsWeakPtr(), base::DoNothing()));
+  EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kInvalid,
+            lock_manager.TestLock(
+                {-1, range1, LeveledLockManager::LockType::kShared}));
   EXPECT_TRUE(locks_holder.locks.empty());
   EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
   EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
@@ -284,6 +315,9 @@
   EXPECT_FALSE(lock_manager.AcquireLocks(
       {{4, range1, LeveledLockManager::LockType::kShared}},
       locks_holder.AsWeakPtr(), base::DoNothing()));
+  EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kInvalid,
+            lock_manager.TestLock(
+                {4, range1, LeveledLockManager::LockType::kShared}));
   EXPECT_TRUE(locks_holder.locks.empty());
   EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
   EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
@@ -293,6 +327,9 @@
   EXPECT_FALSE(lock_manager.AcquireLocks(
       {{0, range3, LeveledLockManager::LockType::kShared}},
       locks_holder.AsWeakPtr(), base::DoNothing()));
+  EXPECT_EQ(DisjointRangeLockManager::TestLockResult::kInvalid,
+            lock_manager.TestLock(
+                {0, range3, LeveledLockManager::LockType::kShared}));
   EXPECT_TRUE(locks_holder.locks.empty());
   EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
   EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
diff --git a/components/test/data/webcrypto/rsa_oaep.json b/components/test/data/webcrypto/rsa_oaep.json
deleted file mode 100644
index 6a86348..0000000
--- a/components/test/data/webcrypto/rsa_oaep.json
+++ /dev/null
@@ -1,71 +0,0 @@
-[
-  // Format for tests:
-  //  public_key - the hex encoding of an RSA key as SubjectPublicKeyInfo
-  //  private_key - the hex encoding of an RSA key as PKCS#8 PrivateKeyInfo
-  //  hash - the hash name (same as in the digest tests) to use as both the
-  //    seed function and the MGF-1 digest function
-  //  label - the hex encoding of the label, or an empty string to indicate
-  //    that the empty string should be used
-  //  ciphertext / plaintext - hex encoded
-  // Tests for RSA-OAEP Encrypt/Decrypt without a label (the empty string).
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-1",
-    "label": "",
-    "ciphertext": "443FA1354F1DBC5C007A019CACCF18A3E6F986D7513D787F13DED463239F1833D6E33BFA8AF034C198B0D903F202F543FEF38FAF54018EB7794B4FE638CA4D87C564B845C0695D7E70C5D4464BEFF05225E747A6CA096A5E5E634002836D3CCE35713F082B20DCE7BB51324E4C89E202E3568E9F403ED864DE751BBE63E09680",
-    "plaintext": "666F6F64"
-  },
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-256",
-    "label": "",
-    "ciphertext": "4EBEBCA7297864FDEA44B3BF0E4D5AC26A8478E63642CED06182597DF247EC9883E72DFDC4507EE5058C52F6B929FBC34CE1FCF7C4A914D5B0C5C94638BDB0C70618E3F4FE79D291585DFD3197C4C16B57213337D12E59FC7A38617A1BE3DD2B09DA518E568712D2E6523F079C16EFCE540CAA829C5E39D62D64902A4E9D0BB3",
-    "plaintext": "666F6F64"
-  },
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-384",
-    "label": "",
-    "ciphertext": "67B83119BA513947000F3D7F144408FCBD6B22F93C01671C1E40607972BB991716EAA79B96FF8DEF95D8E673697E279096D035BA9ED79B9FCAC933A26FB003941CC8E8749511CEDFFACA653769AB5209E414B80D30A0DC44BE72E49A7FE732819C0DA4142FA0810FFF19E56EFB14EAA5649398E4C7D920B254CAE54F8019B25A",
-    "plaintext": "666F6F64"
-  },
-
-  // Tests for RSA-OAEP with an optional label specified.
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-1",
-    "label": "66656564206D65207365796D6F7572",
-    "ciphertext": "A27427C7CB3CD5B7D3C432B3F4BE98577B1FFBF302EDEFF0B219CABAB3E42DF7E8E24F9A89B387D314B199219F91B7F2CDE8E8D6F461A9495C3B5A398E0F670919EF62CCFF96CCF0FCAF178E5D898C332AAD342F4C42B3209B10CE04B0D004A3ED2514A707D617A321206C225084C1446BF17208C6D278B0EA3F5968D1D44590",
-    "plaintext": "666F6F64"
-  },
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-256",
-    "label": "66656564206D65207365796D6F7572",
-    "ciphertext": "333777A27C14C6186D2E90024507D7BD01D2A23FD462E9DBA6E9E96759A7025F29ABAA40DF6B3355648AE8FD90CD08D9D92529CAD337A6BED806D19B998E472EC0704205A6B83BDB4D4F5DB03FFE8BC68B44CA7F723A032161BD5B6D4517D58FAD8F1859676BC15A3BE9D20D78B11D73F79B23372CF4793F6301F612E820D67A",
-    "plaintext": "666F6F64"
-  },
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-384",
-    "label": "66656564206D65207365796D6F7572",
-    "ciphertext": "686D4B27EBD14F4745FB947459DE0D349E53C115F466245268E5C6B8C48FFFDAFB9C7737360D850A6865883ADD516E4AFE71AACE2A73083A4D991293D59199639CF27F6DC0799F785653C3B1E4213EC277A6FA121F6CD2F81E29F1A35A4604B473983CFEDACB00AA9786E92999DC9FA9AFDBDBB3F0EB3F49B301C5BFE14974BE",
-    "plaintext": "666F6F64"
-  },
-
-  // With RSA-OAEP, an empty message is valid.
-  {
-    "public_key": "30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a21370203010001",
-    "private_key": "30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
-    "hash": "sha-1",
-    "label": "",
-    "ciphertext": "5E35C080E4A0EBBB5AC8EE44888A6DB6B8C4D05A6427BE0ECBF245A23BCFC4A4A7D9E5466123511399F5D01A3CF910DD6FEBCA969B23C753A0574163D847E70E7EFBFBBF6CC01545560D620F00CFA33AE318AF6090B76E4ADC5FE1686165786F8B7E559156E8AF690D6EF050133AB5620FAF91B17CF52FED0B57FAC0924F2CC4",
-    "plaintext": ""
-  }
-]
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc
index 1c28222..bbc98d2 100644
--- a/components/viz/service/display_embedder/skia_output_device.cc
+++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -9,7 +9,9 @@
 
 #include "base/bind.h"
 #include "base/check_op.h"
+#include "base/feature_list.h"
 #include "base/notreached.h"
+#include "base/task/task_features.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
@@ -27,11 +29,18 @@
 namespace viz {
 namespace {
 
+const base::Feature kAsyncGpuLatencyReporting CONSTINIT{
+    "AsyncGpuLatencyReporting", base::FEATURE_ENABLED_BY_DEFAULT};
+
 using ::perfetto::protos::pbzero::ChromeLatencyInfo;
 
 scoped_refptr<base::SequencedTaskRunner> CreateLatencyTracerRunner() {
   if (!base::ThreadPoolInstance::Get())
     return nullptr;
+
+  if (!base::FeatureList::IsEnabled(kAsyncGpuLatencyReporting))
+    return nullptr;
+
   return base::ThreadPool::CreateSequencedTaskRunner(
       {base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
diff --git a/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/components/webcrypto/algorithms/rsa_oaep_unittest.cc
index da232f7..7db3bcb9 100644
--- a/components/webcrypto/algorithms/rsa_oaep_unittest.cc
+++ b/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -38,13 +38,15 @@
   return base64url_encoded;
 }
 
-std::unique_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() {
-  std::unique_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
-  jwk->SetString("kty", "RSA");
-  jwk->SetString("n",
-                 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex)));
-  jwk->SetString("e",
-                 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex)));
+base::Value::Dict CreatePublicKeyJwkDict(
+    base::flat_map<std::string, std::string> extra_properties) {
+  base::Value::Dict jwk;
+  jwk.Set("kty", "RSA");
+  jwk.Set("n", Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex)));
+  jwk.Set("e", Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex)));
+  for (const auto& prop : extra_properties) {
+    jwk.Set(prop.first, prop.second);
+  }
   return jwk;
 }
 
@@ -64,56 +66,44 @@
 }
 
 TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(
       Status::Success(),
       ImportKeyJwkFromDict(
-          *jwk,
+          CreatePublicKeyJwkDict({}),
           CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
                                          blink::kWebCryptoAlgorithmIdSha1),
           true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
 }
 
 TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-  jwk->SetString("alg", "RSA-OAEP");
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(
       Status::Success(),
       ImportKeyJwkFromDict(
-          *jwk,
+          CreatePublicKeyJwkDict({{"alg", "RSA-OAEP"}}),
           CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
                                          blink::kWebCryptoAlgorithmIdSha1),
           true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
 }
 
 TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-  jwk->SetString("alg", "RSA-OAEP-512");
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(
       Status::ErrorJwkAlgorithmInconsistent(),
       ImportKeyJwkFromDict(
-          *jwk,
+          CreatePublicKeyJwkDict({{"alg", "RSA-OAEP-512"}}),
           CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
                                          blink::kWebCryptoAlgorithmIdSha1),
           true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
 }
 
 TEST_F(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-  jwk->SetString("kty", "oct");
-  jwk->SetString("alg", "RSA-OAEP");
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(
       Status::ErrorJwkUnexpectedKty("RSA"),
       ImportKeyJwkFromDict(
-          *jwk,
+          CreatePublicKeyJwkDict({{"kty", "oct"}, {"alg", "RSA-OAEP"}}),
           CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep,
                                          blink::kWebCryptoAlgorithmIdSha1),
           true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
@@ -131,14 +121,11 @@
     const TestData& test_data = kTestData[i];
     SCOPED_TRACE(test_data.expected_jwk_alg);
 
-    std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-    jwk->SetString("alg", test_data.expected_jwk_alg);
-
     // Import the key in a known-good format
     blink::WebCryptoKey public_key;
     ASSERT_EQ(Status::Success(),
               ImportKeyJwkFromDict(
-                  *jwk,
+                  CreatePublicKeyJwkDict({{"alg", test_data.expected_jwk_alg}}),
                   CreateRsaHashedImportAlgorithm(
                       blink::kWebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
                   true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
@@ -153,28 +140,236 @@
   }
 }
 
+struct RsaOaepKnownAnswer {
+  const char* pubkey;
+  const char* privkey;
+  blink::WebCryptoAlgorithmId hash;
+  const char* label;
+  const char* ciphertext;
+  const char* plaintext;
+};
+
+const RsaOaepKnownAnswer kRsaOaepKnownAnswers[] = {
+    // Tests for RSA-OAEP Encrypt/Decrypt without a label (the empty string).
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha1, "",
+     "443FA1354F1DBC5C007A019CACCF18A3E6F986D7513D787F13DED463239F1833D6E33BFA8"
+     "AF034C198B0D903F202F543FEF38FAF54018EB7794B4FE638CA4D87C564B845C0695D7E70"
+     "C5D4464BEFF05225E747A6CA096A5E5E634002836D3CCE35713F082B20DCE7BB51324E4C8"
+     "9E202E3568E9F403ED864DE751BBE63E09680",
+     "666F6F64"},
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha256, "",
+     "4EBEBCA7297864FDEA44B3BF0E4D5AC26A8478E63642CED06182597DF247EC9883E72DFDC"
+     "4507EE5058C52F6B929FBC34CE1FCF7C4A914D5B0C5C94638BDB0C70618E3F4FE79D29158"
+     "5DFD3197C4C16B57213337D12E59FC7A38617A1BE3DD2B09DA518E568712D2E6523F079C1"
+     "6EFCE540CAA829C5E39D62D64902A4E9D0BB3",
+     "666F6F64"},
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha384, "",
+     "67B83119BA513947000F3D7F144408FCBD6B22F93C01671C1E40607972BB991716EAA79B9"
+     "6FF8DEF95D8E673697E279096D035BA9ED79B9FCAC933A26FB003941CC8E8749511CEDFFA"
+     "CA653769AB5209E414B80D30A0DC44BE72E49A7FE732819C0DA4142FA0810FFF19E56EFB1"
+     "4EAA5649398E4C7D920B254CAE54F8019B25A",
+     "666F6F64"},
+    // Tests for RSA-OAEP with an optional label specified.
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha1, "66656564206D65207365796D6F7572",
+     "A27427C7CB3CD5B7D3C432B3F4BE98577B1FFBF302EDEFF0B219CABAB3E42DF7E8E24F9A8"
+     "9B387D314B199219F91B7F2CDE8E8D6F461A9495C3B5A398E0F670919EF62CCFF96CCF0FC"
+     "AF178E5D898C332AAD342F4C42B3209B10CE04B0D004A3ED2514A707D617A321206C22508"
+     "4C1446BF17208C6D278B0EA3F5968D1D44590",
+     "666F6F64"},
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha256, "66656564206D65207365796D6F7572",
+     "333777A27C14C6186D2E90024507D7BD01D2A23FD462E9DBA6E9E96759A7025F29ABAA40D"
+     "F6B3355648AE8FD90CD08D9D92529CAD337A6BED806D19B998E472EC0704205A6B83BDB4D"
+     "4F5DB03FFE8BC68B44CA7F723A032161BD5B6D4517D58FAD8F1859676BC15A3BE9D20D78B"
+     "11D73F79B23372CF4793F6301F612E820D67A",
+     "666F6F64"},
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha384, "66656564206D65207365796D6F7572",
+     "686D4B27EBD14F4745FB947459DE0D349E53C115F466245268E5C6B8C48FFFDAFB9C77373"
+     "60D850A6865883ADD516E4AFE71AACE2A73083A4D991293D59199639CF27F6DC0799F7856"
+     "53C3B1E4213EC277A6FA121F6CD2F81E29F1A35A4604B473983CFEDACB00AA9786E92999D"
+     "C9FA9AFDBDBB3F0EB3F49B301C5BFE14974BE",
+     "666F6F64"},
+    // With RSA-OAEP, an empty message is valid.
+    {"30819f300d06092a864886f70d010101050003818d0030818902818100a56e4a0e7010175"
+     "89a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283"
+     "a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c"
+     "0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f2"
+     "0d0ce8cffb2249bd9a21370203010001",
+     "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810"
+     "0a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056"
+     "ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8"
+     "b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b"
+     "6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f545"
+     "1ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c02"
+     "66c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a3957"
+     "4501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6"
+     "dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8"
+     "6296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda"
+     "8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48d"
+     "e8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028"
+     "fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c0777"
+     "90427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa7120"
+     "49898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e16"
+     "78255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27"
+     "f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb219"
+     "0acf832b847f13a3d24a79f4d",
+     blink::kWebCryptoAlgorithmIdSha1, "",
+     "5E35C080E4A0EBBB5AC8EE44888A6DB6B8C4D05A6427BE0ECBF245A23BCFC4A4A7D9E5466"
+     "123511399F5D01A3CF910DD6FEBCA969B23C753A0574163D847E70E7EFBFBBF6CC0154556"
+     "0D620F00CFA33AE318AF6090B76E4ADC5FE1686165786F8B7E559156E8AF690D6EF050133"
+     "AB5620FAF91B17CF52FED0B57FAC0924F2CC4",
+     ""},
+};
+
 TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
-  base::Value::List tests = ReadJsonTestFileAsList("rsa_oaep.json");
-  for (const auto& test_value : tests) {
-    SCOPED_TRACE(&test_value - &tests[0]);
+  for (const auto& test : kRsaOaepKnownAnswers) {
+    SCOPED_TRACE(&test - &kRsaOaepKnownAnswers[0]);
 
-    ASSERT_TRUE(test_value.is_dict());
-    const base::DictionaryValue* test =
-        &base::Value::AsDictionaryValue(test_value);
-
-    blink::WebCryptoAlgorithm digest_algorithm =
-        GetDigestAlgorithm(test, "hash");
-    ASSERT_FALSE(digest_algorithm.IsNull());
-    std::vector<uint8_t> public_key_der =
-        GetBytesFromHexString(test, "public_key");
-    std::vector<uint8_t> private_key_der =
-        GetBytesFromHexString(test, "private_key");
-    std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext");
-    std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext");
-    std::vector<uint8_t> label = GetBytesFromHexString(test, "label");
+    std::vector<uint8_t> public_key_der = HexStringToBytes(test.pubkey);
+    std::vector<uint8_t> private_key_der = HexStringToBytes(test.privkey);
+    std::vector<uint8_t> ciphertext = HexStringToBytes(test.ciphertext);
+    std::vector<uint8_t> plaintext = HexStringToBytes(test.plaintext);
+    std::vector<uint8_t> label = HexStringToBytes(test.label);
 
     blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
-        blink::kWebCryptoAlgorithmIdRsaOaep, digest_algorithm.Id());
+        blink::kWebCryptoAlgorithmIdRsaOaep, test.hash);
     blink::WebCryptoKey public_key;
     blink::WebCryptoKey private_key;
 
@@ -202,12 +397,10 @@
   const blink::WebCryptoAlgorithmId kHash = blink::kWebCryptoAlgorithmIdSha1;
   const size_t kHashSize = 20;
 
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(Status::Success(),
             ImportKeyJwkFromDict(
-                *jwk,
+                CreatePublicKeyJwkDict({}),
                 CreateRsaHashedImportAlgorithm(
                     blink::kWebCryptoAlgorithmIdRsaOaep, kHash),
                 true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
@@ -257,12 +450,10 @@
 TEST_F(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
   const blink::WebCryptoAlgorithmId kHash = blink::kWebCryptoAlgorithmIdSha512;
 
-  std::unique_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
-
   blink::WebCryptoKey public_key;
   ASSERT_EQ(Status::Success(),
             ImportKeyJwkFromDict(
-                *jwk,
+                CreatePublicKeyJwkDict({}),
                 CreateRsaHashedImportAlgorithm(
                     blink::kWebCryptoAlgorithmIdRsaOaep, kHash),
                 true, blink::kWebCryptoKeyUsageEncrypt, &public_key));
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 4ea2ad7..4ca7ffbe 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -196,6 +196,8 @@
 
 namespace {
 
+using InvokedIn = ContentMainDelegate::InvokedIn;
+
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) && BUILDFLAG(IS_ANDROID)
 #if defined __LP64__
 #define kV8SnapshotDataDescriptor kV8Snapshot64DataDescriptor
@@ -616,8 +618,9 @@
   MainFunctionParams main_params(command_line);
   main_params.zygote_child = true;
 
-  InitializeFieldTrialAndFeatureList();
-  delegate->PostFieldTrialInitialization();
+  if (delegate->ShouldCreateFeatureList(InvokedIn::kChildProcess))
+    InitializeFieldTrialAndFeatureList();
+  delegate->PostEarlyInitialization(InvokedIn::kChildProcess);
 
   internal::PartitionAllocSupport::Get()->ReconfigureAfterFeatureListInit(
       process_type);
@@ -992,8 +995,9 @@
     if (process_type != switches::kZygoteProcess) {
       // Zygotes will run this at a later point in time when the command line
       // has been updated.
-      InitializeFieldTrialAndFeatureList();
-      delegate_->PostFieldTrialInitialization();
+      if (delegate_->ShouldCreateFeatureList(InvokedIn::kChildProcess))
+        InitializeFieldTrialAndFeatureList();
+      delegate_->PostEarlyInitialization(InvokedIn::kChildProcess);
 
       internal::PartitionAllocSupport::Get()->ReconfigureAfterFeatureListInit(
           process_type);
@@ -1051,14 +1055,16 @@
 
   bool should_start_minimal_browser = start_minimal_browser;
   if (!mojo_ipc_support_) {
-    if (delegate_->ShouldCreateFeatureList()) {
+    const auto invoked_in = main_params.ui_task
+                                ? InvokedIn::kBrowserProcessUnderTest
+                                : InvokedIn::kBrowserProcess;
+    if (delegate_->ShouldCreateFeatureList(invoked_in)) {
       // This is intentionally leaked since it needs to live for the duration
       // of the process and there's no benefit in cleaning it up at exit.
       base::FieldTrialList* leaked_field_trial_list =
           SetUpFieldTrialsAndFeatureList().release();
       ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
       std::ignore = leaked_field_trial_list;
-      delegate_->PostFieldTrialInitialization();
       mojo::core::InitFeatures();
     }
 
@@ -1089,7 +1095,7 @@
           variations::VariationsIdsProvider::Mode::kUseSignedInState);
     }
 
-    delegate_->PostEarlyInitialization(!!main_params.ui_task);
+    delegate_->PostEarlyInitialization(invoked_in);
 
     // The hang watcher needs to be started once the feature list is available
     // but before the IO thread is started.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index f6a133d4..e9983d94 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -412,11 +412,10 @@
     "attribution_reporting/attribution_internals_handler_impl.h",
     "attribution_reporting/attribution_internals_ui.cc",
     "attribution_reporting/attribution_internals_ui.h",
+    "attribution_reporting/attribution_manager.cc",
     "attribution_reporting/attribution_manager.h",
     "attribution_reporting/attribution_manager_impl.cc",
     "attribution_reporting/attribution_manager_impl.h",
-    "attribution_reporting/attribution_manager_provider.cc",
-    "attribution_reporting/attribution_manager_provider.h",
     "attribution_reporting/attribution_metrics.cc",
     "attribution_reporting/attribution_metrics.h",
     "attribution_reporting/attribution_observer.h",
diff --git a/content/browser/attribution_reporting/attribution_host.cc b/content/browser/attribution_reporting/attribution_host.cc
index 91182b26..f98f17d 100644
--- a/content/browser/attribution_reporting/attribution_host.cc
+++ b/content/browser/attribution_reporting/attribution_host.cc
@@ -12,7 +12,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "content/browser/attribution_reporting/attribution_data_host_manager.h"
 #include "content/browser/attribution_reporting/attribution_manager.h"
-#include "content/browser/attribution_reporting/attribution_manager_provider.h"
 #include "content/browser/attribution_reporting/attribution_metrics.h"
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
@@ -61,7 +60,6 @@
 AttributionHost::AttributionHost(WebContents* web_contents)
     : WebContentsObserver(web_contents),
       WebContentsUserData<AttributionHost>(*web_contents),
-      attribution_manager_provider_(AttributionManagerProvider::Default()),
       receivers_(web_contents, this) {
   // TODO(csharrison): When https://crbug.com/1051334 is resolved, add a DCHECK
   // that the kConversionMeasurement feature is enabled.
@@ -75,7 +73,7 @@
   // Impression navigations need to navigate the primary main frame to be valid.
   if (!navigation_handle->GetImpression() ||
       !navigation_handle->IsInPrimaryMainFrame() ||
-      !attribution_manager_provider_->GetManager(web_contents())) {
+      !AttributionManager::FromWebContents(web_contents())) {
     return;
   }
 
@@ -122,7 +120,7 @@
   }
 
   AttributionManager* attribution_manager =
-      attribution_manager_provider_->GetManager(web_contents());
+      AttributionManager::FromWebContents(web_contents());
   if (!attribution_manager) {
     DCHECK(navigation_impression_origins_.empty());
     if (navigation_handle->GetImpression())
@@ -174,7 +172,7 @@
 void AttributionHost::MaybeNotifyFailedSourceNavigation(
     NavigationHandle* navigation_handle) {
   auto* attribution_manager =
-      attribution_manager_provider_->GetManager(web_contents());
+      AttributionManager::FromWebContents(web_contents());
   if (!attribution_manager)
     return;
 
@@ -194,7 +192,7 @@
     mojo::PendingReceiver<blink::mojom::AttributionDataHost> data_host) {
   // If there is no attribution manager available, ignore any registrations.
   AttributionManager* attribution_manager =
-      attribution_manager_provider_->GetManager(web_contents());
+      AttributionManager::FromWebContents(web_contents());
   if (!attribution_manager)
     return;
 
@@ -231,7 +229,7 @@
     const blink::AttributionSrcToken& attribution_src_token) {
   // If there is no attribution manager available, ignore any registrations.
   AttributionManager* attribution_manager =
-      attribution_manager_provider_->GetManager(web_contents());
+      AttributionManager::FromWebContents(web_contents());
   if (!attribution_manager)
     return;
 
diff --git a/content/browser/attribution_reporting/attribution_host.h b/content/browser/attribution_reporting/attribution_host.h
index b2692f48..b54d318d 100644
--- a/content/browser/attribution_reporting/attribution_host.h
+++ b/content/browser/attribution_reporting/attribution_host.h
@@ -7,8 +7,6 @@
 
 #include <stdint.h>
 
-#include <memory>
-
 #include "base/containers/flat_map.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/render_frame_host_receiver_set.h"
@@ -18,7 +16,6 @@
 
 namespace content {
 
-class AttributionManagerProvider;
 class WebContents;
 
 // Class responsible for listening to conversion events originating from blink,
@@ -74,10 +71,6 @@
   using NavigationImpressionOriginMap = base::flat_map<int64_t, url::Origin>;
   NavigationImpressionOriginMap navigation_impression_origins_;
 
-  // Gives access to a AttributionManager implementation to forward impressions
-  // and conversion registrations to.
-  std::unique_ptr<AttributionManagerProvider> attribution_manager_provider_;
-
   RenderFrameHostReceiverSet<blink::mojom::ConversionHost> receivers_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
diff --git a/content/browser/attribution_reporting/attribution_host_unittest.cc b/content/browser/attribution_reporting/attribution_host_unittest.cc
index 868f964..b8fa819 100644
--- a/content/browser/attribution_reporting/attribution_host_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_host_unittest.cc
@@ -6,10 +6,10 @@
 
 #include <memory>
 
+#include "base/memory/raw_ptr.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "content/browser/attribution_reporting/attribution_data_host_manager.h"
 #include "content/browser/attribution_reporting/attribution_manager.h"
-#include "content/browser/attribution_reporting/attribution_manager_provider.h"
 #include "content/browser/attribution_reporting/attribution_source_type.h"
 #include "content/browser/attribution_reporting/attribution_test_utils.h"
 #include "content/browser/storage_partition_impl.h"
@@ -34,12 +34,6 @@
 
 class AttributionHostTestPeer {
  public:
-  static void SetAttributionManagerProvider(
-      AttributionHost* host,
-      std::unique_ptr<AttributionManagerProvider> provider) {
-    host->attribution_manager_provider_ = std::move(provider);
-  }
-
   static void SetCurrentTargetFrameForTesting(
       AttributionHost* conversion_host,
       RenderFrameHost* render_frame_host) {
@@ -66,13 +60,12 @@
   void SetUp() override {
     RenderViewHostTestHarness::SetUp();
 
-    AttributionHostTestPeer::SetAttributionManagerProvider(
-        conversion_host(),
-        std::make_unique<TestManagerProvider>(&mock_manager_));
-
     auto data_host_manager = std::make_unique<MockDataHostManager>();
     mock_data_host_manager_ = data_host_manager.get();
-    mock_manager_.SetDataHostManager(std::move(data_host_manager));
+
+    auto mock_manager = std::make_unique<MockAttributionManager>();
+    mock_manager->SetDataHostManager(std::move(data_host_manager));
+    OverrideAttributionManager(std::move(mock_manager));
 
     contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
   }
@@ -94,15 +87,27 @@
                                                              render_frame_host);
   }
 
- private:
-  MockAttributionManager mock_manager_;
+  void ClearAttributionManager() {
+    mock_data_host_manager_ = nullptr;
+    OverrideAttributionManager(nullptr);
+  }
 
- protected:
-  MockDataHostManager* mock_data_host_manager_;
+  MockDataHostManager* mock_data_host_manager() {
+    return mock_data_host_manager_;
+  }
+
+ private:
+  void OverrideAttributionManager(std::unique_ptr<AttributionManager> manager) {
+    static_cast<StoragePartitionImpl*>(
+        browser_context()->GetDefaultStoragePartition())
+        ->OverrideAttributionManagerForTesting(std::move(manager));
+  }
+
+  raw_ptr<MockDataHostManager> mock_data_host_manager_;
 };
 
 TEST_F(AttributionHostTest, NavigationWithNoImpression_Ignored) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost).Times(0);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost).Times(0);
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
   NavigationSimulatorImpl::NavigateAndCommitFromDocument(GURL(kConversionUrl),
@@ -112,7 +117,7 @@
 TEST_F(AttributionHostTest, ValidAttributionSrc_ForwardedToManager) {
   blink::Impression impression;
 
-  EXPECT_CALL(*mock_data_host_manager_,
+  EXPECT_CALL(*mock_data_host_manager(),
               NotifyNavigationForDataHost(
                   impression.attribution_src_token,
                   url::Origin::Create(GURL("https://secure_impression.com")),
@@ -126,9 +131,8 @@
   navigation->Commit();
 }
 
-TEST_F(AttributionHostTest, ImpressionWithNoManagerAvilable_NoCrash) {
-  AttributionHostTestPeer::SetAttributionManagerProvider(
-      conversion_host(), std::make_unique<TestManagerProvider>(nullptr));
+TEST_F(AttributionHostTest, ImpressionWithNoManagerAvailable_NoCrash) {
+  ClearAttributionManager();
 
   auto navigation = NavigationSimulatorImpl::CreateRendererInitiated(
       GURL(kConversionUrl), main_rfh());
@@ -138,7 +142,7 @@
 }
 
 TEST_F(AttributionHostTest, ImpressionInSubframe_Ignored) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost).Times(0);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost).Times(0);
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
 
@@ -158,7 +162,7 @@
 // Test that if we cannot access the initiator frame of the navigation, we
 // ignore the associated impression.
 TEST_F(AttributionHostTest, ImpressionNavigationWithDeadInitiator_Ignored) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost).Times(0);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost).Times(0);
 
   base::HistogramTester histograms;
 
@@ -176,7 +180,7 @@
 }
 
 TEST_F(AttributionHostTest, ImpressionNavigationCommitsToErrorPage_Ignored) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost).Times(0);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost).Times(0);
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
 
@@ -192,7 +196,7 @@
        AttributionSrcNavigationCommitsToErrorPage_Ignored) {
   blink::Impression impression;
 
-  EXPECT_CALL(*mock_data_host_manager_,
+  EXPECT_CALL(*mock_data_host_manager(),
               NotifyNavigationFailure(impression.attribution_src_token));
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
@@ -206,7 +210,7 @@
 }
 
 TEST_F(AttributionHostTest, ImpressionNavigationAborts_Ignored) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost).Times(0);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost).Times(0);
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
 
@@ -220,7 +224,7 @@
 TEST_F(AttributionHostTest, AttributionSrcNavigationAborts_Ignored) {
   blink::Impression impression;
 
-  EXPECT_CALL(*mock_data_host_manager_,
+  EXPECT_CALL(*mock_data_host_manager(),
               NotifyNavigationFailure(impression.attribution_src_token));
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
@@ -234,7 +238,7 @@
 
 TEST_F(AttributionHostTest,
        CommittedOriginDiffersFromConversionDesintation_Propagated) {
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost);
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost);
 
   contents()->NavigateAndCommit(GURL("https://secure_impression.com"));
 
@@ -282,7 +286,7 @@
        ImpressionNavigation_OriginTrustworthyChecksPerformed) {
   const OriginTrustworthyChecksTestCase& test_case = GetParam();
 
-  EXPECT_CALL(*mock_data_host_manager_, NotifyNavigationForDataHost)
+  EXPECT_CALL(*mock_data_host_manager(), NotifyNavigationForDataHost)
       .Times(test_case.impression_expected);
 
   contents()->NavigateAndCommit(GURL(test_case.impression_origin));
@@ -301,7 +305,7 @@
 
 TEST_F(AttributionHostTest, DataHost_RegisteredWithContext) {
   EXPECT_CALL(
-      *mock_data_host_manager_,
+      *mock_data_host_manager(),
       RegisterDataHost(_, url::Origin::Create(GURL("https://top.example"))));
 
   contents()->NavigateAndCommit(GURL("https://top.example"));
@@ -359,7 +363,7 @@
 }
 
 TEST_F(AttributionHostTest, DuplicateAttributionSrcToken_BadMessage) {
-  ON_CALL(*mock_data_host_manager_, RegisterNavigationDataHost)
+  ON_CALL(*mock_data_host_manager(), RegisterNavigationDataHost)
       .WillByDefault(Return(false));
 
   contents()->NavigateAndCommit(GURL("https://top.example"));
@@ -382,7 +386,7 @@
 
 TEST_F(AttributionHostTest, DataHostInSubframe_ContextIsOutermostFrame) {
   EXPECT_CALL(
-      *mock_data_host_manager_,
+      *mock_data_host_manager(),
       RegisterDataHost(_, url::Origin::Create(GURL("https://top.example"))));
 
   contents()->NavigateAndCommit(GURL("https://top.example"));
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
index 76037cf..87c6ef3 100644
--- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc
+++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -25,9 +25,9 @@
 #include "content/browser/attribution_reporting/send_result.h"
 #include "content/browser/attribution_reporting/storable_source.h"
 #include "content/browser/attribution_reporting/stored_source.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_controller.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -67,7 +67,7 @@
 auto InvokeCallback(std::vector<AttributionReport> value) {
   return
       [value = std::move(value)](
-          AttributionReport::ReportType report_type,
+          AttributionReport::ReportTypes report_types, int limit,
           base::OnceCallback<void(std::vector<AttributionReport>)> callback) {
         std::move(callback).Run(std::move(value));
       };
@@ -91,12 +91,25 @@
 
 class AttributionInternalsWebUiBrowserTest : public ContentBrowserTest {
  public:
-  AttributionInternalsWebUiBrowserTest() {
-    ON_CALL(manager_, GetActiveSourcesForWebUI)
+  AttributionInternalsWebUiBrowserTest() = default;
+
+  void SetUpOnMainThread() override {
+    ContentBrowserTest::SetUpOnMainThread();
+
+    auto manager = std::make_unique<MockAttributionManager>();
+    manager_ = manager.get();
+
+    ON_CALL(*manager_, GetActiveSourcesForWebUI)
         .WillByDefault(InvokeCallback(std::vector<StoredSource>{}));
 
-    ON_CALL(manager_, GetPendingReportsForInternalUse)
+    ON_CALL(*manager_, GetPendingReportsForInternalUse)
         .WillByDefault(InvokeCallback(std::vector<AttributionReport>{}));
+
+    static_cast<StoragePartitionImpl*>(shell()
+                                           ->web_contents()
+                                           ->GetBrowserContext()
+                                           ->GetDefaultStoragePartition())
+        ->OverrideAttributionManagerForTesting(std::move(manager));
   }
 
   void ClickRefreshButton() {
@@ -111,18 +124,6 @@
                   EXECUTE_SCRIPT_DEFAULT_OPTIONS, /*world_id=*/1);
   }
 
-  void OverrideWebUIAttributionManager() {
-    content::WebUI* web_ui = shell()->web_contents()->GetWebUI();
-
-    // Performs a safe downcast to the concrete AttributionInternalsUI subclass.
-    AttributionInternalsUI* attribution_internals_ui =
-        web_ui ? web_ui->GetController()->GetAs<AttributionInternalsUI>()
-               : nullptr;
-    EXPECT_TRUE(attribution_internals_ui);
-    attribution_internals_ui->SetAttributionManagerProviderForTesting(
-        std::make_unique<TestManagerProvider>(&manager_));
-  }
-
   // Registers a mutation observer that sets the window title to |title| when
   // the report table is empty.
   void SetTitleOnReportsTableEmpty(const std::u16string& title) {
@@ -141,11 +142,10 @@
         ExecJsInWebUI(JsReplace(kObserveEmptyReportsTableScript, title)));
   }
 
- protected:
-  // The manager must outlive the `AttributionInternalsHandler` so that the
-  // latter can remove itself as an observer of the former on the latter's
-  // destruction.
-  MockAttributionManager manager_;
+  MockAttributionManager* manager() { return manager_; }
+
+ private:
+  raw_ptr<MockAttributionManager> manager_;
 };
 
 IN_PROC_BROWSER_TEST_F(AttributionInternalsWebUiBrowserTest,
@@ -164,8 +164,6 @@
                        WebUIShownWithManager_MeasurementConsideredEnabled) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   // Create a mutation observer to wait for the content to render to the dom.
   // Waiting on calls to `MockAttributionManager` is not sufficient because the
   // results are returned in promises.
@@ -197,8 +195,6 @@
 
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   // Create a mutation observer to wait for the content to render to the dom.
   // Waiting on calls to `MockAttributionManager` is not sufficient because the
   // results are returned in promises.
@@ -223,8 +219,6 @@
     WebUIShownWithNoActiveImpression_NoImpressionsDisplayed) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   static constexpr char wait_script[] = R"(
     let table = document.querySelector('#sourceTable')
         .shadowRoot.querySelector('tbody');
@@ -248,15 +242,13 @@
                        WebUIShownWithActiveImpression_ImpressionsDisplayed) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   const base::Time now = base::Time::Now();
 
   // We use the max values of `uint64_t` and `int64_t` here to ensure that they
   // are properly handled as `bigint` values in JS and don't run into issues
   // with `Number.MAX_SAFE_INTEGER`.
 
-  ON_CALL(manager_, GetActiveSourcesForWebUI)
+  ON_CALL(*manager(), GetActiveSourcesForWebUI)
       .WillByDefault(InvokeCallback(
           {SourceBuilder(now)
                .SetSourceEventId(std::numeric_limits<uint64_t>::max())
@@ -277,25 +269,25 @@
                                    kReachedEventLevelAttributionLimit)
                .BuildStored()}));
 
-  manager_.NotifySourceDeactivated(
+  manager()->NotifySourceDeactivated(
       SourceBuilder(now + base::Hours(3)).BuildStored());
 
   // This shouldn't result in a row, as registration succeeded.
-  manager_.NotifySourceHandled(SourceBuilder(now).Build(),
-                               StorableSource::Result::kSuccess);
+  manager()->NotifySourceHandled(SourceBuilder(now).Build(),
+                                 StorableSource::Result::kSuccess);
 
-  manager_.NotifySourceHandled(SourceBuilder(now + base::Hours(4)).Build(),
-                               StorableSource::Result::kInternalError);
+  manager()->NotifySourceHandled(SourceBuilder(now + base::Hours(4)).Build(),
+                                 StorableSource::Result::kInternalError);
 
-  manager_.NotifySourceHandled(
+  manager()->NotifySourceHandled(
       SourceBuilder(now + base::Hours(5)).Build(),
       StorableSource::Result::kInsufficientSourceCapacity);
 
-  manager_.NotifySourceHandled(
+  manager()->NotifySourceHandled(
       SourceBuilder(now + base::Hours(6)).Build(),
       StorableSource::Result::kInsufficientUniqueDestinationCapacity);
 
-  manager_.NotifySourceHandled(
+  manager()->NotifySourceHandled(
       SourceBuilder(now + base::Hours(7)).Build(),
       StorableSource::Result::kExcessiveReportingOrigins);
 
@@ -342,8 +334,6 @@
                        WebUIShownWithNoReports_NoReportsDisplayed) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   TitleWatcher title_watcher(shell()->web_contents(), kCompleteTitle);
   SetTitleOnReportsTableEmpty(kCompleteTitle);
   ClickRefreshButton();
@@ -354,8 +344,6 @@
                        WebUIShownWithManager_DebugModeDisabled) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   // Create a mutation observer to wait for the content to render to the dom.
   // Waiting on calls to `MockAttributionManager` is not sufficient because the
   // results are returned in promises.
@@ -382,8 +370,6 @@
 
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   // Create a mutation observer to wait for the content to render to the dom.
   // Waiting on calls to `MockAttributionManager` is not sufficient because the
   // results are returned in promises.
@@ -409,9 +395,7 @@
 
   const base::Time now = base::Time::Now();
 
-  OverrideWebUIAttributionManager();
-
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(3))
@@ -419,14 +403,14 @@
       /*is_debug_report=*/false,
       SendResult(SendResult::Status::kSent, net::OK,
                  /*http_response_code=*/200));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(4))
           .SetPriority(-1)
           .Build(),
       /*is_debug_report=*/false, SendResult(SendResult::Status::kDropped));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(5))
@@ -434,7 +418,7 @@
           .Build(),
       /*is_debug_report=*/false,
       SendResult(SendResult::Status::kFailure, net::ERR_METHOD_NOT_SUPPORTED));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(11))
@@ -443,7 +427,7 @@
       /*is_debug_report=*/true,
       SendResult(SendResult::Status::kTransientFailure, net::ERR_TIMED_OUT));
 
-  ON_CALL(manager_, GetPendingReportsForInternalUse)
+  ON_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillByDefault(InvokeCallback(
           {ReportBuilder(AttributionInfoBuilder(
                              SourceBuilder(now)
@@ -455,7 +439,7 @@
                .SetReportTime(now)
                .SetPriority(13)
                .Build()}));
-  manager_.NotifyTriggerHandled(
+  manager()->NotifyTriggerHandled(
       DefaultTrigger(),
       CreateReportResult(
           /*trigger_time=*/base::Time::Now(),
@@ -585,24 +569,22 @@
 
   const base::Time now = base::Time::Now();
 
-  OverrideWebUIAttributionManager();
-
   AttributionReport report =
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now)
           .SetPriority(7)
           .Build();
-  EXPECT_CALL(manager_, GetPendingReportsForInternalUse)
+  EXPECT_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillOnce(InvokeCallback({report}))
       .WillOnce(InvokeCallback(std::vector<AttributionReport>{}));
   report.set_report_time(report.report_time() + base::Hours(1));
-  manager_.NotifyReportSent(report,
-                            /*is_debug_report=*/false,
-                            SendResult(SendResult::Status::kSent, net::OK,
-                                       /*http_response_code=*/200));
+  manager()->NotifyReportSent(report,
+                              /*is_debug_report=*/false,
+                              SendResult(SendResult::Status::kSent, net::OK,
+                                         /*http_response_code=*/200));
 
-  EXPECT_CALL(manager_, ClearData)
+  EXPECT_CALL(*manager(), ClearData)
       .WillOnce([](base::Time delete_begin, base::Time delete_end,
                    base::RepeatingCallback<bool(const url::Origin&)> filter,
                    base::OnceClosure done) { std::move(done).Run(); });
@@ -641,18 +623,16 @@
                        ClearButton_ClearsSourceTable) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  OverrideWebUIAttributionManager();
-
   base::Time now = base::Time::Now();
 
-  ON_CALL(manager_, GetActiveSourcesForWebUI)
+  ON_CALL(*manager(), GetActiveSourcesForWebUI)
       .WillByDefault(InvokeCallback(
           {SourceBuilder(now).SetSourceEventId(5).BuildStored()}));
 
-  manager_.NotifySourceDeactivated(
+  manager()->NotifySourceDeactivated(
       SourceBuilder(now + base::Hours(2)).SetSourceEventId(6).BuildStored());
 
-  EXPECT_CALL(manager_, ClearData)
+  EXPECT_CALL(*manager(), ClearData)
       .WillOnce([](base::Time delete_begin, base::Time delete_end,
                    base::RepeatingCallback<bool(const url::Origin&)> filter,
                    base::OnceClosure done) { std::move(done).Run(); });
@@ -703,7 +683,7 @@
                        WebUISendReports_ReportsRemoved) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  EXPECT_CALL(manager_, GetPendingReportsForInternalUse)
+  EXPECT_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillOnce(InvokeCallback(
           {ReportBuilder(
                AttributionInfoBuilder(SourceBuilder().BuildStored()).Build())
@@ -714,7 +694,7 @@
       .WillOnce(InvokeCallback(std::vector<AttributionReport>{}));
 
   EXPECT_CALL(
-      manager_,
+      *manager(),
       SendReportsForWebUI(
           ElementsAre(VariantWith<AttributionReport::EventLevelData::Id>(
               AttributionReport::EventLevelData::Id(5))),
@@ -722,8 +702,6 @@
       .WillOnce([](const std::vector<AttributionReport::Id>& ids,
                    base::OnceClosure done) { std::move(done).Run(); });
 
-  OverrideWebUIAttributionManager();
-
   static constexpr char wait_script[] = R"(
     let table = document.querySelector('#reportTable')
         .shadowRoot.querySelector('tbody');
@@ -763,7 +741,7 @@
 
   // The real manager would do this itself, but the test manager requires manual
   // triggering.
-  manager_.NotifyReportsChanged(AttributionReport::ReportType::kEventLevel);
+  manager()->NotifyReportsChanged(AttributionReport::ReportType::kEventLevel);
 
   ASSERT_EQ(kSentTitle, sent_title_watcher.WaitAndGetTitle());
 }
@@ -797,12 +775,10 @@
 
   const base::Time now = base::Time::Now();
 
-  OverrideWebUIAttributionManager();
-
   std::vector<AggregatableHistogramContribution> contributions{
       AggregatableHistogramContribution(1, 2)};
 
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(3))
@@ -811,14 +787,14 @@
       /*is_debug_report=*/false,
       SendResult(SendResult::Status::kSent, net::OK,
                  /*http_response_code=*/200));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(4))
           .SetAggregatableHistogramContributions(contributions)
           .BuildAggregatableAttribution(),
       /*is_debug_report=*/false, SendResult(SendResult::Status::kDropped));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(5))
@@ -826,7 +802,7 @@
           .BuildAggregatableAttribution(),
       /*is_debug_report=*/false,
       SendResult(SendResult::Status::kFailedToAssemble));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(6))
@@ -834,7 +810,7 @@
           .BuildAggregatableAttribution(),
       /*is_debug_report=*/false,
       SendResult(SendResult::Status::kFailure, net::ERR_INVALID_REDIRECT));
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(10))
@@ -843,7 +819,7 @@
       /*is_debug_report=*/true,
       SendResult(SendResult::Status::kTransientFailure,
                  net::ERR_INTERNET_DISCONNECTED));
-  ON_CALL(manager_, GetPendingReportsForInternalUse)
+  ON_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillByDefault(InvokeCallback(
           {ReportBuilder(AttributionInfoBuilder(
                              SourceBuilder(now)
@@ -913,8 +889,6 @@
       },
       AttributionAggregatableTrigger());
 
-  OverrideWebUIAttributionManager();
-
   static constexpr char kWantEventTriggerJSON[] =
       R"json([ {  "data": "2",  "priority": "3",  "filters": {   "c": [    "d"   ]  } }, {  "data": "4",  "priority": "5",  "deduplication_key": "6",  "not_filters": {   "e": [    "f"   ]  } }])json";
 
@@ -942,7 +916,7 @@
       [&](AttributionTrigger::EventLevelResult event_status,
           AttributionTrigger::AggregatableResult aggregatable_status) {
         static int offset_hours = 0;
-        manager_.NotifyTriggerHandled(
+        manager()->NotifyTriggerHandled(
             trigger,
             CreateReportResult(
                 /*trigger_time=*/now + base::Hours(++offset_hours),
@@ -966,7 +940,7 @@
                        WebUISendAggregatableReports_ReportsRemoved) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL(kAttributionInternalsUrl)));
 
-  EXPECT_CALL(manager_, GetPendingReportsForInternalUse)
+  EXPECT_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillOnce(InvokeCallback(std::vector<AttributionReport>{}))
       .WillOnce(InvokeCallback(
           {ReportBuilder(
@@ -979,7 +953,7 @@
       .WillOnce(InvokeCallback(std::vector<AttributionReport>{}));
 
   EXPECT_CALL(
-      manager_,
+      *manager(),
       SendReportsForWebUI(
           ElementsAre(
               VariantWith<AttributionReport::AggregatableAttributionData::Id>(
@@ -988,8 +962,6 @@
       .WillOnce([](const std::vector<AttributionReport::Id>& ids,
                    base::OnceClosure done) { std::move(done).Run(); });
 
-  OverrideWebUIAttributionManager();
-
   static constexpr char wait_script[] = R"(
     let table = document.querySelector('#aggregatableReportTable')
         .shadowRoot.querySelector('tbody');
@@ -1033,7 +1005,7 @@
 
   // The real manager would do this itself, but the test manager requires manual
   // triggering.
-  manager_.NotifyReportsChanged(
+  manager()->NotifyReportsChanged(
       AttributionReport::ReportType::kAggregatableAttribution);
 
   EXPECT_EQ(kSentTitle, sent_title_watcher.WaitAndGetTitle());
@@ -1045,9 +1017,7 @@
 
   const base::Time now = base::Time::Now();
 
-  OverrideWebUIAttributionManager();
-
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now)
@@ -1057,7 +1027,7 @@
       SendResult(SendResult::Status::kSent, net::OK,
                  /*http_response_code=*/200));
 
-  ON_CALL(manager_, GetPendingReportsForInternalUse)
+  ON_CALL(*manager(), GetPendingReportsForInternalUse)
       .WillByDefault(InvokeCallback(
           {ReportBuilder(
                AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
@@ -1093,7 +1063,7 @@
   EXPECT_TRUE(ExecJsInWebUI(R"(
       document.querySelector('#show-debug-event-reports input').click();)"));
 
-  manager_.NotifyReportSent(
+  manager()->NotifyReportSent(
       ReportBuilder(
           AttributionInfoBuilder(SourceBuilder(now).BuildStored()).Build())
           .SetReportTime(now + base::Hours(2))
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
index 9f8ec68..dd663d1 100644
--- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
+++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -19,7 +19,6 @@
 #include "content/browser/attribution_reporting/aggregatable_attribution_utils.h"
 #include "content/browser/attribution_reporting/attribution_aggregatable_source.h"
 #include "content/browser/attribution_reporting/attribution_info.h"
-#include "content/browser/attribution_reporting/attribution_manager_provider.h"
 #include "content/browser/attribution_reporting/attribution_observer_types.h"
 #include "content/browser/attribution_reporting/attribution_report.h"
 #include "content/browser/attribution_reporting/attribution_trigger.h"
@@ -177,9 +176,7 @@
 AttributionInternalsHandlerImpl::AttributionInternalsHandlerImpl(
     WebUI* web_ui,
     mojo::PendingReceiver<attribution_internals::mojom::Handler> receiver)
-    : web_ui_(web_ui),
-      manager_provider_(AttributionManagerProvider::Default()),
-      receiver_(this, std::move(receiver)) {}
+    : web_ui_(web_ui), receiver_(this, std::move(receiver)) {}
 
 AttributionInternalsHandlerImpl::~AttributionInternalsHandlerImpl() = default;
 
@@ -188,7 +185,7 @@
         callback) {
   content::WebContents* contents = web_ui_->GetWebContents();
   bool attribution_reporting_enabled =
-      manager_provider_->GetManager(contents) &&
+      AttributionManager::FromWebContents(contents) &&
       GetContentClient()->browser()->IsConversionMeasurementOperationAllowed(
           contents->GetBrowserContext(),
           ContentBrowserClient::ConversionMeasurementOperation::kAny,
@@ -202,7 +199,7 @@
 void AttributionInternalsHandlerImpl::GetActiveSources(
     attribution_internals::mojom::Handler::GetActiveSourcesCallback callback) {
   if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
+          AttributionManager::FromWebContents(web_ui_->GetWebContents())) {
     manager->GetActiveSourcesForWebUI(
         base::BindOnce(&ForwardSourcesToWebUI, std::move(callback)));
   } else {
@@ -214,9 +211,10 @@
     AttributionReport::ReportType report_type,
     attribution_internals::mojom::Handler::GetReportsCallback callback) {
   if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
+          AttributionManager::FromWebContents(web_ui_->GetWebContents())) {
     manager->GetPendingReportsForInternalUse(
-        report_type,
+        AttributionReport::ReportTypes{report_type},
+        /*limit=*/1000,
         base::BindOnce(&ForwardReportsToWebUI, std::move(callback)));
   } else {
     std::move(callback).Run({});
@@ -227,7 +225,7 @@
     const std::vector<AttributionReport::Id>& ids,
     attribution_internals::mojom::Handler::SendReportsCallback callback) {
   if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
+          AttributionManager::FromWebContents(web_ui_->GetWebContents())) {
     manager->SendReportsForWebUI(ids, std::move(callback));
   } else {
     std::move(callback).Run();
@@ -237,7 +235,7 @@
 void AttributionInternalsHandlerImpl::ClearStorage(
     attribution_internals::mojom::Handler::ClearStorageCallback callback) {
   if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
+          AttributionManager::FromWebContents(web_ui_->GetWebContents())) {
     manager->ClearData(base::Time::Min(), base::Time::Max(),
                        base::NullCallback(), std::move(callback));
   } else {
@@ -249,7 +247,7 @@
     mojo::PendingRemote<attribution_internals::mojom::Observer> observer,
     attribution_internals::mojom::Handler::AddObserverCallback callback) {
   if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
+          AttributionManager::FromWebContents(web_ui_->GetWebContents())) {
     observers_.Add(std::move(observer));
 
     if (!manager_observation_.IsObservingSource(manager))
@@ -460,17 +458,4 @@
   }
 }
 
-void AttributionInternalsHandlerImpl::SetAttributionManagerProviderForTesting(
-    std::unique_ptr<AttributionManagerProvider> manager_provider) {
-  DCHECK(manager_provider);
-
-  manager_observation_.Reset();
-  manager_provider_ = std::move(manager_provider);
-
-  if (AttributionManager* manager =
-          manager_provider_->GetManager(web_ui_->GetWebContents())) {
-    manager_observation_.Observe(manager);
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.h b/content/browser/attribution_reporting/attribution_internals_handler_impl.h
index 87028f4..1c99e34a 100644
--- a/content/browser/attribution_reporting/attribution_internals_handler_impl.h
+++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.h
@@ -17,7 +17,6 @@
 
 namespace content {
 
-class AttributionManagerProvider;
 class WebUI;
 
 // Implements the mojo endpoint for the attribution internals WebUI which
@@ -62,9 +61,6 @@
       attribution_internals::mojom::Handler::AddObserverCallback callback)
       override;
 
-  void SetAttributionManagerProviderForTesting(
-      std::unique_ptr<AttributionManagerProvider> manager_provider);
-
  private:
   // AttributionObserver:
   void OnSourcesChanged() override;
@@ -79,7 +75,6 @@
                         const CreateReportResult& result) override;
 
   raw_ptr<WebUI> web_ui_;
-  std::unique_ptr<AttributionManagerProvider> manager_provider_;
 
   mojo::Receiver<attribution_internals::mojom::Handler> receiver_;
 
diff --git a/content/browser/attribution_reporting/attribution_internals_ui.cc b/content/browser/attribution_reporting/attribution_internals_ui.cc
index e9473638..703c75e 100644
--- a/content/browser/attribution_reporting/attribution_internals_ui.cc
+++ b/content/browser/attribution_reporting/attribution_internals_ui.cc
@@ -5,7 +5,6 @@
 #include "content/browser/attribution_reporting/attribution_internals_ui.h"
 
 #include "content/browser/attribution_reporting/attribution_internals_handler_impl.h"
-#include "content/browser/attribution_reporting/attribution_manager_provider.h"
 #include "content/grit/dev_ui_content_resources.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -60,10 +59,4 @@
       web_ui(), std::move(receiver));
 }
 
-void AttributionInternalsUI::SetAttributionManagerProviderForTesting(
-    std::unique_ptr<AttributionManagerProvider> manager_provider) {
-  ui_handler_->SetAttributionManagerProviderForTesting(
-      std::move(manager_provider));
-}
-
 }  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_internals_ui.h b/content/browser/attribution_reporting/attribution_internals_ui.h
index 26db2e6..2587d7e 100644
--- a/content/browser/attribution_reporting/attribution_internals_ui.h
+++ b/content/browser/attribution_reporting/attribution_internals_ui.h
@@ -17,7 +17,6 @@
 namespace content {
 
 class AttributionInternalsHandlerImpl;
-class AttributionManagerProvider;
 class AttributionInternalsUI;
 
 // WebUIConfig for chrome://attribution-internals page
@@ -46,9 +45,6 @@
   void BindInterface(
       mojo::PendingReceiver<attribution_internals::mojom::Handler> receiver);
 
-  void SetAttributionManagerProviderForTesting(
-      std::unique_ptr<AttributionManagerProvider> manager_provider);
-
  private:
   std::unique_ptr<AttributionInternalsHandlerImpl> ui_handler_;
 
diff --git a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
index d7c7a39..dfe463afb 100644
--- a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
@@ -103,7 +103,6 @@
         "report_url": "https://r.example/path",
         "report": {
           "attribution_destination": "https://d.test",
-          "source_site": "https://s.test"
         },
         "test_info": {
           "histograms": [{
@@ -131,7 +130,6 @@
         "report_url": "https://r.example/path",
         "payload": {
           "attribution_destination": "https://d.test",
-          "source_site": "https://s.test",
           "histograms": [{
             "key": "key",
             "value": "0x159"
diff --git a/content/browser/attribution_reporting/attribution_manager.cc b/content/browser/attribution_reporting/attribution_manager.cc
new file mode 100644
index 0000000..769ec9a
--- /dev/null
+++ b/content/browser/attribution_reporting/attribution_manager.cc
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/attribution_reporting/attribution_manager.h"
+
+#include "base/check.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+// static
+AttributionManager* AttributionManager::FromWebContents(
+    WebContents* web_contents) {
+  DCHECK(web_contents);
+  return static_cast<StoragePartitionImpl*>(
+             web_contents->GetBrowserContext()->GetDefaultStoragePartition())
+      ->GetAttributionManager();
+}
+
+}  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_manager.h b/content/browser/attribution_reporting/attribution_manager.h
index 312a449..1854a722 100644
--- a/content/browser/attribution_reporting/attribution_manager.h
+++ b/content/browser/attribution_reporting/attribution_manager.h
@@ -25,11 +25,14 @@
 class AttributionTrigger;
 class StorableSource;
 class StoredSource;
+class WebContents;
 
 // Interface that mediates data flow between the network, storage layer, and
 // blink.
 class AttributionManager {
  public:
+  static AttributionManager* FromWebContents(WebContents* web_contents);
+
   virtual ~AttributionManager() = default;
 
   virtual void AddObserver(AttributionObserver* observer) = 0;
@@ -55,7 +58,8 @@
   // Get all pending reports that are currently stored in this partition. Used
   // for populating WebUI and simulator.
   virtual void GetPendingReportsForInternalUse(
-      AttributionReport::ReportType report_type,
+      AttributionReport::ReportTypes report_types,
+      int limit,
       base::OnceCallback<void(std::vector<AttributionReport>)> callback) = 0;
 
   // Sends the given reports immediately, and runs |done| once they have all
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc
index 9b899ec..312aae7 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -544,12 +544,12 @@
 }
 
 void AttributionManagerImpl::GetPendingReportsForInternalUse(
-    AttributionReport::ReportType report_type,
+    AttributionReport::ReportTypes report_types,
+    int limit,
     base::OnceCallback<void(std::vector<AttributionReport>)> callback) {
   attribution_storage_.AsyncCall(&AttributionStorage::GetAttributionReports)
       .WithArgs(
-          /*max_report_time=*/base::Time::Max(), /*limit=*/1000,
-          AttributionReport::ReportTypes{report_type})
+          /*max_report_time=*/base::Time::Max(), limit, std::move(report_types))
       .Then(std::move(callback));
 }
 
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.h b/content/browser/attribution_reporting/attribution_manager_impl.h
index 77977ea7..bc641faa3 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl.h
+++ b/content/browser/attribution_reporting/attribution_manager_impl.h
@@ -92,7 +92,8 @@
   void GetActiveSourcesForWebUI(
       base::OnceCallback<void(std::vector<StoredSource>)> callback) override;
   void GetPendingReportsForInternalUse(
-      AttributionReport::ReportType report_type,
+      AttributionReport::ReportTypes report_types,
+      int limit,
       base::OnceCallback<void(std::vector<AttributionReport>)> callback)
       override;
   void SendReportsForWebUI(const std::vector<AttributionReport::Id>& ids,
@@ -163,11 +164,6 @@
 
   bool IsReportAllowed(const AttributionReport&) const;
 
-  // Friend to expose the AttributionStorage for certain tests.
-  friend std::vector<AttributionReport> GetAttributionReportsForTesting(
-      AttributionManagerImpl* manager,
-      base::Time max_report_time);
-
   // Never null.
   const raw_ptr<StoragePartitionImpl> storage_partition_;
 
diff --git a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
index 9279610..65aa6bb 100644
--- a/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_manager_impl_unittest.cc
@@ -319,8 +319,7 @@
   }
 
   std::vector<AttributionReport> StoredReports() {
-    return GetAttributionReportsForTesting(
-        attribution_manager_.get(), /*max_report_time=*/base::Time::Max());
+    return GetAttributionReportsForTesting(attribution_manager_.get());
   }
 
   void ForceGetReportsToSend() { attribution_manager_->GetReportsToSend(); }
diff --git a/content/browser/attribution_reporting/attribution_manager_provider.cc b/content/browser/attribution_reporting/attribution_manager_provider.cc
deleted file mode 100644
index d8cb65a..0000000
--- a/content/browser/attribution_reporting/attribution_manager_provider.cc
+++ /dev/null
@@ -1,49 +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/attribution_reporting/attribution_manager_provider.h"
-
-#include "content/browser/attribution_reporting/attribution_manager_impl.h"
-#include "content/browser/storage_partition_impl.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents.h"
-
-namespace content {
-
-namespace {
-
-class AttributionManagerProviderImpl : public AttributionManagerProvider {
- public:
-  AttributionManagerProviderImpl() = default;
-
-  ~AttributionManagerProviderImpl() override = default;
-
-  AttributionManagerProviderImpl(const AttributionManagerProviderImpl&) =
-      delete;
-  AttributionManagerProviderImpl(AttributionManagerProviderImpl&&) = delete;
-
-  AttributionManagerProviderImpl& operator=(
-      const AttributionManagerProviderImpl&) = delete;
-  AttributionManagerProviderImpl& operator=(AttributionManagerProviderImpl&&) =
-      delete;
-
- private:
-  // AttributionManagerProvider:
-  AttributionManager* GetManager(WebContents* web_contents) const override {
-    return static_cast<StoragePartitionImpl*>(
-               web_contents->GetBrowserContext()->GetDefaultStoragePartition())
-        ->GetAttributionManager();
-  }
-};
-
-}  // namespace
-
-// static
-std::unique_ptr<AttributionManagerProvider>
-AttributionManagerProvider::Default() {
-  return std::make_unique<AttributionManagerProviderImpl>();
-}
-
-}  // namespace content
diff --git a/content/browser/attribution_reporting/attribution_manager_provider.h b/content/browser/attribution_reporting/attribution_manager_provider.h
deleted file mode 100644
index 0593f66..0000000
--- a/content/browser/attribution_reporting/attribution_manager_provider.h
+++ /dev/null
@@ -1,34 +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 CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_PROVIDER_H_
-#define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_PROVIDER_H_
-
-#include <memory>
-
-namespace content {
-
-class AttributionManager;
-class WebContents;
-
-// Provides access to an `AttributionManager` implementation. This layer of
-// abstraction is to allow tests to mock out the `AttributionManager` without
-// injecting a manager explicitly.
-class AttributionManagerProvider {
- public:
-  // Provides access to the manager owned by the default `StoragePartition`.
-  static std::unique_ptr<AttributionManagerProvider> Default();
-
-  virtual ~AttributionManagerProvider() = default;
-
-  // Gets the `AttributionManager` that should be used for handling attributions
-  // that occur in the given `web_contents`. Returns `nullptr` if attribution
-  // reporting is not enabled in the given `web_contents`, e.g. when the
-  // browser context is off the record.
-  virtual AttributionManager* GetManager(WebContents* web_contents) const = 0;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_MANAGER_PROVIDER_H_
diff --git a/content/browser/attribution_reporting/attribution_report.cc b/content/browser/attribution_reporting/attribution_report.cc
index d81e437..7314e923 100644
--- a/content/browser/attribution_reporting/attribution_report.cc
+++ b/content/browser/attribution_reporting/attribution_report.cc
@@ -201,7 +201,6 @@
       const CommonSourceInfo& common_info =
           report->attribution_info().source.common_info();
 
-      dict.Set("source_site", common_info.ImpressionSite().Serialize());
       dict.Set("attribution_destination",
                common_info.ConversionDestination().Serialize());
 
diff --git a/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc b/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc
index 747f9e0..0584f25ca 100644
--- a/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc
@@ -619,8 +619,7 @@
       R"({"aggregation_service_payloads":"not generated prior to send",)"
       R"("attribution_destination":"https://conversion.test",)"
       R"("shared_info":"not generated prior to send",)"
-      R"("source_registration_time":"1234483200",)"
-      R"("source_site":"https://impression.test"})";
+      R"("source_registration_time":"1234483200"})";
 
   AttributionReport report =
       ReportBuilder(AttributionInfoBuilder(
@@ -648,8 +647,7 @@
       R"({"aggregation_service_payloads":"not generated prior to send",)"
       R"("attribution_destination":"https://conversion.test",)"
       R"("shared_info":"not generated prior to send",)"
-      R"("source_registration_time":"1234483200",)"
-      R"("source_site":"https://impression.test"})";
+      R"("source_registration_time":"1234483200"})";
 
   AttributionReport report =
       ReportBuilder(AttributionInfoBuilder(
diff --git a/content/browser/attribution_reporting/attribution_test_utils.cc b/content/browser/attribution_reporting/attribution_test_utils.cc
index 3bafa911..e43835f7 100644
--- a/content/browser/attribution_reporting/attribution_test_utils.cc
+++ b/content/browser/attribution_reporting/attribution_test_utils.cc
@@ -19,7 +19,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task/task_runner_util.h"
 #include "base/test/bind.h"
-#include "content/browser/attribution_reporting/attribution_manager_impl.h"
 #include "content/browser/attribution_reporting/attribution_observer.h"
 #include "content/browser/attribution_reporting/rate_limit_result.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -362,11 +361,6 @@
   source_event_id_cardinality_ = cardinality;
 }
 
-AttributionManager* TestManagerProvider::GetManager(
-    WebContents* web_contents) const {
-  return manager_;
-}
-
 MockAttributionManager::MockAttributionManager() = default;
 
 MockAttributionManager::~MockAttributionManager() = default;
@@ -1368,17 +1362,15 @@
 }
 
 std::vector<AttributionReport> GetAttributionReportsForTesting(
-    AttributionManagerImpl* manager,
-    base::Time max_report_time) {
+    AttributionManager* manager) {
   base::RunLoop run_loop;
   std::vector<AttributionReport> attribution_reports;
-  manager->attribution_storage_
-      .AsyncCall(&AttributionStorage::GetAttributionReports)
-      .WithArgs(max_report_time, /*limit=*/-1,
-                AttributionReport::ReportTypes{
-                    AttributionReport::ReportType::kEventLevel,
-                    AttributionReport::ReportType::kAggregatableAttribution})
-      .Then(base::BindOnce(base::BindLambdaForTesting(
+  manager->GetPendingReportsForInternalUse(
+      AttributionReport::ReportTypes{
+          AttributionReport::ReportType::kEventLevel,
+          AttributionReport::ReportType::kAggregatableAttribution},
+      /*limit=*/-1,
+      base::BindOnce(base::BindLambdaForTesting(
           [&](std::vector<AttributionReport> reports) {
             attribution_reports = std::move(reports);
             run_loop.Quit();
diff --git a/content/browser/attribution_reporting/attribution_test_utils.h b/content/browser/attribution_reporting/attribution_test_utils.h
index 402c08c..33cf8206 100644
--- a/content/browser/attribution_reporting/attribution_test_utils.h
+++ b/content/browser/attribution_reporting/attribution_test_utils.h
@@ -30,7 +30,6 @@
 #include "content/browser/attribution_reporting/attribution_host.h"
 #include "content/browser/attribution_reporting/attribution_info.h"
 #include "content/browser/attribution_reporting/attribution_manager.h"
-#include "content/browser/attribution_reporting/attribution_manager_provider.h"
 #include "content/browser/attribution_reporting/attribution_observer.h"
 #include "content/browser/attribution_reporting/attribution_observer_types.h"
 #include "content/browser/attribution_reporting/attribution_report.h"
@@ -62,7 +61,6 @@
 
 namespace content {
 
-class AttributionManagerImpl;
 class AttributionObserver;
 class AttributionTrigger;
 
@@ -294,20 +292,6 @@
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
-// Test manager provider which can be used to inject a fake
-// `AttributionManager`.
-class TestManagerProvider : public AttributionManagerProvider {
- public:
-  explicit TestManagerProvider(AttributionManager* manager)
-      : manager_(manager) {}
-  ~TestManagerProvider() override = default;
-
-  AttributionManager* GetManager(WebContents* web_contents) const override;
-
- private:
-  raw_ptr<AttributionManager> manager_ = nullptr;
-};
-
 class MockAttributionManager : public AttributionManager {
  public:
   MockAttributionManager();
@@ -326,7 +310,8 @@
   MOCK_METHOD(
       void,
       GetPendingReportsForInternalUse,
-      (AttributionReport::ReportType report_type,
+      (AttributionReport::ReportTypes report_types,
+       int limit,
        base::OnceCallback<void(std::vector<AttributionReport>)> callback),
       (override));
 
@@ -731,8 +716,7 @@
     const AttributionAggregatableSource& aggregatable_source);
 
 std::vector<AttributionReport> GetAttributionReportsForTesting(
-    AttributionManagerImpl* manager,
-    base::Time max_report_time);
+    AttributionManager* manager);
 
 std::unique_ptr<MockDataHost> GetRegisteredDataHost(
     mojo::PendingReceiver<blink::mojom::AttributionDataHost> data_host);
diff --git a/content/browser/net/network_errors_listing_ui.cc b/content/browser/net/network_errors_listing_ui.cc
index fecb5b72..96a7ae5 100644
--- a/content/browser/net/network_errors_listing_ui.cc
+++ b/content/browser/net/network_errors_listing_ui.cc
@@ -28,29 +28,24 @@
 
 namespace {
 
-std::unique_ptr<base::ListValue> GetNetworkErrorData() {
-  base::Value error_codes = net::GetNetConstants();
-  const base::DictionaryValue* net_error_codes_dict = nullptr;
+base::Value::List GetNetworkErrorData() {
+  base::Value::Dict error_codes = net::GetNetConstants();
+  const base::Value::Dict* net_error_codes_dict =
+      error_codes.FindDict(kNetworkErrorKey);
+  DCHECK(net_error_codes_dict);
 
-  for (auto item : error_codes.DictItems()) {
-    if (item.first == kNetworkErrorKey) {
-      item.second.GetAsDictionary(&net_error_codes_dict);
-      break;
-    }
-  }
+  base::Value::List error_list;
 
-  std::unique_ptr<base::ListValue> error_list(new base::ListValue());
-
-  for (base::DictionaryValue::Iterator itr(*net_error_codes_dict);
-            !itr.IsAtEnd(); itr.Advance()) {
-    const int error_code = itr.value().GetInt();
+  for (auto it = net_error_codes_dict->begin();
+       it != net_error_codes_dict->end(); ++it) {
+    const int error_code = it->second.GetInt();
     // Exclude the aborted and pending codes as these don't return a page.
     if (error_code != net::Error::ERR_IO_PENDING &&
         error_code != net::Error::ERR_ABORTED) {
       base::Value::Dict error;
       error.Set(kErrorIdField, error_code);
-      error.Set(kErrorCodeField, itr.key());
-      error_list->GetList().Append(std::move(error));
+      error.Set(kErrorCodeField, it->first);
+      error_list.Append(std::move(error));
     }
   }
   return error_list;
@@ -65,9 +60,8 @@
                                 WebUIDataSource::GotDataCallback callback) {
   DCHECK(ShouldHandleWebUIRequestCallback(path));
 
-  base::DictionaryValue data;
-  data.SetKey(kErrorCodesDataName,
-              base::Value::FromUniquePtrValue(GetNetworkErrorData()));
+  base::Value::Dict data;
+  data.Set(kErrorCodesDataName, GetNetworkErrorData());
   std::string json_string;
   base::JSONWriter::Write(data, &json_string);
   std::move(callback).Run(base::RefCountedString::TakeString(&json_string));
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc
index ebd445ad..81208f00 100644
--- a/content/browser/renderer_host/input/fling_controller_unittest.cc
+++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -216,6 +216,7 @@
   bool first_wheel_event_sent_ = false;
   int sent_scroll_gesture_count_ = 0;
 #if BUILDFLAG(IS_WIN)
+  // This is necessary for static methods of `display::ScreenWin`.
   display::win::test::ScopedScreenWin scoped_screen_win_;
 #endif
 
diff --git a/content/browser/renderer_host/input/fling_scheduler_unittest.cc b/content/browser/renderer_host/input/fling_scheduler_unittest.cc
index f8de4972b..1b45630 100644
--- a/content/browser/renderer_host/input/fling_scheduler_unittest.cc
+++ b/content/browser/renderer_host/input/fling_scheduler_unittest.cc
@@ -15,10 +15,6 @@
 #include "content/test/test_render_widget_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if BUILDFLAG(IS_WIN)
-#include "ui/display/win/test/scoped_screen_win.h"
-#endif
-
 namespace content {
 
 class FakeFlingScheduler : public FlingScheduler {
@@ -139,9 +135,6 @@
   scoped_refptr<SiteInstanceGroup> site_instance_group_;
   std::unique_ptr<TestRenderWidgetHostView> view_;
   std::unique_ptr<MockRenderWidgetHostDelegate> delegate_;
-#if BUILDFLAG(IS_WIN)
-  display::win::test::ScopedScreenWin scoped_screen_win_;
-#endif
 };
 
 TEST_F(FlingSchedulerTest, ScheduleNextFlingProgress) {
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
index 292f17f..8ba2b0f7 100644
--- a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -25,10 +25,6 @@
 #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
 #include "ui/events/blink/blink_features.h"
 
-#if BUILDFLAG(IS_WIN)
-#include "ui/display/win/test/scoped_screen_win.h"
-#endif
-
 using blink::WebGestureDevice;
 using blink::WebGestureEvent;
 using blink::WebInputEvent;
@@ -244,9 +240,6 @@
   std::unique_ptr<blink::mojom::InputEventResultState> sync_ack_result_;
   std::unique_ptr<WebGestureEvent> sync_followup_event_;
   base::test::ScopedFeatureList feature_list_;
-#if BUILDFLAG(IS_WIN)
-  display::win::test::ScopedScreenWin scoped_screen_win_;
-#endif
 };
 
 class GestureEventQueueWithCompositorEventQueueTest
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index b4e1505c..3e4d7c6 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -46,10 +46,6 @@
 #include "ui/events/event.h"
 #endif
 
-#if BUILDFLAG(IS_WIN)
-#include "ui/display/win/test/scoped_screen_win.h"
-#endif
-
 using blink::SyntheticWebGestureEventBuilder;
 using blink::SyntheticWebMouseEventBuilder;
 using blink::SyntheticWebMouseWheelEventBuilder;
@@ -970,9 +966,6 @@
 TEST_F(InputRouterImplTest, DISABLED_GestureTypesIgnoringAck) {
   // We test every gesture type, ensuring that the stream of gestures is valid.
 
-#if BUILDFLAG(IS_WIN)
-  display::win::test::ScopedScreenWin scoped_screen_win_;
-#endif
   const WebInputEvent::Type eventTypes[] = {
       WebInputEvent::Type::kGestureTapDown,
       WebInputEvent::Type::kGestureShowPress,
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index b22ccbf..17c5ed84 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -81,6 +81,7 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "content/browser/renderer_host/test_render_widget_host_view_mac_factory.h"
+#include "ui/display/test/test_screen.h"
 #endif
 
 #if defined(USE_AURA) || BUILDFLAG(IS_MAC)
@@ -558,6 +559,10 @@
     // calls display::Screen::SetScreenInstance().
     ui::SetScreenAndroid(false /* use_display_wide_color_gamut */);
 #endif
+#if BUILDFLAG(IS_MAC)
+    screen_ = std::make_unique<display::test::TestScreen>();
+    display::Screen::SetScreenInstance(screen_.get());
+#endif
 #if defined(USE_AURA)
     screen_.reset(aura::TestScreen::Create(gfx::Size()));
     display::Screen::SetScreenInstance(screen_.get());
@@ -619,11 +624,11 @@
     browser_context_.reset();
 
 #if defined(USE_AURA)
-    display::Screen::SetScreenInstance(nullptr);
-    screen_.reset();
+    ImageTransportFactory::Terminate();
 #endif
 #if defined(USE_AURA) || BUILDFLAG(IS_MAC)
-    ImageTransportFactory::Terminate();
+    display::Screen::SetScreenInstance(nullptr);
+    screen_.reset();
 #endif
 #if BUILDFLAG(IS_ANDROID)
     display::Screen::SetScreenInstance(nullptr);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 6f7e468..21f3e45 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -131,7 +131,6 @@
 #if BUILDFLAG(IS_WIN)
 #include "ui/base/view_prop.h"
 #include "ui/base/win/window_event_target.h"
-#include "ui/display/win/test/scoped_screen_win.h"
 #endif
 
 using testing::_;
@@ -3763,11 +3762,6 @@
        ScrollEventsOverscrollWithFling) {
   SetUpOverscrollEnvironment();
 
-#if BUILDFLAG(IS_WIN)
-  // Create a ScopedScreenWin.
-  display::win::test::ScopedScreenWin scoped_screen_win;
-#endif
-
   // Send a wheel event. ACK the event as not processed. This should not
   // initiate an overscroll gesture since it doesn't cross the threshold yet.
   SimulateWheelEvent(10, 0, 0, true, WebMouseWheelEvent::kPhaseBegan);
@@ -3844,11 +3838,6 @@
        ScrollEventsOverscrollWithZeroFling) {
   SetUpOverscrollEnvironment();
 
-#if BUILDFLAG(IS_WIN)
-  // Create a ScopedScreenWin.
-  display::win::test::ScopedScreenWin scoped_screen_win;
-#endif
-
   // Send a wheel event. ACK the event as not processed. This should not
   // initiate an overscroll gesture since it doesn't cross the threshold yet.
   SimulateWheelEvent(10, 0, 0, true, WebMouseWheelEvent::kPhaseBegan);
@@ -3926,11 +3915,6 @@
        MAYBE_ReverseFlingCancelsOverscroll) {
   SetUpOverscrollEnvironment();
 
-#if BUILDFLAG(IS_WIN)
-  // Create a ScopedScreenWin.
-  display::win::test::ScopedScreenWin scoped_screen_win;
-#endif
-
   {
     PressAndSetTouchActionAuto();
     // Start and end a gesture in the same direction without processing the
@@ -4801,11 +4785,6 @@
        OverscrollStateResetsAfterScroll) {
   SetUpOverscrollEnvironment();
 
-#if BUILDFLAG(IS_WIN)
-  // Create a ScopedScreenWin.
-  display::win::test::ScopedScreenWin scoped_screen_win;
-#endif
-
   SimulateWheelEvent(0, 5, 0, true,
                      WebMouseWheelEvent::kPhaseBegan);  // sent directly
   SimulateWheelEvent(0, 30, 0, true,
@@ -5243,11 +5222,6 @@
 TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) {
   SetUpOverscrollEnvironment();
 
-#if BUILDFLAG(IS_WIN)
-  // Create a ScopedScreenWin.
-  display::win::test::ScopedScreenWin scoped_screen_win;
-#endif
-
   PressAndSetTouchActionAuto();
   // Wheel event scroll ending with mouse move.
   SimulateWheelEvent(-30, -10, 0, true,
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
index c79d604..8f8fb19c 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -27,6 +27,7 @@
 #include "testing/platform_test.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/layout.h"
+#include "ui/display/screen.h"
 
 using content::RenderWidgetHostViewMac;
 
@@ -122,6 +123,7 @@
   void TearDown() override { ImageTransportFactory::Terminate(); }
 
  private:
+  display::ScopedNativeScreen screen_;
   // This has a MessageLoop for ImageTransportFactory and enables
   // BrowserThread::UI for RecyclableCompositorMac used by
   // RenderWidgetHostViewMac.
diff --git a/content/browser/screen_enumeration/screen_enumeration_browsertest.cc b/content/browser/screen_enumeration/screen_enumeration_browsertest.cc
index 6267f67..feb76c9 100644
--- a/content/browser/screen_enumeration/screen_enumeration_browsertest.cc
+++ b/content/browser/screen_enumeration/screen_enumeration_browsertest.cc
@@ -135,18 +135,26 @@
 
  protected:
   // ScreenEnumerationTest:
-  void SetUpOnMainThread() override {
-    ScreenEnumerationTest::SetUpOnMainThread();
-    original_screen_ = display::Screen::GetScreen();
-    display::Screen::SetScreenInstance(&screen_);
 
+  void SetUp() override {
+    display::Screen::SetScreenInstance(&screen_);
     // Create a shell that observes the fake screen. A display is required.
     screen()->display_list().AddDisplay({0, gfx::Rect(100, 100, 801, 802)},
                                         display::DisplayList::Type::PRIMARY);
+
+    ScreenEnumerationTest::SetUp();
+  }
+  void TearDown() override {
+    ScreenEnumerationTest::TearDown();
+    display::Screen::SetScreenInstance(nullptr);
+  }
+
+  void SetUpOnMainThread() override {
+    ScreenEnumerationTest::SetUpOnMainThread();
+
     test_shell_ = CreateBrowser();
   }
   void TearDownOnMainThread() override {
-    display::Screen::SetScreenInstance(original_screen_);
     ScreenEnumerationTest::TearDownOnMainThread();
   }
 
@@ -154,7 +162,6 @@
   Shell* test_shell() { return test_shell_; }
 
  private:
-  raw_ptr<display::Screen> original_screen_ = nullptr;
   display::ScreenBase screen_;
   raw_ptr<Shell> test_shell_ = nullptr;
 };
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index c2c6ae8..5eccf88 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -956,7 +956,7 @@
       storage::FileSystemContext* filesystem_context,
       network::mojom::CookieManager* cookie_manager,
       InterestGroupManagerImpl* interest_group_manager,
-      AttributionManagerImpl* attribution_manager,
+      AttributionManager* attribution_manager,
       AggregationServiceImpl* aggregation_service,
       storage::SharedStorageManager* shared_storage_manager,
       bool perform_storage_cleanup,
@@ -1643,7 +1643,7 @@
   return file_system_access_manager_.get();
 }
 
-AttributionManagerImpl* StoragePartitionImpl::GetAttributionManager() {
+AttributionManager* StoragePartitionImpl::GetAttributionManager() {
   DCHECK(initialized_);
   return attribution_manager_.get();
 }
@@ -2391,7 +2391,7 @@
     storage::FileSystemContext* filesystem_context,
     network::mojom::CookieManager* cookie_manager,
     InterestGroupManagerImpl* interest_group_manager,
-    AttributionManagerImpl* attribution_manager,
+    AttributionManager* attribution_manager,
     AggregationServiceImpl* aggregation_service,
     storage::SharedStorageManager* shared_storage_manager,
     bool perform_storage_cleanup,
@@ -2792,6 +2792,12 @@
   aggregation_service_ = std::move(aggregation_service);
 }
 
+void StoragePartitionImpl::OverrideAttributionManagerForTesting(
+    std::unique_ptr<AttributionManager> attribution_manager) {
+  DCHECK(initialized_);
+  attribution_manager_ = std::move(attribution_manager);
+}
+
 void StoragePartitionImpl::GetQuotaSettings(
     storage::OptionalQuotaSettingsCallback callback) {
   if (g_test_quota_settings) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 5d80450..25100c6 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -65,7 +65,7 @@
 namespace content {
 
 class AggregationServiceImpl;
-class AttributionManagerImpl;
+class AttributionManager;
 class BackgroundFetchContext;
 class BlobRegistryWrapper;
 class BluetoothAllowedDevicesMap;
@@ -142,6 +142,8 @@
           shared_storage_worklet_host_manager);
   void OverrideAggregationServiceForTesting(
       std::unique_ptr<AggregationServiceImpl> aggregation_service);
+  void OverrideAttributionManagerForTesting(
+      std::unique_ptr<AttributionManager> attribution_manager);
 
   // Returns the StoragePartitionConfig that represents this StoragePartition.
   const StoragePartitionConfig& GetConfig();
@@ -248,7 +250,7 @@
   FileSystemAccessManagerImpl* GetFileSystemAccessManager();
   BucketManager* GetBucketManager();
   QuotaContext* GetQuotaContext();
-  AttributionManagerImpl* GetAttributionManager();
+  AttributionManager* GetAttributionManager();
   void SetFontAccessManagerForTesting(
       std::unique_ptr<FontAccessManager> font_access_manager);
   ComputePressureManager* GetComputePressureManager();
@@ -654,7 +656,7 @@
       proto_database_provider_;
   scoped_refptr<ContentIndexContextImpl> content_index_context_;
   scoped_refptr<NativeIOContextImpl> native_io_context_;
-  std::unique_ptr<AttributionManagerImpl> attribution_manager_;
+  std::unique_ptr<AttributionManager> attribution_manager_;
   std::unique_ptr<FontAccessManager> font_access_manager_;
   std::unique_ptr<InterestGroupManagerImpl> interest_group_manager_;
   std::unique_ptr<BrowsingTopicsSiteDataManager>
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index a2db9da..a9241fb 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -2020,8 +2020,7 @@
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       browser_context()->GetDefaultStoragePartition());
 
-  AttributionManagerImpl* attribution_manager =
-      partition->GetAttributionManager();
+  AttributionManager* attribution_manager = partition->GetAttributionManager();
 
   base::Time now = base::Time::Now();
   auto source = SourceBuilder(now).SetExpiry(base::Days(2)).Build();
@@ -2034,26 +2033,21 @@
                        now, run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(
-      GetAttributionReportsForTesting(attribution_manager, base::Time::Max())
-          .empty());
+  EXPECT_TRUE(GetAttributionReportsForTesting(attribution_manager).empty());
 }
 
 TEST_F(StoragePartitionImplTest, ConversionsClearDataWrongMask) {
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       browser_context()->GetDefaultStoragePartition());
 
-  AttributionManagerImpl* attribution_manager =
-      partition->GetAttributionManager();
+  AttributionManager* attribution_manager = partition->GetAttributionManager();
 
   base::Time now = base::Time::Now();
   auto source = SourceBuilder(now).SetExpiry(base::Days(2)).Build();
   attribution_manager->HandleSource(source);
   attribution_manager->HandleTrigger(DefaultTrigger());
 
-  EXPECT_FALSE(
-      GetAttributionReportsForTesting(attribution_manager, base::Time::Max())
-          .empty());
+  EXPECT_FALSE(GetAttributionReportsForTesting(attribution_manager).empty());
 
   // Arbitrary non-conversions mask.
   base::RunLoop run_loop;
@@ -2061,17 +2055,14 @@
                        source.common_info().impression_origin().GetURL(), now,
                        now, run_loop.QuitClosure());
   run_loop.Run();
-  EXPECT_FALSE(
-      GetAttributionReportsForTesting(attribution_manager, base::Time::Max())
-          .empty());
+  EXPECT_FALSE(GetAttributionReportsForTesting(attribution_manager).empty());
 }
 
 TEST_F(StoragePartitionImplTest, ConversionsClearAllData) {
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       browser_context()->GetDefaultStoragePartition());
 
-  AttributionManagerImpl* attribution_manager =
-      partition->GetAttributionManager();
+  AttributionManager* attribution_manager = partition->GetAttributionManager();
 
   base::Time now = base::Time::Now();
   for (int i = 0; i < 20; i++) {
@@ -2090,17 +2081,14 @@
                        GURL(), now, now, run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(
-      GetAttributionReportsForTesting(attribution_manager, base::Time::Max())
-          .empty());
+  EXPECT_TRUE(GetAttributionReportsForTesting(attribution_manager).empty());
 }
 
 TEST_F(StoragePartitionImplTest, ConversionsClearDataForFilter) {
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       browser_context()->GetDefaultStoragePartition());
 
-  AttributionManagerImpl* attribution_manager =
-      partition->GetAttributionManager();
+  AttributionManager* attribution_manager = partition->GetAttributionManager();
 
   base::Time now = base::Time::Now();
   for (int i = 0; i < 5; i++) {
@@ -2122,9 +2110,7 @@
                                            .Build());
   }
 
-  EXPECT_EQ(5u, GetAttributionReportsForTesting(attribution_manager,
-                                                base::Time::Max())
-                    .size());
+  EXPECT_EQ(5u, GetAttributionReportsForTesting(attribution_manager).size());
 
   // Match against enough Origins to delete three of the imp/conv pairs.
   base::RunLoop run_loop;
@@ -2138,9 +2124,7 @@
   partition->ClearData(StoragePartition::REMOVE_DATA_MASK_CONVERSIONS, 0, func,
                        nullptr, false, now, now, run_loop.QuitClosure());
   run_loop.Run();
-  EXPECT_EQ(2u, GetAttributionReportsForTesting(attribution_manager,
-                                                base::Time::Max())
-                    .size());
+  EXPECT_EQ(2u, GetAttributionReportsForTesting(attribution_manager).size());
 }
 
 TEST_F(StoragePartitionImplTest, DataRemovalObserver) {
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index 829d2c8..630da6d 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -258,20 +258,14 @@
 }
 
 bool URLDataManagerBackend::IsValidNetworkErrorCode(int error_code) {
-  base::Value error_codes = net::GetNetConstants();
-  const base::DictionaryValue* net_error_codes_dict = nullptr;
-
-  for (auto item : error_codes.DictItems()) {
-    if (item.first == kNetworkErrorKey) {
-      item.second.GetAsDictionary(&net_error_codes_dict);
-      break;
-    }
-  }
+  base::Value::Dict error_codes = net::GetNetConstants();
+  const base::Value::Dict* net_error_codes_dict =
+      error_codes.FindDict(kNetworkErrorKey);
 
   if (net_error_codes_dict != nullptr) {
-    for (base::DictionaryValue::Iterator itr(*net_error_codes_dict);
-         !itr.IsAtEnd(); itr.Advance()) {
-      if (error_code == itr.value().GetInt())
+    for (auto it = net_error_codes_dict->begin();
+         it != net_error_codes_dict->end(); ++it) {
+      if (error_code == it->second.GetInt())
         return true;
     }
   }
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc
index c046c58..ce6b8b4 100644
--- a/content/public/app/content_main_delegate.cc
+++ b/content/public/app/content_main_delegate.cc
@@ -46,7 +46,7 @@
   return true;
 }
 
-bool ContentMainDelegate::ShouldCreateFeatureList() {
+bool ContentMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
   return true;
 }
 
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h
index 1d85b76..c32d8d0 100644
--- a/content/public/app/content_main_delegate.h
+++ b/content/public/app/content_main_delegate.h
@@ -29,7 +29,25 @@
 
 class CONTENT_EXPORT ContentMainDelegate {
  public:
-  virtual ~ContentMainDelegate() {}
+  // The context in which a delegate method is invoked, including the process
+  // type and whether it is in a test harness. Can distinguish between
+  // the browser process and child processes; for more fine-grained process
+  // types check the `switches::kProcessType` command-line switch.
+  enum class InvokedIn {
+    // Delegate is being invoked in the browser process. The `kProcessType`
+    // switch will be empty.
+    kBrowserProcess,
+
+    // Delegate is being invoked in the browser process, from a test harness.
+    // The `kProcessType` switch will be empty.
+    kBrowserProcessUnderTest,
+
+    // Delegate is being invoked in a child process. The `kProcessType` switch
+    // will hold the precise child process type.
+    kChildProcess,
+  };
+
+  virtual ~ContentMainDelegate() = default;
 
   // Tells the embedder that the absolute basic startup has been done, i.e.
   // it's now safe to create singletons and check the command line. Return true
@@ -96,30 +114,33 @@
   // FeatureList instance for this process. Default implementation returns true.
   // Embedders that need to control when and/or how FeatureList should be
   // created should override and return false.
-  virtual bool ShouldCreateFeatureList();
+  virtual bool ShouldCreateFeatureList(InvokedIn invoked_in);
 
   // Creates and returns the VariationsIdsProvider. If null is returned,
   // a VariationsIdsProvider is created with a mode of `kUseSignedInState`.
   // VariationsIdsProvider is a singleton.
   virtual variations::VariationsIdsProvider* CreateVariationsIdsProvider();
 
-  // Allows the embedder to perform initialization once field trials/FeatureList
-  // initialization has completed if ShouldCreateFeatureList() returns true.
-  // Otherwise, the embedder is responsible for calling this method once feature
-  // list initialization is complete. Called in every process.
-  virtual void PostFieldTrialInitialization() {}
-
   // Allows the embedder to perform its own initialization after early content
-  // initialization. At this point, it is possible to post to base::ThreadPool
-  // or to the main thread loop via base::ThreadTaskRunnerHandle, but the tasks
-  // won't run immediately.
+  // initialization.
   //
-  // If ShouldCreateFeatureList() returns true, the field trials and FeatureList
-  // have been initialized. Otherwise, the implementation must initialize the
-  // field trials and FeatureList and call PostFieldTrialInitialization().
+  // At this point, in the browser process it is possible to post to
+  // base::ThreadPool, but the tasks won't run until
+  // base::ThreadPoolInstance::Start() is called. In other processes the
+  // ThreadPool will not exist yet so it is not safe to post to it.
+  // TODO(https://crbug.com/1327069): Create the ThreadPool before this in all
+  // processes.
   //
-  // |is_running_tests| indicates whether it is running in tests.
-  virtual void PostEarlyInitialization(bool is_running_tests) {}
+  // It is also possible to post tasks to the main thread loop via
+  // base::ThreadTaskRunnerHandle. These tasks won't run until
+  // base::RunLoop::Run() is called on the main thread, which happens after all
+  // ContentMainDelegate entry points.
+  //
+  // If ShouldCreateFeatureList() returns true for `invoked_in`, the
+  // field trials and FeatureList have been initialized. Otherwise, the
+  // implementation must initialize the field trials and FeatureList before
+  // returning from PostEarlyInitialization.
+  virtual void PostEarlyInitialization(InvokedIn invoked_in) {}
 
 #if BUILDFLAG(IS_WIN)
   // Allows the embedder to indicate that console control events (e.g., Ctrl-C,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 08b6c6f..2974f48 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -927,8 +927,8 @@
   return {};
 }
 
-base::DictionaryValue ContentBrowserClient::GetNetLogConstants() {
-  return base::DictionaryValue();
+base::Value::Dict ContentBrowserClient::GetNetLogConstants() {
+  return base::Value::Dict();
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index c048f7e1..48fffae 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -87,7 +87,6 @@
 
 namespace base {
 class CommandLine;
-class DictionaryValue;
 class FilePath;
 class Location;
 class SequencedTaskRunner;
@@ -1697,7 +1696,7 @@
   // |GetNetConstants()| and passed to FileNetLogObserver - see documentation
   // of |FileNetLogObserver::CreateBounded()| for more information.  The
   // convention is to put new constants under a subdict at the key "clientInfo".
-  virtual base::DictionaryValue GetNetLogConstants();
+  virtual base::Value::Dict GetNetLogConstants();
 
 #if BUILDFLAG(IS_ANDROID)
   // Only used by Android WebView.
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index b58ef821..fdf71ef 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -610,6 +610,8 @@
   tracing::EnableStartupTracingIfNeeded();
 
   {
+    using InvokedIn = ContentMainDelegate::InvokedIn;
+
     SetBrowserClientForTesting(delegate->CreateContentBrowserClient());
     if (command_line->HasSwitch(switches::kSingleProcess))
       SetRendererClientForTesting(delegate->CreateContentRendererClient());
@@ -620,10 +622,8 @@
     delegate->PreSandboxStartup();
 
     DCHECK(!field_trial_list_);
-    if (delegate->ShouldCreateFeatureList()) {
+    if (delegate->ShouldCreateFeatureList(InvokedIn::kBrowserProcessUnderTest))
       field_trial_list_ = SetUpFieldTrialsAndFeatureList();
-      delegate->PostFieldTrialInitialization();
-    }
 
     base::ThreadPoolInstance::Create("Browser");
 
@@ -636,7 +636,7 @@
           variations::VariationsIdsProvider::Mode::kUseSignedInState);
     }
 
-    delegate->PostEarlyInitialization(/*is_running_tests=*/true);
+    delegate->PostEarlyInitialization(InvokedIn::kBrowserProcessUnderTest);
 
     StartBrowserThreadPool();
     BrowserTaskExecutor::PostFeatureListSetup();
diff --git a/content/public/test/content_browser_test_shell_main_delegate.cc b/content/public/test/content_browser_test_shell_main_delegate.cc
index ce95cf95..73fd51eb 100644
--- a/content/public/test/content_browser_test_shell_main_delegate.cc
+++ b/content/public/test/content_browser_test_shell_main_delegate.cc
@@ -29,10 +29,12 @@
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
 void ContentBrowserTestShellMainDelegate::PostEarlyInitialization(
-    bool is_running_tests) {
-  // Browser tests on Lacros requires a non-null LacrosService.
-  lacros_service_ = std::make_unique<chromeos::LacrosService>();
-  ShellMainDelegate::PostEarlyInitialization(is_running_tests);
+    InvokedIn invoked_in) {
+  if (invoked_in != InvokedIn::kChildProcess) {
+    // Browser tests on Lacros requires a non-null LacrosService.
+    lacros_service_ = std::make_unique<chromeos::LacrosService>();
+  }
+  ShellMainDelegate::PostEarlyInitialization(invoked_in);
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/content/public/test/content_browser_test_shell_main_delegate.h b/content/public/test/content_browser_test_shell_main_delegate.h
index c763df9..ed1ffd4 100644
--- a/content/public/test/content_browser_test_shell_main_delegate.h
+++ b/content/public/test/content_browser_test_shell_main_delegate.h
@@ -26,7 +26,7 @@
 
   // ContentMainDelegate implementation:
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  void PostEarlyInitialization(bool is_running_tests) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
 #endif
   // ShellMainDelegate overrides.
   content::ContentBrowserClient* CreateContentBrowserClient() override;
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index aa30f0c..b674a89 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -40,9 +40,12 @@
 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
+#include "ui/display/screen.h"
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
 #include "ui/android/dummy_screen_android.h"
-#include "ui/display/screen.h"
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -239,6 +242,10 @@
 #if BUILDFLAG(IS_WIN)
   ole_initializer_ = std::make_unique<ui::ScopedOleInitializer>();
 #endif
+#if BUILDFLAG(IS_MAC)
+  screen_ = std::make_unique<display::ScopedNativeScreen>();
+#endif
+
 #if defined(USE_AURA)
   aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>(
       ImageTransportFactory::GetInstance()->GetContextFactory());
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index a02288f..8741365c 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -43,6 +43,7 @@
 
 namespace display {
 class Screen;
+class ScopedNativeScreen;
 }
 
 namespace net {
@@ -325,6 +326,9 @@
 #if BUILDFLAG(IS_WIN)
   std::unique_ptr<ui::ScopedOleInitializer> ole_initializer_;
 #endif
+#if BUILDFLAG(IS_MAC)
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
+#endif
 #if defined(USE_AURA)
   std::unique_ptr<aura::test::AuraTestHelper> aura_test_helper_;
 #endif
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 15cbdd3..2ee2fdb 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -310,6 +310,10 @@
     deps += [ "//ui/views/linux_ui:linux_ui_factory" ]
   }
 
+  if (is_mac) {
+    deps += [ "//ui/display:test_support" ]
+  }
+
   if (is_android) {
     deps += [
       "//components/embedder_support/android:view",
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 86e85bd..5c28ef5 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -186,8 +186,8 @@
   return false;
 }
 
-bool ShellMainDelegate::ShouldCreateFeatureList() {
-  return false;
+bool ShellMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
+  return invoked_in == InvokedIn::kChildProcess;
 }
 
 void ShellMainDelegate::PreSandboxStartup() {
@@ -335,9 +335,11 @@
 #endif
 }
 
-void ShellMainDelegate::PostEarlyInitialization(bool is_running_tests) {
-  // Apply field trial testing configuration.
-  browser_client_->CreateFeatureListAndFieldTrials();
+void ShellMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
+  if (!ShouldCreateFeatureList(invoked_in)) {
+    // Apply field trial testing configuration since content did not.
+    browser_client_->CreateFeatureListAndFieldTrials();
+  }
 }
 
 ContentClient* ShellMainDelegate::CreateContentClient() {
diff --git a/content/shell/app/shell_main_delegate.h b/content/shell/app/shell_main_delegate.h
index f19ee28..7044aea 100644
--- a/content/shell/app/shell_main_delegate.h
+++ b/content/shell/app/shell_main_delegate.h
@@ -32,7 +32,7 @@
 
   // ContentMainDelegate implementation:
   bool BasicStartupComplete(int* exit_code) override;
-  bool ShouldCreateFeatureList() override;
+  bool ShouldCreateFeatureList(InvokedIn invoked_in) override;
   void PreSandboxStartup() override;
   absl::variant<int, MainFunctionParams> RunProcess(
       const std::string& process_type,
@@ -41,7 +41,7 @@
   void ZygoteForked() override;
 #endif
   void PreBrowserMain() override;
-  void PostEarlyInitialization(bool is_running_tests) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
   ContentClient* CreateContentClient() override;
   ContentBrowserClient* CreateContentBrowserClient() override;
   ContentGpuClient* CreateContentGpuClient() override;
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 86d34f9..6d4e5f5a 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -508,18 +508,18 @@
   return nullptr;
 }
 
-base::DictionaryValue ShellContentBrowserClient::GetNetLogConstants() {
-  base::DictionaryValue client_constants;
-  client_constants.SetString("name", "content_shell");
+base::Value::Dict ShellContentBrowserClient::GetNetLogConstants() {
+  base::Value::Dict client_constants;
+  client_constants.Set("name", "content_shell");
   base::CommandLine::StringType command_line =
       base::CommandLine::ForCurrentProcess()->GetCommandLineString();
 #if BUILDFLAG(IS_WIN)
-  client_constants.SetString("command_line", base::WideToUTF8(command_line));
+  client_constants.Set("command_line", base::WideToUTF8(command_line));
 #else
-  client_constants.SetString("command_line", command_line);
+  client_constants.Set("command_line", command_line);
 #endif
-  base::DictionaryValue constants;
-  constants.SetKey("clientInfo", std::move(client_constants));
+  base::Value::Dict constants;
+  constants.Set("clientInfo", std::move(client_constants));
   return constants;
 }
 
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index 1f92afd..8e2a500 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -105,7 +105,7 @@
       scoped_refptr<net::HttpResponseHeaders> response_headers,
       bool first_auth_attempt,
       LoginAuthRequiredCallback auth_required_callback) override;
-  base::DictionaryValue GetNetLogConstants() override;
+  base::Value::Dict GetNetLogConstants() override;
   base::FilePath GetSandboxedStorageServiceDataDirectory() override;
   base::FilePath GetFirstPartySetsDirectory() override;
   std::string GetUserAgent() override;
diff --git a/content/shell/browser/shell_platform_data_aura.cc b/content/shell/browser/shell_platform_data_aura.cc
index a02a4058..6e2480ed 100644
--- a/content/shell/browser/shell_platform_data_aura.cc
+++ b/content/shell/browser/shell_platform_data_aura.cc
@@ -82,12 +82,7 @@
 
 #if defined(USE_OZONE)
   // Setup global display::Screen singleton.
-  if (!display::Screen::GetScreen()) {
-    std::unique_ptr<aura::ScreenOzone> screen_ozone =
-        std::make_unique<aura::ScreenOzone>();
-    screen_ozone.get()->Initialize();
-    screen_ = std::move(screen_ozone);
-  }
+  screen_ = std::make_unique<aura::ScopedScreenOzone>();
 #endif  // defined(USE_OZONE)
 
   ui::PlatformWindowInitProperties properties;
diff --git a/content/shell/browser/shell_platform_data_aura.h b/content/shell/browser/shell_platform_data_aura.h
index 8b58302..345a9d9 100644
--- a/content/shell/browser/shell_platform_data_aura.h
+++ b/content/shell/browser/shell_platform_data_aura.h
@@ -20,7 +20,7 @@
 
 #if defined(USE_OZONE)
 namespace display {
-class Screen;
+class ScopedNativeScreen;
 }
 #endif
 
@@ -46,7 +46,7 @@
 
  private:
 #if defined(USE_OZONE)
-  std::unique_ptr<display::Screen> screen_;
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
 #endif
 
   std::unique_ptr<aura::WindowTreeHost> host_;
diff --git a/content/shell/browser/shell_platform_delegate.h b/content/shell/browser/shell_platform_delegate.h
index 32cd23a..9326cb3 100644
--- a/content/shell/browser/shell_platform_delegate.h
+++ b/content/shell/browser/shell_platform_delegate.h
@@ -15,6 +15,7 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "content/public/browser/native_web_keyboard_event.h"
+#include "ui/display/screen.h"
 #endif
 
 class GURL;
@@ -139,6 +140,9 @@
 #endif
 
  private:
+#if BUILDFLAG(IS_MAC)
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
+#endif
   // Data held for each Shell instance, since there is one ShellPlatformDelegate
   // for the whole browser process (shared across Shells). This is defined for
   // each platform implementation.
diff --git a/content/shell/browser/shell_platform_delegate_mac.mm b/content/shell/browser/shell_platform_delegate_mac.mm
index 0868a06..cf91694 100644
--- a/content/shell/browser/shell_platform_delegate_mac.mm
+++ b/content/shell/browser/shell_platform_delegate_mac.mm
@@ -134,7 +134,7 @@
 ShellPlatformDelegate::~ShellPlatformDelegate() = default;
 
 void ShellPlatformDelegate::Initialize(const gfx::Size& default_window_size) {
-  // |platform_| is unused on this platform.
+  screen_ = std::make_unique<display::ScopedNativeScreen>();
 }
 
 void ShellPlatformDelegate::CreatePlatformWindow(
diff --git a/content/shell/browser/shell_platform_delegate_views.cc b/content/shell/browser/shell_platform_delegate_views.cc
index f6924fc..0063882 100644
--- a/content/shell/browser/shell_platform_delegate_views.cc
+++ b/content/shell/browser/shell_platform_delegate_views.cc
@@ -331,8 +331,9 @@
       std::make_unique<wm::WMTestHelper>(default_window_size);
 #else
   platform_->wm_state = std::make_unique<wm::WMState>();
-  CHECK(!display::Screen::GetScreen());
-  platform_->screen = views::CreateDesktopScreen();
+  // FakeScreen tests create their own screen.
+  if (!display::Screen::HasScreen())
+    platform_->screen = views::CreateDesktopScreen();
 #endif
 
   platform_->views_delegate =
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 9a54afa..733ea005 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1622,6 +1622,7 @@
     "//ui/base/ime/mojom",
     "//ui/compositor",
     "//ui/display",
+    "//ui/display:test_support",
     "//ui/events:test_support",
     "//ui/events/blink:blink",
     "//ui/gfx",
diff --git a/content/test/attribution_simulator_impl.cc b/content/test/attribution_simulator_impl.cc
index 26581c8..f5faf02e 100644
--- a/content/test/attribution_simulator_impl.cc
+++ b/content/test/attribution_simulator_impl.cc
@@ -533,8 +533,7 @@
   }
 
   std::vector<AttributionReport> pending_reports =
-      GetAttributionReportsForTesting(manager.get(),
-                                      /*max_report_time=*/base::Time::Max());
+      GetAttributionReportsForTesting(manager.get());
 
   if (!pending_reports.empty()) {
     base::Time last_report_time =
diff --git a/content/test/attribution_simulator_input_parser.cc b/content/test/attribution_simulator_input_parser.cc
index c09345c..9cfa02f 100644
--- a/content/test/attribution_simulator_input_parser.cc
+++ b/content/test/attribution_simulator_input_parser.cc
@@ -559,12 +559,8 @@
     return expiry;
   }
 
-  absl::uint128 ParseAggregatableKey(const base::Value::Dict& dict) {
-    static constexpr char kKey[] = "key_piece";
-
-    auto context = PushContext(kKey);
-
-    const std::string* s = dict.FindString(kKey);
+  absl::uint128 ParseAggregatableKey(const base::Value& key_value) {
+    const std::string* s = key_value.GetIfString();
 
     absl::uint128 value = 0;
     if (!s || !base::HexStringToUInt128(*s, &value))
@@ -573,46 +569,28 @@
     return value;
   }
 
-  std::string ParseAggregatableKeyId(const base::Value::Dict& dict) {
-    static constexpr char kKey[] = "id";
-
-    auto context = PushContext(kKey);
-
-    const std::string* s = dict.FindString(kKey);
-    if (!s)
-      *Error() << "must be a string";
-
-    return s ? *s : "";
-  }
-
   AttributionAggregatableSource ParseAggregatableSource(
       const base::Value::Dict& cfg) {
     static constexpr char kKey[] =
         "Attribution-Reporting-Register-Aggregatable-Source";
 
-    const base::Value* values = cfg.Find(kKey);
-    if (!values)
+    const base::Value* value = cfg.Find(kKey);
+    if (!value)
+      return AttributionAggregatableSource();
+
+    auto context = PushContext(kKey);
+
+    if (!EnsureDictionary(*value))
       return AttributionAggregatableSource();
 
     AttributionAggregatableSource::Keys::container_type keys;
 
-    auto context = PushContext(kKey);
-
-    ParseList(
-        *values, base::BindLambdaForTesting([&](const base::Value& value) {
-          if (!EnsureDictionary(value))
-            return;
-
-          const base::Value::Dict& dict = value.GetDict();
-
-          std::string id = ParseAggregatableKeyId(dict);
-          absl::uint128 key = ParseAggregatableKey(dict);
-
-          if (has_error())
-            return;
-
-          keys.emplace_back(std::move(id), key);
-        }));
+    for (auto [id, key_value] : value->GetDict()) {
+      auto key_context = PushContext(id);
+      absl::uint128 key = ParseAggregatableKey(key_value);
+      if (!has_error())
+        keys.emplace_back(std::move(id), key);
+    }
 
     absl::optional<AttributionAggregatableSource> aggregatable_source =
         AttributionAggregatableSource::FromKeys(std::move(keys));
@@ -674,7 +652,17 @@
               std::vector<std::string> source_keys =
                   ParseAggregatableTriggerDataSourceKeys(trigger_dict);
 
-              absl::uint128 key = ParseAggregatableKey(trigger_dict);
+              absl::uint128 key;
+              {
+                static constexpr char kKeyKeyPiece[] = "key_piece";
+                auto key_context = PushContext(kKeyKeyPiece);
+                const base::Value* key_piece = trigger_dict.Find(kKeyKeyPiece);
+                if (key_piece) {
+                  key = ParseAggregatableKey(*key_piece);
+                } else {
+                  *Error() << "must be present";
+                }
+              }
 
               AttributionFilterData filters = ParseFilterData(
                   trigger_dict, "filters",
diff --git a/content/test/attribution_simulator_input_parser_unittest.cc b/content/test/attribution_simulator_input_parser_unittest.cc
index b7700d3..3c505cc1 100644
--- a/content/test/attribution_simulator_input_parser_unittest.cc
+++ b/content/test/attribution_simulator_input_parser_unittest.cc
@@ -157,10 +157,9 @@
         "destination": "https://c.d.test",
         "expiry": "864001"
       },
-      "Attribution-Reporting-Register-Aggregatable-Source": [{
-        "id": "a",
-        "key_piece": "0x1"
-      }]
+      "Attribution-Reporting-Register-Aggregatable-Source": {
+        "a": "0x1"
+      }
     }
   ]})json";
 
@@ -740,7 +739,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"]: must be a list)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"]: must be a dictionary)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "event",
@@ -754,7 +753,7 @@
         }]})json",
     },
     {
-        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"][0]: must be a dictionary)",
+        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"]["a"]: must be a uint128 formatted as a base-16 string)",
         R"json({"sources": [{
           "timestamp": "1643235574000",
           "source_type": "event",
@@ -764,38 +763,9 @@
             "source_event_id": "123",
             "destination": "https://a.d.test"
           },
-          "Attribution-Reporting-Register-Aggregatable-Source": [5]
-        }]})json",
-    },
-    {
-        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"][0]["id"]: must be a string)",
-        R"json({"sources": [{
-          "timestamp": "1643235574000",
-          "source_type": "event",
-          "reporting_origin": "https://a.r.test",
-          "source_origin": "https://a.s.test",
-          "Attribution-Reporting-Register-Source": {
-            "source_event_id": "123",
-            "destination": "https://a.d.test"
-          },
-          "Attribution-Reporting-Register-Aggregatable-Source": [{"id": 5}]
-        }]})json",
-    },
-    {
-        R"(["sources"][0]["Attribution-Reporting-Register-Aggregatable-Source"][0]["key_piece"]: must be a uint128 formatted as a base-16 string)",
-        R"json({"sources": [{
-          "timestamp": "1643235574000",
-          "source_type": "event",
-          "reporting_origin": "https://a.r.test",
-          "source_origin": "https://a.s.test",
-          "Attribution-Reporting-Register-Source": {
-            "source_event_id": "123",
-            "destination": "https://a.d.test"
-          },
-          "Attribution-Reporting-Register-Aggregatable-Source": [{
-            "id": "a",
-            "key_piece": "0xG"
-          }]
+          "Attribution-Reporting-Register-Aggregatable-Source": {
+            "a": "0xG"
+          }
         }]})json",
     },
     {
diff --git a/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json b/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
index f9524a9f..263bf888 100644
--- a/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
+++ b/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
@@ -2,12 +2,11 @@
   "aggregation_service_payloads": [ {
      "debug_cleartext_payload": "omRkYXRhgaJldmFsdWVEAAAAAmZidWNrZXRQAAAAAAAAAAAAAAAAAAAAAWlvcGVyYXRpb25paGlzdG9ncmFt",
      "key_id": "example_id",
-     "payload": "P6qDfnLgaTL2jLv6tRHXauNGi1DpBn7KFxX2/HyEzVCP+LwzwsRntTyrnalnZuVTux8bdILblwBa6ehWDfyf1tZ/jLr0uFr+DC6oisTb6sDkFpkCELK/62IoDqsNYzl/DyAmFd9NKaepMoS6+GYH"
+     "payload": "nNJRhchQJaZTld/Cfsz5/4JelfwxVw4wTBwaXdDu0y2YKJ3lKyjjRUKKemGsPtSj+D1MlST0ggABMGuJexhxntg7hO+fK1KIcoSK0IWyvrgfkvdip0enRdtxxEZP7xR3nAd8JFnMGDnRHOjBuOni"
   } ],
   "attribution_destination": "https://conversion.test",
   "shared_info": "{\"debug_mode\":\"enabled\",\"privacy_budget_key\":\"hTxwDPlUIel3dB39m09GOkeAkMLcYVdE6H0eK2t1RYc=\",\"report_id\":\"21abd97f-73e8-4b88-9389-a9fee6abda5e\",\"reporting_origin\":\"https://report.test\",\"scheduled_report_time\":\"1234486400\",\"version\":\"\"}",
   "source_debug_key": "123",
   "source_registration_time": "1234483200",
-  "source_site": "https://impression.test",
   "trigger_debug_key": "456"
 }
diff --git a/content/test/data/attribution_reporting/interop/README.md b/content/test/data/attribution_reporting/interop/README.md
index 7f0685b3f..ec32963 100644
--- a/content/test/data/attribution_reporting/interop/README.md
+++ b/content/test/data/attribution_reporting/interop/README.md
@@ -82,16 +82,12 @@
                 "debug_key": "987"
               },
 
-              // Optional list of zero or more aggregatable keys.
-              "Attribution-Reporting-Register-Aggregatable-Source": [
-                {
-                  // Required string to identify the key.
-                  "id": "a",
-
-                  // Required uint128 formatted as a base-16 string.
-                  "key_piece": "0x1"
-                }
-              ]
+              // Optional dictionary of aggregation key identifiers and
+              // corresponding key pieces.
+              "Attribution-Reporting-Register-Aggregatable-Source": {
+                  // Value is uint128 formatted as a base-16 string.
+                  "a": "0x1"
+              }
             }
           }
         ]
diff --git a/content/test/data/attribution_reporting/interop/basic_aggregatable.json b/content/test/data/attribution_reporting/interop/basic_aggregatable.json
index 2382659..5999aad 100644
--- a/content/test/data/attribution_reporting/interop/basic_aggregatable.json
+++ b/content/test/data/attribution_reporting/interop/basic_aggregatable.json
@@ -16,12 +16,9 @@
               "destination": "https://destination.test",
               "source_event_id": "123"
             },
-            "Attribution-Reporting-Register-Aggregatable-Source": [
-              {
-                "id": "a",
-                "key_piece": "0x159"
-              }
-            ]
+            "Attribution-Reporting-Register-Aggregatable-Source": {
+              "a": "0x159"
+            }
           }
         }]
       }
@@ -75,7 +72,6 @@
       {
         "payload": {
           "attribution_destination": "https://destination.test",
-          "source_site": "https://source.test",
           "histograms": [
             {
               "key": "0x559",
diff --git a/content/test/data/attribution_reporting/register_aggregatable_source_headers.html.mock-http-headers b/content/test/data/attribution_reporting/register_aggregatable_source_headers.html.mock-http-headers
index c9b673b0..67a61c6 100644
--- a/content/test/data/attribution_reporting/register_aggregatable_source_headers.html.mock-http-headers
+++ b/content/test/data/attribution_reporting/register_aggregatable_source_headers.html.mock-http-headers
@@ -1,3 +1,3 @@
 HTTP/1.1 200 OK
 Attribution-Reporting-Register-Source:{"source_event_id":"5","destination":"https://d.test"}
-Attribution-Reporting-Register-Aggregatable-Source:[{"id":"key1","key_piece":"0x5"},{"id":"key2","key_piece":"0x159"}]
+Attribution-Reporting-Register-Aggregatable-Source:{"key1":"0x5","key2":"0x159"}
diff --git a/content/test/data/attribution_reporting/simulator/README.md b/content/test/data/attribution_reporting/simulator/README.md
index 3d634529..4f21d193 100644
--- a/content/test/data/attribution_reporting/simulator/README.md
+++ b/content/test/data/attribution_reporting/simulator/README.md
@@ -47,16 +47,12 @@
         "debug_key": "987"
       },
 
-      // Optional list of zero or more aggregatable keys.
-      "Attribution-Reporting-Register-Aggregatable-Source": [
-        {
-          // Required string to identify the key.
-          "id": "a",
-
-          // Required uint128 formatted as a base-16 string.
-          "key_piece": "0x1"
-        }
-      ]
+      // Optional dictionary of aggregation key identifiers and corresponding
+      // key pieces.
+      "Attribution-Reporting-Register-Aggregatable-Source": {
+          // Value is uint128 formatted as a base-16 string.
+          "a": "0x1"
+      }
     }
   ],
 
diff --git a/content/test/data/attribution_reporting/simulator/basic_aggregatable.input.json b/content/test/data/attribution_reporting/simulator/basic_aggregatable.input.json
index 8cfe8ce..3412c76 100644
--- a/content/test/data/attribution_reporting/simulator/basic_aggregatable.input.json
+++ b/content/test/data/attribution_reporting/simulator/basic_aggregatable.input.json
@@ -9,12 +9,9 @@
         "destination": "https://d.test",
         "source_event_id": "123"
       },
-      "Attribution-Reporting-Register-Aggregatable-Source": [
-        {
-          "id": "a",
-          "key_piece": "0x159"
-        }
-      ]
+      "Attribution-Reporting-Register-Aggregatable-Source": {
+        "a": "0x159"
+      }
     }
   ],
   "triggers": [
diff --git a/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json b/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
index 9ac9594c..3975dbe8 100644
--- a/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
+++ b/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
@@ -2,8 +2,7 @@
   "aggregatable_reports": [
     {
       "report": {
-        "attribution_destination": "https://d.test",
-        "source_site": "https://s.test"
+        "attribution_destination": "https://d.test"
       },
       "report_time": "1643239174123",
       "report_url": "https://r.test/.well-known/attribution-reporting/report-aggregate-attribution",
diff --git a/content/test/data/attribution_reporting/simulator/rejected_triggers.input.json b/content/test/data/attribution_reporting/simulator/rejected_triggers.input.json
index cce2d6d..3bee5aa 100644
--- a/content/test/data/attribution_reporting/simulator/rejected_triggers.input.json
+++ b/content/test/data/attribution_reporting/simulator/rejected_triggers.input.json
@@ -9,12 +9,9 @@
         "destination": "https://d.test",
         "source_event_id": "123"
       },
-      "Attribution-Reporting-Register-Aggregatable-Source": [
-        {
-          "id": "a",
-          "key_piece": "0x159"
-        }
-      ]
+      "Attribution-Reporting-Register-Aggregatable-Source": {
+          "a": "0x159"
+      }
     }
   ],
   "triggers": [
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index 5323718..d5e1f49 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -513,7 +513,6 @@
           'ANGLE_instanced_arrays',
           'EXT_blend_minmax',
           'EXT_texture_filter_anisotropic',
-          'WEBKIT_EXT_texture_filter_anisotropic',
           'OES_element_index_uint',
           'OES_standard_derivatives',
           'OES_texture_float',
@@ -524,10 +523,8 @@
           'WEBGL_compressed_texture_etc1',
           'WEBGL_debug_renderer_info',
           'WEBGL_depth_texture',
-          'WEBKIT_WEBGL_depth_texture',
           'WEBGL_draw_buffers',
           'WEBGL_lose_context',
-          'WEBKIT_WEBGL_lose_context',
       ]
       tab = self.tab
       for ext in ext_list:
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 510c7df..f32f5e44 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -216,7 +216,6 @@
 crbug.com/angleproject/4807 [ win angle-d3d11 passthrough ] conformance2/glsl3/switch-case.html [ Failure ]
 crbug.com/angleproject/5038 conformance/extensions/ext-color-buffer-half-float.html [ Failure ]
 crbug.com/1276153 conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
-crbug.com/angleproject/4394 conformance2/extensions/oes-draw-buffers-indexed.html [ Failure ]
 crbug.com/1206763 [ win intel ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ]
 
 # The validating command decoder suppressions here will not be fixed.
@@ -420,8 +419,6 @@
 crbug.com/811614 [ intel mac ] deqp/functional/gles3/negativeshaderapi.html [ Failure ]
 crbug.com/1289803 [ mac no-passthrough ] conformance2/extensions/webgl-multi-draw-instanced-base-vertex-base-instance.html [ Failure ]
 crbug.com/1289803 [ mac passthrough angle-opengl ] conformance2/extensions/webgl-multi-draw-instanced-base-vertex-base-instance.html [ Failure ]
-# The extension is not supported on ANGLE/Metal yet but we intend to make it work.
-crbug.com/891861 [ mac passthrough angle-metal ] conformance2/extensions/webgl-multi-draw-instanced-base-vertex-base-instance.html [ Skip ]
 
 # Mac Retina NVIDIA
 crbug.com/728271 [ mac nvidia-0xfe9 ] deqp/functional/gles3/shaderindexing/mat_01.html [ Failure ]
diff --git a/content/web_test/BUILD.gn b/content/web_test/BUILD.gn
index 7aab966..00cce83 100644
--- a/content/web_test/BUILD.gn
+++ b/content/web_test/BUILD.gn
@@ -208,6 +208,14 @@
       "//ppapi:blink_test_plugin",
     ]
   }
+
+  if (is_mac) {
+    deps += [ "//ui/display:test_support" ]
+  }
+
+  if (use_aura) {
+    deps += [ "//ui/aura:test_support" ]
+  }
 }
 
 static_library("web_test_renderer") {
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index bb0f2da..f8a8dfe 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -8,61 +8,74 @@
 
 [TOC]
 
-## Metainstaller
+## Installation
+
+### Metainstaller
 The metainstaller (UpdaterSetup) is a small executable that contains a
 compressed copy of the updater as a resource, extracts it, and triggers
 installation of the updater / an app. The metainstaller is downloaded by the
 user and can be run from any directory.
 
-The size of the metainstaller is less than 1500KiB.
-
 The metainstaller may have a tag attached to it. The tag is a piece of unsigned
 data from which the metainstaller extracts the ID of the application to be
 installed, along with the application's brand code, usage-stats opt-in status,
 and any additional parameters to be associated with the application.
 
+After the metainstaller installs the updater, the updater installs an
+application by connecting to update servers and [downloading and executing an
+application installer](#Updates).
+
 On Windows, the tag is embedded in one of the certificates in the metainstaller
 PE. The tag is supported for both EXE and MSI formats.
 
-### Tag Format
+#### Tag Format
+TODO(crbug.com/1328903) - document the rest of the tag format.
 
-#### Brand code
+##### Brand code
 The brand code is a string of up to 4 characters long. The brand code is
 persisted during the install, over-installs, and updates.
 
-TODO(crbug.com/1328903) - document the rest of the tag format.
-
-
-### Elevation (Windows)
+#### Elevation (Windows)
 The metainstaller parses its tag and re-launches itself at high integrity if
 installing an application with `needsadmin=true` or `needsadmin=prefers`.
 
-### Localization
+#### Localization
 Metainstaller localization presents the metainstaller UI with the user's
 preferred language on the current system. Every string shown in the UI is
 translated.
 
-## Bundle Installer
+### Bundle Installer
 The bundle installer allows installation of more than one application. The
 bundle installer is typically used in software distribution scenarios.
 
 TODO(crbug.com/1035895): Document bundled installers.
 
-
-## Standalone Installer
+### Standalone Installer
 TODO(crbug.com/1035895): Document the standalone installer, including building
 a standalone installer for a given application.
 
+Standalone installers embed all data required to install the application,
+including the payload and various configuration data needed by the application
+setup. Such an install completes even if a network connection is not available.
+
+Standalone installers are used:
+
+1. when an interactive user experience is not needed, such as automated
+deployments in an enterprise.
+2. when downloading the application payload is not desirable for any reason.
+3. during OEM installation.
+
+TODO(crbug.com/1139014): Document OEM.
+
 Applications on macOS frequently install via "drag-install", and then install
 the updater using a standalone installer on the application's first-run. The
 updater app can be embedded in a macOS application bundle as a helper and then
 invoked with appropriate command line arguments to install itself.
 
-## MSI Wrapper
+### MSI Wrapper
 TODO(crbug.com/1327497) - document.
 
-
-## Updater
+### Scope
 The updater is installed in one of the following modes (or scopes):
 1. per-system (or per-machine). This mode requires administrator privileges.
 2. per-user
@@ -76,6 +89,8 @@
 * (macOS, User): `~/Library/{COMPANY}/{UPDATERNAME}/{VERSION}/{UPDATERNAME}.app`
 * (macOS, System): `/Library/{COMPANY}/{UPDATERNAME}/{VERSION}/{UPDATERNAME}.app`
 
+### Command Line
+
 The updater's functionality is split between several processes. The mode of a
 process is determined by command-line arguments:
 
@@ -163,142 +178,13 @@
     *   The updater operates in system scope if and only if this switch is
         present.
 
-### Protocol
-The updater communicates with update servers using the
-[Omaha Protocol](protocol_3_1.md).
-
-#### Security
-It is not possible to MITM the updater even if the network (including TLS) is
-compromised. The integrity of the client-server communication is guaranteed
-by the [Client Update Protocol (CUP)](cup.md).
-
-#### Retries
-The updater does not retry an update check that transacted with the backend,
-even if the response was erroneous (misformatted or unparsable), until the
-next normally scheduled update check.
-
-#### DOS Mitigation
-The updater sends DoS mitigation headers in requests to the server.
-
-When the server responds with an `X-Retry-After header`, the client does not
-issue another update check until the specified period has passed (maximum 24
-hours).
-
-* The updater distinguishes between foreground and background priority: if an
-  `X-Retry-After` was received in the background case, a foreground update is
-  still permitted (but not if it was received in response to a foreground
-  update).
-
-#### Load Smoothing
-TODO(crbug.com/1329868) - implement the algorithm.
-The updater scatters its routine updates:
-* Two updaters installed in identical situations and at the same time, after
-  some period of time, do not have synchronized times at which they check
-  for updates.
-  * For example, the updater may randomly choose to wait 6 hours instead of 5 to
-    perform the next check. The probability of choosing 6 hours is .1.
-  * The change only applies to users who have not overridden their
-    `UpdateCheckMs` feature.
-  * For testing purposes, the feature can be disabled by creating an
-    DWORD value `DisableUpdateAppsHourlyJitter` in `UpdateDev`.
-  * For testing purposes, an `UpdateDev` value can set the jitter time to a
-    constant value, in the same [0, 60) seconds range. The name of the value is
-    `AutoUpdateJitterMs` and it represents the time to wait before an update
-    check is made in milliseconds.
-* The global load from updaters is scattered among the minutes of the hour, the
-  seconds of the minute, and the milliseconds of the second.
-  * For example, load spikes on the first minute of the hour, or
-    the first second of every minute, or even the first millisecond of every
-    second are undesirable.
-
-#### Usage Counts
-TODO(crbug.com/1329328) - document the client responsibilities.
-
-### Update Formats
-The updater accepts updates packaged as CRX₃ files. All files are signed with a
-publisher key. The corresponding public key is hardcoded into the updater.
-
-### Installation
-
-The updater handles the installation of new applications. The updater can
-download, install, and update an applications when the application is running.
-
-One or more applications can be installed at once, as a bundle.
-
-Before installing, the integrity of the payload if verified. The payloads are
-stored in secure locations of the file system for per-system installs.
-
-
-Considering network connectivity, there are two scenarios for installing an
-application:
-
-1. Online
-2. Offline
-
-#### Online Installs
-
-An online install is done with a [metainstaller](#Metainstaller). Every time an
-online installer runs, it sends an install event ping. The update check and
-the install event ping have the same session id. The install ping is lost if the
-network is unreachable for any reason, or the program has crashed.
-
-#### Standalone/Offline Installs
-
-This type of installs is done with a [standalone/offline installer]
-(#Standalone-Installer). This is an installer which embeds all data required to
-install the application, including the payload and various configuration data
-needed by the application setup. Such an install completes even if a network
-connection is not available.
-
-There are a couple of scenarios where the standalone/offline installer is used:
-
-1. when an interactive user experience is not needed, such as automated
-deployments in the enterprise.
-2. when downloading the application payload is not desirable for any reason.
-3. OEM installs.
-
-[installdataindex](#installdataindex) provides a mechanism to specify
-configuration data which is passed to the application installer.
-
-#### User Interface
-TODO(crbug.com/1035895): Document UI/UX
-
-* The install flow can be stopped before the payload finished downloading.
-* The user interface is localized in the following languages: TBD.
-* Has a silent mode where the UI is not displayed at all.
-
-##### Help Button
-If the installation fails, the updater shows an error message with a "Help"
-button. Clicking the help button opens a web page in the user's default browser.
-The page is opened with a query string:
-`?product={AppId}&errorcode={ErrorCode}`.
-
-#### OEM Installs.
-
-TODO(crbug.com/1139014): Document OEM.
-
-#### Install Source
-
-The `installsource` identifies the originator of an install. It is provided on
-the command line of the metainstaller.
-TODO(crbug.com/1327491) - is this needed? If yes, document the algorithm.
-
-#### Installer APIs
-As part of installing or updating an application, the updater executes the
-application's installer. The API for the application installer is platform-
-specific.
-
-The macOS API is [defined here](installer_api_mac.md).
-
-TODO(crbug.com/1035895): Document Windows installer APIs
-
-#### Backward-Compatible Updater Shims
+### Backward-Compatible Updater Shims
 To maintain backwards compatibility with
 [Omaha](https://github.com/google/omaha) and
 [Keystone](https://code.google.com/archive/p/update-engine/), the updater
 installs small versions of those programs that implement a subset of their APIs.
 
-##### Keystone Shims
+#### Keystone Shims
 The updater installs a Keystone-like application that contains these shims:
 
 1.  The Keystone app executable.
@@ -366,14 +252,89 @@
 *   --xcpath, -x PATH
     *   Set a path to use as an existence checker.
 
-##### Omaha Shims
+#### Omaha Shims
 On Windows, the updater replaces Omaha's files with a copy of the updater, and
 keeps the Omaha registry entry
 (`CLIENTS/{430FD4D0-B729-4F61-AA34-91526481799D}`) up-to-date with the latest
 `pv` value. Additionally, the updater replaces the Omaha uninstall command line
 with its own.
 
-#### Enterprise Policies
+### Installer User Interface
+TODO(crbug.com/1035895): Document UI/UX.
+
+The user interface is localized in the following languages: TBD.
+
+TODO(crbug.com/1014591): Implement install cancellation.
+
+The install flow can be stopped before the payload finished downloading.
+
+TODO(crbug.com/1286580): Implement silent mode.
+
+Has a silent mode where the UI is not displayed at all.
+
+#### Help Button
+If the installation fails, the updater shows an error message with a "Help"
+button. Clicking the help button opens a web page in the user's default browser.
+The page is opened with a query string:
+`?product={AppId}&errorcode={ErrorCode}`.
+
+### Install Source
+
+TODO(crbug.com/1327491) - Implement the following algorithm.
+
+The `installsource` identifies the originator of an install. It is provided on
+the command line of the metainstaller.
+
+TODO(crbug.com/1327491) - is this needed? If yes, document the algorithm.
+
+## Updates
+There is no limit for the number of retries to update an application if the
+update fails repeatedly.
+
+### Protocol
+The updater communicates with update servers using the
+[Omaha Protocol](protocol_3_1.md).
+
+#### Security
+It is not possible to MITM the updater even if the network (including TLS) is
+compromised. The integrity of the client-server communication is guaranteed
+by the [Client Update Protocol (CUP)](cup.md).
+
+#### Retries
+The updater does not retry an update check that transacted with the backend,
+even if the response was erroneous (misformatted or unparsable), until the
+next normally scheduled update check.
+
+#### DOS Mitigation
+The updater sends DoS mitigation headers in requests to the server.
+
+When the server responds with an `X-Retry-After header`, the client does not
+issue another update check until the specified period has passed (maximum 24
+hours).
+
+* The updater distinguishes between foreground and background priority: if an
+  `X-Retry-After` was received in the background case, a foreground update is
+  still permitted (but not if it was received in response to a foreground
+  update).
+
+#### Usage Counts
+TODO(crbug.com/1329328) - document the client responsibilities.
+
+#### Cohort Tracking
+The client records the `cohort`, `cohortname`, and `cohorthint` values from the
+server in each update response (even if there is no-update) and reports them on
+subsequent update checks.
+
+### Installer APIs
+As part of installing or updating an application, the updater executes the
+application's installer. The API for the application installer is platform-
+specific.
+
+The macOS API is [defined here](installer_api_mac.md).
+
+TODO(crbug.com/1035895): Document Windows installer APIs
+
+### Enterprise Policies
 Enterprise policies can prevent the installation of applications:
 *   A per-application setting may specify whether an application is installable.
 *   If no per-application setting specifies otherwise, the default install
@@ -382,9 +343,9 @@
 
 Refer to chrome/updater/protos/omaha\_settings.proto for more details.
 
-#### Dynamic Install Parameters
+### Dynamic Install Parameters
 
-##### `needsadmin`
+#### `needsadmin`
 
 `needsadmin` is one of the install parameters that can be specified for
 first installs via the
@@ -411,7 +372,7 @@
 application installer needs to be able to support the installation as system, or
 per-user, or both modes.
 
-##### `installdataindex`
+#### `installdataindex`
 
 `installdataindex` is one of the install parameters that can be specified for
 first installs on the command line or via the
@@ -555,26 +516,40 @@
 * This installerdata is not persisted anywhere else, and it is not sent as a
 part of pings to the update server.
 
-## Updates
-There is no limit for the number of retries to update an application if the
-update fails repeatedly.
-
-### Cohort Tracking
-The client records the `cohort`, `cohortname`, and `cohorthint` values from the
-server in each update response (even if there is no-update) and reports them on
-subsequent update checks.
+### Update Formats
+The updater accepts updates packaged as CRX₃ files. All files are signed with a
+publisher key. The corresponding public key is hardcoded into the updater.
 
 ### Differential Updates
 TODO(crbug.com/1035895): Document differential updates.
 
+TODO(crbug.com/1331030): Implement differential update support.
+
 ### Update Timing
 The updater runs periodic tasks every hour, checking its own status, detecting
 application uninstalls, and potential checking for updates (if it has been at
 least 5 hours since the last update check).
 
-For internal users, the period of the scheduled tasks is 30 minutes.
-
-TODO(crbug.com/1328943) - document the jitter for starting updates.
+TODO(crbug.com/1329868): implement the following algorithm.
+The updater scatters its routine updates:
+* Two updaters installed in identical situations and at the same time, after
+  some period of time, do not have synchronized times at which they check
+  for updates.
+  * For example, the updater may randomly choose to wait 6 hours instead of 5 to
+    perform the next check. The probability of choosing 6 hours is .1.
+  * The change only applies to users who have not overridden their
+    `UpdateCheckMs` feature.
+  * For testing purposes, the feature can be disabled by creating an
+    DWORD value `DisableUpdateAppsHourlyJitter` in `UpdateDev`.
+  * For testing purposes, an `UpdateDev` value can set the jitter time to a
+    constant value, in the same [0, 60) seconds range. The name of the value is
+    `AutoUpdateJitterMs` and it represents the time to wait before an update
+    check is made in milliseconds.
+* The global load from updaters is scattered among the minutes of the hour, the
+  seconds of the minute, and the milliseconds of the second.
+  * For example, load spikes on the first minute of the hour, or
+    the first second of every minute, or even the first millisecond of every
+    second are undesirable.
 
 #### Windows Scheduling of Updates
 The update tasks are scheduled using the OS task scheduler.
@@ -582,7 +557,8 @@
 The time resolution for tasks is 1 minute. Tasks are set to run 5 minutes after
 they've been created.
 
-TODO(crbug.com/1328935) - built in task scheduler as a failover mechanism
+TODO(crbug.com/1328935): implement built in task scheduler as a failover
+mechanism
 
 TODO(crbug.com/1035895): Does the updater run at user login on Windows?
 
@@ -653,6 +629,8 @@
 TODO(crbug.com/1035895): Document relevant enterprise policies.
 
 #### Windows
+TODO(crbug.com/1035895): Implement this section. (ADMX file export.)
+
 ADMX templates are provided.
 
 ### Telemetry
@@ -672,11 +650,11 @@
 Multiple events associated with an update session are bundled together into a
 single request.
 
-## Downloading
+### Downloading
 There could be multiple URLs for a given application payload. The URLs are tried
 in the order they are returned in the update response.
 
-The integrity and authenticity of the payload is verified.
+The integrity of the payload is verified.
 
 There is no download cache. Payloads are re-downloaded for applications which
 fail to install.
@@ -810,11 +788,8 @@
 *   `group_policies`: Allows setting group policies, such as install and update
     policies.
 
-Windows: these overrides exist in registry, under
-`HKLM\Software\{Company}\Update\Clients\ClientState\UpdateDev`.
-
-macOS: these overrides exist in user defaults, in the `{MAC_BUNDLE_IDENTIFIER}`
-suite. For system installs, the defaults are those of the root user.
+Overrides are specified in an overrides.json file placed in the updater data
+directory.
 
 ### Tagging Tools
 TODO(crbug.com/1035895): Document tagging tools.
diff --git a/extensions/browser/api/system_display/display_info_provider.cc b/extensions/browser/api/system_display/display_info_provider.cc
index 1b979ee..9097b1b 100644
--- a/extensions/browser/api/system_display/display_info_provider.cc
+++ b/extensions/browser/api/system_display/display_info_provider.cc
@@ -37,7 +37,11 @@
 
 }  // namespace
 
-DisplayInfoProvider::DisplayInfoProvider() = default;
+DisplayInfoProvider::DisplayInfoProvider(display::Screen* screen)
+    : screen_(screen ? screen : display::Screen::GetScreen()) {
+  // Do not use/call on the screen object in this constructor yet because a
+  // subclass may pass not-yet-initialized screen instance.
+}
 
 DisplayInfoProvider::~DisplayInfoProvider() = default;
 
@@ -111,9 +115,8 @@
 void DisplayInfoProvider::GetAllDisplaysInfo(
     bool /* single_unified*/,
     base::OnceCallback<void(DisplayUnitInfoList result)> callback) {
-  display::Screen* screen = display::Screen::GetScreen();
-  int64_t primary_id = screen->GetPrimaryDisplay().id();
-  std::vector<display::Display> displays = screen->GetAllDisplays();
+  int64_t primary_id = screen_->GetPrimaryDisplay().id();
+  std::vector<display::Display> displays = screen_->GetAllDisplays();
   DisplayUnitInfoList all_displays;
   for (const display::Display& display : displays) {
     api::system_display::DisplayUnitInfo unit =
diff --git a/extensions/browser/api/system_display/display_info_provider.h b/extensions/browser/api/system_display/display_info_provider.h
index 2d0d26bf..d060ff4 100644
--- a/extensions/browser/api/system_display/display_info_provider.h
+++ b/extensions/browser/api/system_display/display_info_provider.h
@@ -17,6 +17,7 @@
 
 namespace display {
 class Display;
+class Screen;
 }
 
 namespace extensions {
@@ -118,7 +119,7 @@
                              ErrorCallback callback);
 
  protected:
-  DisplayInfoProvider();
+  explicit DisplayInfoProvider(display::Screen* screen = nullptr);
 
   // Trigger OnDisplayChangedEvent
   void DispatchOnDisplayChangedEvent();
@@ -142,6 +143,8 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
 
+  display::Screen* const screen_;
+
   absl::optional<display::ScopedDisplayObserver> display_observer_;
 };
 
diff --git a/extensions/browser/api/system_display/system_display_apitest.cc b/extensions/browser/api/system_display/system_display_apitest.cc
index 970ee75..b4ccfd1 100644
--- a/extensions/browser/api/system_display/system_display_apitest.cc
+++ b/extensions/browser/api/system_display/system_display_apitest.cc
@@ -13,24 +13,17 @@
 #include "extensions/browser/api/system_display/system_display_api.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/mock_display_info_provider.h"
-#include "extensions/browser/mock_screen.h"
 #include "extensions/common/api/system_display.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/shell/test/shell_apitest.h"
 #include "extensions/test/result_catcher.h"
-#include "ui/display/display.h"
 #include "ui/display/screen.h"
-#include "ui/display/test/scoped_screen_override.h"
 
 namespace extensions {
 
-using display::Screen;
-using display::test::ScopedScreenOverride;
-
 class SystemDisplayApiTest : public ShellApiTest {
  public:
-  SystemDisplayApiTest()
-      : provider_(new MockDisplayInfoProvider), screen_(new MockScreen) {}
+  SystemDisplayApiTest() : provider_(new MockDisplayInfoProvider) {}
 
   SystemDisplayApiTest(const SystemDisplayApiTest&) = delete;
   SystemDisplayApiTest& operator=(const SystemDisplayApiTest&) = delete;
@@ -39,17 +32,9 @@
 
   void SetUpOnMainThread() override {
     ShellApiTest::SetUpOnMainThread();
-    ANNOTATE_LEAKING_OBJECT_PTR(Screen::GetScreen());
-    scoped_screen_override_ =
-        std::make_unique<ScopedScreenOverride>(screen_.get());
     DisplayInfoProvider::InitializeForTesting(provider_.get());
   }
 
-  void TearDownOnMainThread() override {
-    ShellApiTest::TearDownOnMainThread();
-    scoped_screen_override_.reset();
-  }
-
  protected:
   void SetInfo(const std::string& display_id,
                const api::system_display::DisplayProperties& properties) {
@@ -58,8 +43,6 @@
         base::BindOnce([](absl::optional<std::string>) {}));
   }
   std::unique_ptr<MockDisplayInfoProvider> provider_;
-  std::unique_ptr<Screen> screen_;
-  std::unique_ptr<ScopedScreenOverride> scoped_screen_override_;
 };
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/extensions/browser/mock_display_info_provider.cc b/extensions/browser/mock_display_info_provider.cc
index 56ae05d..0ce2110 100644
--- a/extensions/browser/mock_display_info_provider.cc
+++ b/extensions/browser/mock_display_info_provider.cc
@@ -16,7 +16,8 @@
 
 namespace extensions {
 
-MockDisplayInfoProvider::MockDisplayInfoProvider() = default;
+MockDisplayInfoProvider::MockDisplayInfoProvider()
+    : DisplayInfoProvider(&screen_) {}
 
 MockDisplayInfoProvider::~MockDisplayInfoProvider() = default;
 
diff --git a/extensions/browser/mock_display_info_provider.h b/extensions/browser/mock_display_info_provider.h
index 4e6fba2..f173f59 100644
--- a/extensions/browser/mock_display_info_provider.h
+++ b/extensions/browser/mock_display_info_provider.h
@@ -13,6 +13,7 @@
 
 #include "base/values.h"
 #include "extensions/browser/api/system_display/display_info_provider.h"
+#include "extensions/browser/mock_screen.h"
 #include "extensions/common/api/system_display.h"
 
 namespace extensions {
@@ -85,6 +86,8 @@
 
   bool native_touch_calibration_success_ = false;
 
+  MockScreen screen_;
+
   api::system_display::MirrorMode mirror_mode_ =
       api::system_display::MIRROR_MODE_OFF;
 };
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 8020b2c..af355d5 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -95,4 +95,11 @@
 const base::Feature kExtensionsMenuAccessControl{
     "ExtensionsMenuAccessControl", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// If enabled, calls RenderFrame::SetAllowsCrossBrowsingInstanceFrameLookup() in
+// DidCreateScriptContext() instead of DidCommitProvisionalLoad() to avoid
+// creating the script context too early which can be bad for performance.
+const base::Feature kAvoidEarlyExtensionScriptContextCreation{
+    "AvoidEarlyExtensionScriptContextCreation",
+    base::FEATURE_ENABLED_BY_DEFAULT};
+
 }  // namespace extensions_features
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index 5f12159..3083c76 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -37,6 +37,8 @@
 
 extern const base::Feature kExtensionsMenuAccessControl;
 
+extern const base::Feature kAvoidEarlyExtensionScriptContextCreation;
+
 }  // namespace extensions_features
 
 #endif  // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/extensions/common/image_util.cc b/extensions/common/image_util.cc
index a87ba5cd2..f4cc06d 100644
--- a/extensions/common/image_util.cc
+++ b/extensions/common/image_util.cc
@@ -13,6 +13,7 @@
 #include "base/cxx17_backports.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
@@ -104,9 +105,10 @@
   // Draw the icon onto a canvas, then draw the background color onto the
   // resulting bitmap, using SkBlendMode::kDifference. Then, check the RGB
   // values against the threshold. Any pixel with a value greater than the
-  // threshold is considered visible.
+  // threshold is considered visible. If analysis fails, don't render the icon.
   SkBitmap bitmap;
-  RenderIconForVisibilityAnalysis(icon, background_color, &bitmap);
+  if (!RenderIconForVisibilityAnalysis(icon, background_color, &bitmap))
+    return false;
 
   int visible_pixels = 0;
   for (int x = 0; x < icon.width(); ++x) {
@@ -123,16 +125,25 @@
   return false;
 }
 
-void RenderIconForVisibilityAnalysis(const SkBitmap& icon,
+bool RenderIconForVisibilityAnalysis(const SkBitmap& icon,
                                      SkColor background_color,
                                      SkBitmap* rendered_icon) {
   DCHECK(rendered_icon);
   DCHECK(rendered_icon->empty());
-  rendered_icon->allocN32Pixels(icon.width(), icon.height());
+  if (icon.width() * icon.height() > kMaxAllowedPixels) {
+    return false;
+  }
+  if (!rendered_icon->tryAllocN32Pixels(icon.width(), icon.height())) {
+    LOG(ERROR) << "Unable to allocate pixels for a " << icon.width() << "x"
+               << icon.height() << "icon.";
+    return false;
+  }
   rendered_icon->eraseColor(background_color);
   SkCanvas offscreen(*rendered_icon, SkSurfaceProps{});
   offscreen.drawImage(SkImage::MakeFromBitmap(icon), 0, 0);
   offscreen.drawColor(background_color, SkBlendMode::kDifference);
+
+  return true;
 }
 
 bool IsRenderedIconAtPathSufficientlyVisible(const base::FilePath& path,
diff --git a/extensions/common/image_util.h b/extensions/common/image_util.h
index b0bd4352c..ae4b1e3 100644
--- a/extensions/common/image_util.h
+++ b/extensions/common/image_util.h
@@ -40,11 +40,16 @@
 bool IsRenderedIconAtPathSufficientlyVisible(const base::FilePath& path,
                                              SkColor background_color);
 
+// Icons should be a reasonable size for analysis. There have been crash
+// reports due to memory allocation issues with calls to
+// SkBitmap::allocN32Pixels. See crbug.com/1155746.
+constexpr int kMaxAllowedPixels = 2048 * 2048;
+
 // Renders the icon bitmap onto another bitmap, combining it with the specified
 // background color. The output bitmap must be empty.
-void RenderIconForVisibilityAnalysis(const SkBitmap& icon,
-                                     SkColor background_color,
-                                     SkBitmap* rendered_icon);
+[[nodiscard]] bool RenderIconForVisibilityAnalysis(const SkBitmap& icon,
+                                                   SkColor background_color,
+                                                   SkBitmap* rendered_icon);
 
 // Load a PNG image from a file into the destination bitmap.
 bool LoadPngFromFile(const base::FilePath& path, SkBitmap* dst);
diff --git a/extensions/common/image_util_unittest.cc b/extensions/common/image_util_unittest.cc
index c9bac18..eaf5286a 100644
--- a/extensions/common/image_util_unittest.cc
+++ b/extensions/common/image_util_unittest.cc
@@ -111,6 +111,29 @@
   }
 }
 
+TEST(ImageUtilTest, IconTooLargeForAnalysis) {
+  base::FilePath test_dir;
+  ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
+  // This is a large icon which is entirely black, so it would be
+  // visible. However, it exceeds the max allowed size for analysis,
+  // so it will fail.
+  base::FilePath icon_path = test_dir.AppendASCII("3000x3000.png");
+  SkBitmap large_icon;
+  SkBitmap rendered_icon;
+  ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &large_icon));
+  EXPECT_FALSE(image_util::RenderIconForVisibilityAnalysis(
+      large_icon, SK_ColorWHITE, &rendered_icon));
+
+  // Shrink the icon so it's under the limit. It should be visible.
+  const SkImageInfo& image_info = large_icon.info();
+  SkImageInfo new_image_info = SkImageInfo::Make(
+      128, 128, image_info.colorType(), image_info.alphaType());
+  ASSERT_TRUE(large_icon.setInfo(new_image_info));
+  EXPECT_TRUE(image_util::RenderIconForVisibilityAnalysis(
+      large_icon, SK_ColorWHITE, &rendered_icon));
+  EXPECT_FALSE(rendered_icon.empty());
+}
+
 TEST(ImageUtilTest, MANUAL_IsIconSufficientlyVisiblePerfTest) {
   base::FilePath test_dir;
   ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
@@ -161,7 +184,8 @@
                        SkColor background_color,
                        const base::FilePath& rendered_icon_path) {
   SkBitmap bitmap;
-  image_util::RenderIconForVisibilityAnalysis(icon, background_color, &bitmap);
+  DCHECK(image_util::RenderIconForVisibilityAnalysis(icon, background_color,
+                                                     &bitmap));
   std::vector<unsigned char> output_data;
   ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output_data));
   const int bytes_to_write = output_data.size();
diff --git a/extensions/renderer/bindings/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
index ae6f419..737ba8f 100644
--- a/extensions/renderer/bindings/api_binding.cc
+++ b/extensions/renderer/bindings/api_binding.cc
@@ -74,7 +74,7 @@
       dict->FindKeyOfType("returns_async", base::Value::Type::DICTIONARY);
 
   return APISignature::CreateFromValues(*params, returns_async, access_checker,
-                                        api_name);
+                                        api_name, false /*is_event_signature*/);
 }
 
 void RunAPIBindingHandlerCallback(
@@ -332,6 +332,21 @@
         }
       }
 
+      if (binding::IsResponseValidationEnabled()) {
+        const base::Value* params =
+            event_dict->FindKeyOfType("parameters", base::Value::Type::LIST);
+        // NOTE: At least in tests, events may omit "parameters". It's unclear
+        // if real schemas do, too. For now, sub in an empty list if necessary.
+        // TODO(devlin): Track this down and CHECK(params).
+        base::Value empty_params(base::Value::Type::LIST);
+        std::unique_ptr<APISignature> event_signature =
+            APISignature::CreateFromValues(
+                params ? *params : empty_params, nullptr /*returns_async*/,
+                access_checker, name, true /*is_event_signature*/);
+        DCHECK(!event_signature->has_async_return());
+        type_refs_->AddEventSignature(full_name, std::move(event_signature));
+      }
+
       events_.push_back(std::make_unique<EventData>(
           std::move(name), std::move(full_name), supports_filters,
           supports_rules, supports_lazy_listeners, max_listeners,
diff --git a/extensions/renderer/bindings/api_binding_js_util.cc b/extensions/renderer/bindings/api_binding_js_util.cc
index 293bc4c9..7391858 100644
--- a/extensions/renderer/bindings/api_binding_js_util.cc
+++ b/extensions/renderer/bindings/api_binding_js_util.cc
@@ -305,7 +305,8 @@
       custom_signature_name,
       APISignature::CreateFromValues(*base_signature, nullptr /*returns_async*/,
                                      nullptr /*access_checker*/,
-                                     custom_signature_name));
+                                     custom_signature_name,
+                                     false /*is_event_signature*/));
 }
 
 void APIBindingJSUtil::ValidateCustomSignature(
diff --git a/extensions/renderer/bindings/api_bindings_system.cc b/extensions/renderer/bindings/api_bindings_system.cc
index 8e16846c..243935f 100644
--- a/extensions/renderer/bindings/api_bindings_system.cc
+++ b/extensions/renderer/bindings/api_bindings_system.cc
@@ -45,6 +45,8 @@
   if (binding::IsResponseValidationEnabled()) {
     request_handler_.SetResponseValidator(
         std::make_unique<APIResponseValidator>(&type_reference_map_));
+    event_handler_.SetResponseValidator(
+        std::make_unique<APIResponseValidator>(&type_reference_map_));
   }
 }
 
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
index 74ce87b..2c4603f 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -68,7 +68,12 @@
         "parameters": [{"name": "e", "$ref": "alpha.enumRef"}]
       }],
       "events": [{
-        "name": "alphaEvent"
+        "name": "alphaEvent",
+        "parameters": [{
+          "name": "eventArg",
+          "type": "object",
+          "properties": { "key": {"type": "integer"} }
+        }]
       }, {
         "name": "alphaOtherEvent"
       }]
@@ -320,7 +325,7 @@
         });)";
     CallFunctionOnObject(context, alpha_api, kTestCall);
 
-    const char kResponseArgsJson[] = R"(["response",1,{"key":42}])";
+    const char kResponseArgsJson[] = R"([{"key":42}])";
     base::Value::List expected_args = ListValueFromString(kResponseArgsJson);
     bindings_system()->FireEventInContext("alpha.alphaEvent", context,
                                           expected_args, nullptr);
diff --git a/extensions/renderer/bindings/api_event_handler.cc b/extensions/renderer/bindings/api_event_handler.cc
index 1e805ca..bb2d056 100644
--- a/extensions/renderer/bindings/api_event_handler.cc
+++ b/extensions/renderer/bindings/api_event_handler.cc
@@ -18,6 +18,7 @@
 #include "base/values.h"
 #include "content/public/renderer/v8_value_converter.h"
 #include "extensions/common/mojom/event_dispatcher.mojom.h"
+#include "extensions/renderer/bindings/api_response_validator.h"
 #include "extensions/renderer/bindings/event_emitter.h"
 #include "extensions/renderer/bindings/get_per_context_data.h"
 #include "extensions/renderer/bindings/js_runner.h"
@@ -109,6 +110,11 @@
       exception_handler_(exception_handler) {}
 APIEventHandler::~APIEventHandler() {}
 
+void APIEventHandler::SetResponseValidator(
+    std::unique_ptr<APIResponseValidator> validator) {
+  api_response_validator_ = std::move(validator);
+}
+
 v8::Local<v8::Object> APIEventHandler::CreateEventInstance(
     const std::string& event_name,
     bool supports_filters,
@@ -257,6 +263,17 @@
 
   auto massager_iter = data->massagers.find(event_name);
   if (massager_iter == data->massagers.end()) {
+    // Validate the event arguments if there are no massagers (and validation is
+    // enabled). Unfortunately, massagers both transform the event args from
+    // unexpected -> expected and (badly!) from expected -> unexpected. As such,
+    // we simply don't validate if there's a massager attached to the event.
+    // TODO(crbug.com/1329587): Ideally, we'd be able to validate the response
+    // after the massagers run. This requires fixing our schema for at least
+    // chrome.permissions events.
+    if (api_response_validator_) {
+      api_response_validator_->ValidateEvent(context, event_name, *arguments);
+    }
+
     emitter->Fire(context, arguments, std::move(filter), std::move(callback));
   } else {
     DCHECK(!callback) << "Can't use an event callback with argument massagers.";
diff --git a/extensions/renderer/bindings/api_event_handler.h b/extensions/renderer/bindings/api_event_handler.h
index d5c949f..4fa861c 100644
--- a/extensions/renderer/bindings/api_event_handler.h
+++ b/extensions/renderer/bindings/api_event_handler.h
@@ -16,6 +16,7 @@
 #include "v8/include/v8.h"
 
 namespace extensions {
+class APIResponseValidator;
 class ExceptionHandler;
 
 // The object to handle API events. This includes vending v8::Objects for the
@@ -39,6 +40,9 @@
 
   ~APIEventHandler();
 
+  // Sets the response validator to be used in verifying event arguments.
+  void SetResponseValidator(std::unique_ptr<APIResponseValidator> validator);
+
   // Returns a new v8::Object for an event with the given |event_name|. If
   // |notify_on_change| is true, notifies whenever listeners state is changed.
   // TODO(devlin): Maybe worth creating a Params struct to hold the event
@@ -111,6 +115,10 @@
   // The exception handler associated with the bindings system; guaranteed to
   // outlive this object.
   ExceptionHandler* const exception_handler_;
+
+  // The response validator used to verify event arguments. Only non-null if
+  // validation is enabled.
+  std::unique_ptr<APIResponseValidator> api_response_validator_;
 };
 
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_response_validator.cc b/extensions/renderer/bindings/api_response_validator.cc
index 42cb471..2386fca3 100644
--- a/extensions/renderer/bindings/api_response_validator.cc
+++ b/extensions/renderer/bindings/api_response_validator.cc
@@ -6,6 +6,8 @@
 
 #include <ostream>
 
+#include "base/containers/contains.h"
+#include "base/ranges/algorithm.h"
 #include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_signature.h"
 #include "extensions/renderer/bindings/api_type_reference_map.h"
@@ -14,21 +16,35 @@
 
 namespace {
 
-APIResponseValidator::TestHandler::HandlerMethod*
-    g_failure_handler_for_testing = nullptr;
+APIResponseValidator::TestHandler* g_handler_for_testing = nullptr;
 
 }  // namespace
 
 APIResponseValidator::TestHandler::TestHandler(HandlerMethod method)
     : method_(method) {
-  DCHECK(!g_failure_handler_for_testing)
+  DCHECK(!g_handler_for_testing)
       << "Only one TestHandler is allowed at a time.";
-  g_failure_handler_for_testing = &method_;
+  g_handler_for_testing = this;
 }
 
 APIResponseValidator::TestHandler::~TestHandler() {
-  DCHECK_EQ(&method_, g_failure_handler_for_testing);
-  g_failure_handler_for_testing = nullptr;
+  DCHECK_EQ(this, g_handler_for_testing);
+  g_handler_for_testing = nullptr;
+}
+
+void APIResponseValidator::TestHandler::IgnoreSignature(std::string signature) {
+  signatures_to_ignore_.insert(std::move(signature));
+}
+
+void APIResponseValidator::TestHandler::HandleFailure(
+    const std::string& signature_name,
+    const std::string& error) {
+  method_.Run(signature_name, error);
+}
+
+bool APIResponseValidator::TestHandler::ShouldIgnoreSignature(
+    const std::string& signature_name) const {
+  return base::Contains(signatures_to_ignore_, signature_name);
 }
 
 APIResponseValidator::APIResponseValidator(const APITypeReferenceMap* type_refs)
@@ -72,12 +88,58 @@
   }
 
   // The response did not match the expected schema.
-  if (g_failure_handler_for_testing) {
-    g_failure_handler_for_testing->Run(method_name, error);
+  if (g_handler_for_testing) {
+    g_handler_for_testing->HandleFailure(method_name, error);
   } else {
     NOTREACHED() << "Error validating response to `" << method_name
                  << "`: " << error;
   }
 }
 
+void APIResponseValidator::ValidateEvent(
+    v8::Local<v8::Context> context,
+    const std::string& event_name,
+    const std::vector<v8::Local<v8::Value>>& event_args) {
+  DCHECK(binding::IsResponseValidationEnabled());
+
+  const APISignature* signature = type_refs_->GetEventSignature(event_name);
+  // If there's no corresponding signature, don't validate. This can
+  // legitimately happen with APIs that create custom requests.
+  if (!signature)
+    return;
+
+  if (g_handler_for_testing &&
+      g_handler_for_testing->ShouldIgnoreSignature(event_name))
+    return;
+
+  // The following signatures are incorrect (the parameters dispatched to the
+  // event don't match the schema's event definition). These should be fixed
+  // and then validated.
+  // TODO(https://crbug.com/1329587): Eliminate this list.
+  static constexpr char const* kBrokenSignaturesToIgnore[] = {
+      "automationInternal.onAccessibilityEvent",
+      "chromeWebViewInternal.onClicked",
+      "test.onMessage",
+  };
+
+  if (base::ranges::find(kBrokenSignaturesToIgnore, event_name) !=
+      std::end(kBrokenSignaturesToIgnore))
+    return;
+
+  std::string error;
+  if (signature->ValidateCall(context, event_args, *type_refs_, &error)) {
+    // Response was valid.
+    return;
+  }
+
+  // The response did not match the expected schema.
+  // Pull to helper method.
+  if (g_handler_for_testing) {
+    g_handler_for_testing->HandleFailure(event_name, error);
+  } else {
+    NOTREACHED() << "Error validating event arguments to `" << event_name
+                 << "`: " << error;
+  }
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_response_validator.h b/extensions/renderer/bindings/api_response_validator.h
index 7628739..8144678 100644
--- a/extensions/renderer/bindings/api_response_validator.h
+++ b/extensions/renderer/bindings/api_response_validator.h
@@ -5,6 +5,7 @@
 #ifndef EXTENSIONS_RENDERER_BINDINGS_API_RESPONSE_VALIDATOR_H_
 #define EXTENSIONS_RENDERER_BINDINGS_API_RESPONSE_VALIDATOR_H_
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -17,6 +18,8 @@
 // A class to validate the responses to API calls sent by the browser. This
 // helps ensure that the browser returns values that match the expected schema
 // (which corresponds to the public documentation).
+// TODO(devlin): This is now used for both API method responses and event
+// arguments. Rename to APISignatureValidator?
 class APIResponseValidator {
  public:
   // Allow overriding the default failure behavior.
@@ -32,8 +35,21 @@
 
     ~TestHandler();
 
+    // Ignores the given `signature` for testing purposes.
+    void IgnoreSignature(std::string signature);
+
+    // Forwards the failure call to the handler `method_`.
+    void HandleFailure(const std::string& signature_name,
+                       const std::string& error);
+
+    // Returns true if the given `signature_name` should be ignored for
+    // testing purposes.
+    bool ShouldIgnoreSignature(const std::string& signature_name) const;
+
    private:
     HandlerMethod method_;
+
+    std::set<std::string> signatures_to_ignore_;
   };
 
   // The origin of the callback passed to the response.
@@ -65,6 +81,12 @@
       const std::string& api_error,
       CallbackType callback_type);
 
+  // Validates a collection of event arguments against the expected schema.
+  // By default, this will NOTREACHED() in cases of validation failure.
+  void ValidateEvent(v8::Local<v8::Context> context,
+                     const std::string& event_name,
+                     const std::vector<v8::Local<v8::Value>>& event_args);
+
  private:
   // The type reference map; guaranteed to outlive this object.
   const APITypeReferenceMap* type_refs_;
diff --git a/extensions/renderer/bindings/api_signature.cc b/extensions/renderer/bindings/api_signature.cc
index 6165522..9a0d69e 100644
--- a/extensions/renderer/bindings/api_signature.cc
+++ b/extensions/renderer/bindings/api_signature.cc
@@ -445,6 +445,59 @@
   return result;
 }
 
+// A helper method used to validate a signature for an internal caller (such as
+// a response to an API method or event arguments) to ensure it matches the
+// expected schema.
+bool ValidateSignatureForInternalCaller(
+    v8::Local<v8::Context> context,
+    const std::vector<v8::Local<v8::Value>>& arguments,
+    const std::vector<std::unique_ptr<ArgumentSpec>>& expected,
+    const APITypeReferenceMap& type_refs,
+    std::string* error) {
+  size_t expected_size = expected.size();
+  size_t actual_size = arguments.size();
+  if (actual_size > expected_size) {
+    *error = api_errors::TooManyArguments();
+    return false;
+  }
+
+  // Easy validation: arguments go in order, and must match the expected schema.
+  // Anything less is failure.
+  std::string parse_error;
+  for (size_t i = 0; i < actual_size; ++i) {
+    DCHECK(!arguments[i].IsEmpty());
+    const ArgumentSpec& spec = *expected[i];
+    if (arguments[i]->IsNullOrUndefined()) {
+      if (!spec.optional()) {
+        *error = api_errors::MissingRequiredArgument(spec.name().c_str());
+        return false;
+      }
+      continue;
+    }
+
+    if (!spec.ParseArgument(context, arguments[i], type_refs, nullptr, nullptr,
+                            &parse_error)) {
+      *error = api_errors::ArgumentError(spec.name(), parse_error);
+      return false;
+    }
+  }
+
+  // Responses may omit trailing optional parameters (which would then be
+  // undefined for the caller).
+  // NOTE(devlin): It might be nice to see if we could require all arguments to
+  // be present, no matter what. For one, it avoids this loop, and it would also
+  // unify what a "not found" value was (some APIs use undefined, some use
+  // null).
+  for (size_t i = actual_size; i < expected_size; ++i) {
+    if (!expected[i]->optional()) {
+      *error = api_errors::MissingRequiredArgument(expected[i]->name().c_str());
+      return false;
+    }
+  }
+
+  return true;
+}
+
 }  // namespace
 
 APISignature::ReturnsAsync::ReturnsAsync() = default;
@@ -467,7 +520,7 @@
     std::vector<std::unique_ptr<ArgumentSpec>> signature,
     std::unique_ptr<APISignature::ReturnsAsync> returns_async,
     BindingAccessChecker* access_checker)
-    : method_signature_(std::move(signature)),
+    : signature_(std::move(signature)),
       returns_async_(std::move(returns_async)),
       access_checker_(access_checker) {
   if (returns_async_) {
@@ -481,7 +534,7 @@
     auto callback = std::make_unique<ArgumentSpec>(ArgumentType::FUNCTION);
     callback->set_optional(returns_async_->optional);
     callback->set_name("callback");
-    method_signature_.push_back(std::move(callback));
+    signature_.push_back(std::move(callback));
 
     if (returns_async_->promise_support ==
         binding::APIPromiseSupport::kSupported) {
@@ -500,7 +553,8 @@
     const base::Value& spec_list,
     const base::Value* returns_async,
     BindingAccessChecker* access_checker,
-    const std::string& api_name) {
+    const std::string& api_name,
+    bool is_event_signature) {
   bool uses_returns_async = returns_async != nullptr;
   auto argument_specs = ValueListToArgumentSpecs(spec_list, uses_returns_async);
 
@@ -511,8 +565,9 @@
   // all the asynchronous API schemas to use the returns_async format it will be
   // clear when this is the case, but for now we keep a list of the names of
   // these APIs to ensure we are handling them correctly.
+  // This is irrelevant for event signatures.
   const base::Value* returns_async_spec = returns_async;
-  if (!argument_specs.empty() &&
+  if (!is_event_signature && !argument_specs.empty() &&
       argument_specs.back()->type() == ArgumentType::FUNCTION &&
       !base::Contains(kNonCallbackTrailingFunctionAPINames, api_name)) {
     DCHECK(!returns_async_spec);
@@ -537,7 +592,7 @@
     const std::vector<v8::Local<v8::Value>>& arguments,
     const APITypeReferenceMap& type_refs) const {
   PromisesAllowed promises_allowed = CheckPromisesAllowed(context);
-  return V8ArgumentParser(context, method_signature_, arguments, type_refs,
+  return V8ArgumentParser(context, signature_, arguments, type_refs,
                           promises_allowed)
       .ParseArguments(has_async_return());
 }
@@ -547,8 +602,8 @@
     const std::vector<v8::Local<v8::Value>>& arguments,
     const APITypeReferenceMap& type_refs) const {
   PromisesAllowed promises_allowed = CheckPromisesAllowed(context);
-  return BaseValueArgumentParser(context, method_signature_, arguments,
-                                 type_refs, promises_allowed)
+  return BaseValueArgumentParser(context, signature_, arguments, type_refs,
+                                 promises_allowed)
       .ParseArguments(has_async_return());
 }
 
@@ -615,56 +670,24 @@
     std::string* error) const {
   DCHECK(returns_async_);
   DCHECK(returns_async_->signature);
-  size_t expected_size = returns_async_->signature->size();
-  size_t actual_size = arguments.size();
-  if (actual_size > expected_size) {
-    *error = api_errors::TooManyArguments();
-    return false;
-  }
+  return ValidateSignatureForInternalCaller(
+      context, arguments, *returns_async_->signature, type_refs, error);
+}
 
-  // Easy validation: arguments go in order, and must match the expected schema.
-  // Anything less is failure.
-  std::string parse_error;
-  for (size_t i = 0; i < actual_size; ++i) {
-    DCHECK(!arguments[i].IsEmpty());
-    const ArgumentSpec& spec = *returns_async_->signature.value()[i];
-    if (arguments[i]->IsNullOrUndefined()) {
-      if (!spec.optional()) {
-        *error = api_errors::MissingRequiredArgument(spec.name().c_str());
-        return false;
-      }
-      continue;
-    }
-
-    if (!spec.ParseArgument(context, arguments[i], type_refs, nullptr, nullptr,
-                            &parse_error)) {
-      *error = api_errors::ArgumentError(spec.name(), parse_error);
-      return false;
-    }
-  }
-
-  // Responses may omit trailing optional parameters (which would then be
-  // undefined for the caller).
-  // NOTE(devlin): It might be nice to see if we could require all arguments to
-  // be present, no matter what. For one, it avoids this loop, and it would also
-  // unify what a "not found" value was (some APIs use undefined, some use
-  // null).
-  for (size_t i = actual_size; i < expected_size; ++i) {
-    if (!returns_async_->signature.value()[i]->optional()) {
-      *error = api_errors::MissingRequiredArgument(
-          returns_async_->signature.value()[i]->name().c_str());
-      return false;
-    }
-  }
-
-  return true;
+bool APISignature::ValidateCall(
+    v8::Local<v8::Context> context,
+    const std::vector<v8::Local<v8::Value>>& arguments,
+    const APITypeReferenceMap& type_refs,
+    std::string* error) const {
+  return ValidateSignatureForInternalCaller(context, arguments, signature_,
+                                            type_refs, error);
 }
 
 std::string APISignature::GetExpectedSignature() const {
-  if (!expected_signature_.empty() || method_signature_.empty())
+  if (!expected_signature_.empty() || signature_.empty())
     return expected_signature_;
 
-  expected_signature_ = ArgumentSpecsToString(method_signature_);
+  expected_signature_ = ArgumentSpecsToString(signature_);
 
   return expected_signature_;
 }
diff --git a/extensions/renderer/bindings/api_signature.h b/extensions/renderer/bindings/api_signature.h
index 9d599f1..3841be9c 100644
--- a/extensions/renderer/bindings/api_signature.h
+++ b/extensions/renderer/bindings/api_signature.h
@@ -29,8 +29,10 @@
   kDisallowed,
 };
 
-// A representation of the expected signature for an API method, along with the
+// A representation of the expected signature for an API, along with the
 // ability to match provided arguments and convert them to base::Values.
+// This is primarily used for API methods, but can also be used for API event
+// signatures.
 class APISignature {
  public:
   // Struct that bundles all the details about an asynchronous return.
@@ -69,7 +71,8 @@
       const base::Value& specification_list,
       const base::Value* returns_async,
       BindingAccessChecker* access_checker,
-      const std::string& api_name);
+      const std::string& api_name,
+      bool is_event_signature);
 
   struct V8ParseResult {
     // Appease the Chromium style plugin (out of line ctor/dtor).
@@ -147,6 +150,15 @@
                         const APITypeReferenceMap& type_refs,
                         std::string* error) const;
 
+  // Same as `ValidateResponse`, but verifies the given `arguments` against the
+  // `signature_` instead of the `returns_async_` types. This can be used when
+  // validating that APIs return proper values to an event (which has a
+  // signature, but no return).
+  bool ValidateCall(v8::Local<v8::Context> context,
+                    const std::vector<v8::Local<v8::Value>>& arguments,
+                    const APITypeReferenceMap& type_refs,
+                    std::string* error) const;
+
   // Returns a developer-readable string of the expected signature. For
   // instance, if this signature expects a string 'someStr' and an optional int
   // 'someInt', this would return "string someStr, optional integer someInt".
@@ -162,10 +174,10 @@
   // |context|.
   PromisesAllowed CheckPromisesAllowed(v8::Local<v8::Context> context) const;
 
-  // The list of expected arguments for the API method.
-  std::vector<std::unique_ptr<ArgumentSpec>> method_signature_;
+  // The list of expected arguments for the API signature.
+  std::vector<std::unique_ptr<ArgumentSpec>> signature_;
 
-  // The details of any asynchronous return the API method may have. Will be
+  // The details of any asynchronous return an API method may have. This will be
   // nullptr if the the API doesn't have an asynchronous return.
   std::unique_ptr<APISignature::ReturnsAsync> returns_async_;
 
diff --git a/extensions/renderer/bindings/api_type_reference_map.cc b/extensions/renderer/bindings/api_type_reference_map.cc
index 9274906..9378919 100644
--- a/extensions/renderer/bindings/api_type_reference_map.cc
+++ b/extensions/renderer/bindings/api_type_reference_map.cc
@@ -97,4 +97,18 @@
   return iter != custom_signatures_.end() ? iter->second.get() : nullptr;
 }
 
+void APITypeReferenceMap::AddEventSignature(
+    const std::string& event_name,
+    std::unique_ptr<APISignature> signature) {
+  DCHECK(event_signatures_.find(event_name) == event_signatures_.end())
+      << "Cannot re-register signature for: " << event_name;
+  event_signatures_[event_name] = std::move(signature);
+}
+
+const APISignature* APITypeReferenceMap::GetEventSignature(
+    const std::string& event_name) const {
+  auto iter = event_signatures_.find(event_name);
+  return iter != event_signatures_.end() ? iter->second.get() : nullptr;
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_type_reference_map.h b/extensions/renderer/bindings/api_type_reference_map.h
index 748e43a..fdfdd20 100644
--- a/extensions/renderer/bindings/api_type_reference_map.h
+++ b/extensions/renderer/bindings/api_type_reference_map.h
@@ -68,6 +68,13 @@
   // Looks up a custom signature that was previously added.
   const APISignature* GetCustomSignature(const std::string& name) const;
 
+  // Adds a signature for an API event with the given `event_name`.
+  void AddEventSignature(const std::string& event_name,
+                         std::unique_ptr<APISignature> signature);
+
+  // Retrieves a signature for an API event with the given `event_name`.
+  const APISignature* GetEventSignature(const std::string& event_name) const;
+
   // Returns the associated APISignature for the given |name|. Logic differs
   // slightly from a normal GetAPIMethodSignature as we don't want to initialize
   // a new type if the signature is not found.
@@ -80,9 +87,12 @@
   InitializeTypeCallback initialize_type_;
 
   std::map<std::string, std::unique_ptr<ArgumentSpec>> type_refs_;
-  std::map<std::string, std::unique_ptr<APISignature>> api_methods_;
-  std::map<std::string, std::unique_ptr<APISignature>> type_methods_;
-  std::map<std::string, std::unique_ptr<APISignature>> custom_signatures_;
+
+  using SignatureMap = std::map<std::string, std::unique_ptr<APISignature>>;
+  SignatureMap api_methods_;
+  SignatureMap type_methods_;
+  SignatureMap custom_signatures_;
+  SignatureMap event_signatures_;
 };
 
 }  // namespace extensions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 9383adb..7f14cbd8 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -450,7 +450,7 @@
   if (!frame_helper)
     return;  // The frame is invisible to extensions.
 
-  frame_helper->set_did_create_script_context();
+  frame_helper->NotifyDidCreateScriptContext(world_id);
 }
 
 void Dispatcher::DidInitializeServiceWorkerContextOnWorkerThread(
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 92ad543..47ab6ad1 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 
+#include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
@@ -15,6 +16,7 @@
 #include "extensions/common/api/messaging/message.h"
 #include "extensions/common/api/messaging/port_id.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_features.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/manifest_handlers/background_info.h"
 #include "extensions/renderer/api/automation/automation_api_helper.h"
@@ -364,6 +366,10 @@
 
 void ExtensionFrameHelper::DidCommitProvisionalLoad(
     ui::PageTransition transition) {
+  if (base::FeatureList::IsEnabled(
+          extensions_features::kAvoidEarlyExtensionScriptContextCreation)) {
+    return;
+  }
   // Grant cross browsing instance frame lookup if we are an extension. This
   // should match the conditions in FindFrame.
   content::RenderFrame* frame = render_frame();
@@ -568,6 +574,19 @@
   browser_window_id_ = window_id;
 }
 
+void ExtensionFrameHelper::NotifyDidCreateScriptContext(int32_t world_id) {
+  did_create_script_context_ = true;
+  if (world_id == blink::kMainDOMWorldId &&
+      base::FeatureList::IsEnabled(
+          extensions_features::kAvoidEarlyExtensionScriptContextCreation)) {
+    // Grant cross browsing instance frame lookup if we are an extension. This
+    // should match the conditions in FindFrame.
+    content::RenderFrame* frame = render_frame();
+    if (GetExtensionFromFrame(frame))
+      frame->SetAllowsCrossBrowsingInstanceFrameLookup();
+  }
+}
+
 void ExtensionFrameHelper::OnDestruct() {
   delete this;
 }
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h
index b5ae5fb..0ccaf96 100644
--- a/extensions/renderer/extension_frame_helper.h
+++ b/extensions/renderer/extension_frame_helper.h
@@ -121,7 +121,7 @@
 
   void UpdateBrowserWindowId(int32_t window_id) override;
 
-  void set_did_create_script_context() { did_create_script_context_ = true; }
+  void NotifyDidCreateScriptContext(int32_t world_id);
   bool did_create_script_context() const { return did_create_script_context_; }
 
   // Called when the document element has been inserted in this frame. This
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 0434f44..247ed15 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -1135,18 +1135,19 @@
   EXPECT_EQ(context, api_bridge.As<v8::Object>()->GetCreationContextChecked());
 }
 
-class ResponseValidationNativeExtensionBindingsSystemUnittest
+class SignatureValidationNativeExtensionBindingsSystemUnittest
     : public NativeExtensionBindingsSystemUnittest,
       public testing::WithParamInterface<bool> {
  public:
-  ResponseValidationNativeExtensionBindingsSystemUnittest() = default;
+  SignatureValidationNativeExtensionBindingsSystemUnittest() = default;
 
-  ResponseValidationNativeExtensionBindingsSystemUnittest(
-      const ResponseValidationNativeExtensionBindingsSystemUnittest&) = delete;
-  ResponseValidationNativeExtensionBindingsSystemUnittest& operator=(
-      const ResponseValidationNativeExtensionBindingsSystemUnittest&) = delete;
+  SignatureValidationNativeExtensionBindingsSystemUnittest(
+      const SignatureValidationNativeExtensionBindingsSystemUnittest&) = delete;
+  SignatureValidationNativeExtensionBindingsSystemUnittest& operator=(
+      const SignatureValidationNativeExtensionBindingsSystemUnittest&) = delete;
 
-  ~ResponseValidationNativeExtensionBindingsSystemUnittest() override = default;
+  ~SignatureValidationNativeExtensionBindingsSystemUnittest() override =
+      default;
 
   void SetUp() override {
     response_validation_override_ =
@@ -1163,7 +1164,7 @@
   std::unique_ptr<base::AutoReset<bool>> response_validation_override_;
 };
 
-TEST_P(ResponseValidationNativeExtensionBindingsSystemUnittest,
+TEST_P(SignatureValidationNativeExtensionBindingsSystemUnittest,
        ResponseValidation) {
   // The APIResponseValidator should only be used if response validation is
   // enabled. Otherwise, it should be null.
@@ -1239,9 +1240,98 @@
   }
 }
 
+TEST_P(SignatureValidationNativeExtensionBindingsSystemUnittest,
+       EventArgumentValidation) {
+  // The APIResponseValidator should only be used if response validation is
+  // enabled. Otherwise, it should be null.
+  EXPECT_EQ(GetParam(), bindings_system()
+                            ->api_system()
+                            ->request_handler()
+                            ->has_response_validator_for_testing());
+
+  absl::optional<std::string> validation_failure_method_name;
+  absl::optional<std::string> validation_failure_error;
+
+  auto on_validation_failure =
+      [&validation_failure_method_name, &validation_failure_error](
+          const std::string& method_name, const std::string& error) {
+        validation_failure_method_name = method_name;
+        validation_failure_error = error;
+      };
+  APIResponseValidator::TestHandler test_validation_failure_handler(
+      base::BindLambdaForTesting(on_validation_failure));
+
+  scoped_refptr<const Extension> extension =
+      ExtensionBuilder("foo").AddPermissions({"idle"}).Build();
+  RegisterExtension(extension);
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  ScriptContext* script_context = CreateScriptContext(
+      context, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT);
+  script_context->set_url(extension->url());
+
+  bindings_system()->UpdateBindingsForContext(script_context);
+
+  const char kAddListenerFunction[] =
+      R"((function() {
+            chrome.idle.onStateChanged.addListener((state) => {
+              this.returnedState = state;
+            });
+          });)";
+  v8::Local<v8::Function> add_listener_function =
+      FunctionFromString(context, kAddListenerFunction);
+  RunFunctionOnGlobal(add_listener_function, context, 0, nullptr);
+
+  EXPECT_TRUE(bindings_system()->HasEventListenerInContext(
+      "idle.onStateChanged", script_context));
+
+  // Dispatch an event with an argument that matches the expected schema.
+  {
+    base::Value::List event_args;
+    event_args.Append("active");
+    bindings_system()->DispatchEventInContext("idle.onStateChanged", event_args,
+                                              nullptr, script_context);
+  }
+
+  // Validation should have succeeded.
+  std::string returned_state =
+      GetStringPropertyFromObject(context->Global(), context, "returnedState");
+  EXPECT_FALSE(validation_failure_method_name);
+  EXPECT_FALSE(validation_failure_error);
+  EXPECT_EQ(R"("active")", returned_state);
+
+  // Now, dispatch the event with an invalid argument.
+  {
+    base::Value::List event_args;
+    event_args.Append("bad enum");
+    bindings_system()->DispatchEventInContext("idle.onStateChanged", event_args,
+                                              nullptr, script_context);
+  }
+
+  // Event validation should have failed.
+  returned_state =
+      GetStringPropertyFromObject(context->Global(), context, "returnedState");
+
+  if (GetParam()) {
+    EXPECT_EQ(validation_failure_method_name, "idle.onStateChanged");
+    EXPECT_EQ(api_errors::ArgumentError(
+                  "newState",
+                  api_errors::InvalidEnumValue({"active", "idle", "locked"})),
+              validation_failure_error.value_or("no value"));
+  } else {
+    EXPECT_FALSE(validation_failure_method_name);
+    EXPECT_FALSE(validation_failure_error);
+  }
+
+  // Even though validation failed, we still dispatch the event.
+  EXPECT_EQ(R"("bad enum")", returned_state);
+}
+
 INSTANTIATE_TEST_SUITE_P(
     All,
-    ResponseValidationNativeExtensionBindingsSystemUnittest,
+    SignatureValidationNativeExtensionBindingsSystemUnittest,
     testing::Bool());
 
 }  // namespace extensions
diff --git a/extensions/renderer/native_renderer_messaging_service_unittest.cc b/extensions/renderer/native_renderer_messaging_service_unittest.cc
index 16622c4c..b8f49b02 100644
--- a/extensions/renderer/native_renderer_messaging_service_unittest.cc
+++ b/extensions/renderer/native_renderer_messaging_service_unittest.cc
@@ -17,6 +17,7 @@
 #include "extensions/common/value_builder.h"
 #include "extensions/renderer/bindings/api_binding_test_util.h"
 #include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_response_validator.h"
 #include "extensions/renderer/message_target.h"
 #include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/native_extension_bindings_system.h"
@@ -26,6 +27,40 @@
 
 namespace extensions {
 
+namespace {
+
+// Unfortunately, we have a layering violation in the runtime API. The runtime
+// API is defined at the //extensions layer, but the `MessageSender` type has an
+// optional `tabs.Tab` property. This causes issues in type validation because
+// when we try to look up the `tabs.Tab` property, it fails (since it's only
+// defined in //chrome). This is a "real bug" in that it's a layering violation,
+// but it doesn't have real-world implications since right now the only consumer
+// of //extensions is //chrome (and thus, the tabs API will always be defined).
+// Ignore validation for the affected runtime message-related events.
+class RuntimeMessageValidationIgnorer {
+ public:
+  RuntimeMessageValidationIgnorer()
+      : test_handler_(base::BindRepeating(
+            &RuntimeMessageValidationIgnorer::HardValidationFailure)) {
+    test_handler_.IgnoreSignature("runtime.onMessage");
+    test_handler_.IgnoreSignature("runtime.onMessageExternal");
+    test_handler_.IgnoreSignature("runtime.onConnect");
+  }
+  ~RuntimeMessageValidationIgnorer() = default;
+
+ private:
+  // Hard-fail on any unexpected validation errors.
+  static void HardValidationFailure(const std::string& name,
+                                    const std::string& failure) {
+    NOTREACHED() << "Unexpected validation failure: " << name << ", "
+                 << failure;
+  }
+
+  APIResponseValidator::TestHandler test_handler_;
+};
+
+}  // namespace
+
 class NativeRendererMessagingServiceTest
     : public NativeExtensionBindingsSystemUnittest {
  public:
@@ -101,6 +136,8 @@
 }
 
 TEST_F(NativeRendererMessagingServiceTest, OpenMessagePort) {
+  RuntimeMessageValidationIgnorer message_validation_ignorer;
+
   v8::HandleScope handle_scope(isolate());
   v8::Local<v8::Context> context = MainContext();
 
@@ -435,6 +472,8 @@
 // this is more thoroughly tested in the OneTimeMessageHandler tests; this is
 // just to ensure NativeRendererMessagingService correctly forwards the calls.
 TEST_F(NativeRendererMessagingServiceTest, ReceiveOneTimeMessage) {
+  RuntimeMessageValidationIgnorer message_validation_ignorer;
+
   v8::HandleScope handle_scope(isolate());
   v8::Local<v8::Context> context = MainContext();
 
@@ -498,6 +537,8 @@
 // Test sending a one-time message from an external source (e.g., a different
 // extension). This shouldn't conflict with messages sent from the same source.
 TEST_F(NativeRendererMessagingServiceTest, TestExternalOneTimeMessages) {
+  RuntimeMessageValidationIgnorer message_validation_ignorer;
+
   v8::HandleScope handle_scope(isolate());
   v8::Local<v8::Context> context = MainContext();
 
diff --git a/extensions/renderer/one_time_message_handler_unittest.cc b/extensions/renderer/one_time_message_handler_unittest.cc
index 3ed5ce6e..0e49a25 100644
--- a/extensions/renderer/one_time_message_handler_unittest.cc
+++ b/extensions/renderer/one_time_message_handler_unittest.cc
@@ -312,9 +312,10 @@
   const PortId port_id(other_context_id, 0, false, SerializationFormat::kJson);
 
   EXPECT_FALSE(message_handler()->HasPort(script_context(), port_id));
-  v8::Local<v8::Object> sender = gin::DataObjectBuilder(isolate())
-                                     .Set("key", std::string("sender"))
-                                     .Build();
+  v8::Local<v8::Object> sender =
+      gin::DataObjectBuilder(isolate())
+          .Set("origin", std::string("https://example.com"))
+          .Build();
   message_handler()->AddReceiver(script_context(), port_id, sender,
                                  messaging_util::kOnMessageEvent);
   EXPECT_TRUE(message_handler()->HasPort(script_context(), port_id));
@@ -328,7 +329,8 @@
   message_handler()->DeliverMessage(script_context(), message, port_id);
 
   EXPECT_EQ("\"Hi\"", GetGlobalProperty(context, "eventMessage"));
-  EXPECT_EQ(R"({"key":"sender"})", GetGlobalProperty(context, "eventSender"));
+  EXPECT_EQ(R"({"origin":"https://example.com"})",
+            GetGlobalProperty(context, "eventSender"));
 
   // TODO(devlin): Right now, the port lives eternally. In JS bindings, we have
   // two ways of dealing with this:
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc
index aec280e..e13a55e 100644
--- a/extensions/shell/app/shell_main_delegate.cc
+++ b/extensions/shell/app/shell_main_delegate.cc
@@ -178,12 +178,6 @@
 }
 #endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
 
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-void ShellMainDelegate::PostEarlyInitialization(bool is_running_tests) {}
-#endif
-
 // static
 bool ShellMainDelegate::ProcessNeedsResourceBundle(
     const std::string& process_type) {
diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h
index 51bf192..8117ae4 100644
--- a/extensions/shell/app/shell_main_delegate.h
+++ b/extensions/shell/app/shell_main_delegate.h
@@ -44,11 +44,6 @@
 #if BUILDFLAG(IS_MAC)
   void PreBrowserMain() override;
 #endif
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-  void PostEarlyInitialization(bool is_running_tests) override;
-#endif
 
  private:
   // |process_type| is zygote, renderer, utility, etc. Returns true if the
diff --git a/extensions/shell/browser/shell_desktop_controller_aura_unittest.cc b/extensions/shell/browser/shell_desktop_controller_aura_unittest.cc
index aac03851..204c58e 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura_unittest.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura_unittest.cc
@@ -54,9 +54,7 @@
   ~ShellDesktopControllerAuraTest() override = default;
 
   void SetUp() override {
-    ShellTestBaseAura::SetUp();
-
-    // Set up a screen with 2 displays.
+    // Set up a screen with 2 displays before `ShellTestBaseAura::SetUp()`
     screen_ = std::make_unique<display::ScreenBase>();
     screen_->display_list().AddDisplay(
         display::Display(100, gfx::Rect(0, 0, 1920, 1080)),
@@ -66,6 +64,7 @@
         display::DisplayList::Type::NOT_PRIMARY);
     screen_override_ =
         std::make_unique<display::test::ScopedScreenOverride>(screen_.get());
+    ShellTestBaseAura::SetUp();
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     chromeos::PowerManagerClient::InitializeFake();
@@ -80,9 +79,9 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     chromeos::PowerManagerClient::Shutdown();
 #endif
+    ShellTestBaseAura::TearDown();
     screen_override_.reset();
     screen_.reset();
-    ShellTestBaseAura::TearDown();
   }
 
  protected:
diff --git a/extensions/shell/browser/shell_desktop_controller_mac.h b/extensions/shell/browser/shell_desktop_controller_mac.h
index e78005f2..d3ba91d 100644
--- a/extensions/shell/browser/shell_desktop_controller_mac.h
+++ b/extensions/shell/browser/shell_desktop_controller_mac.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "extensions/shell/browser/desktop_controller.h"
+#include "ui/display/screen.h"
 
 namespace extensions {
 
@@ -36,6 +37,8 @@
   // The desktop only supports a single app window.
   // TODO(yoz): Support multiple app windows, as we do in Aura.
   AppWindow* app_window_;  // NativeAppWindow::Close() deletes this.
+
+  display::ScopedNativeScreen screen_;
 };
 
 }  // namespace extensions
diff --git a/extensions/shell/test/test_shell_main_delegate.cc b/extensions/shell/test/test_shell_main_delegate.cc
index 8d326cdf..a1d8e96 100644
--- a/extensions/shell/test/test_shell_main_delegate.cc
+++ b/extensions/shell/test/test_shell_main_delegate.cc
@@ -49,9 +49,12 @@
 TestShellMainDelegate::~TestShellMainDelegate() {}
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-void TestShellMainDelegate::PostEarlyInitialization(bool is_running_tests) {
-  // Browser tests on Lacros requires a non-null LacrosService.
-  lacros_service_ = std::make_unique<chromeos::LacrosService>();
+void TestShellMainDelegate::PostEarlyInitialization(InvokedIn invoked_in) {
+  if (invoked_in != InvokedIn::kChildProcess) {
+    // Browser tests on Lacros requires a non-null LacrosService.
+    lacros_service_ = std::make_unique<chromeos::LacrosService>();
+  }
+  extensions::ShellMainDelegate::PostEarlyInitialization(invoked_in);
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/extensions/shell/test/test_shell_main_delegate.h b/extensions/shell/test/test_shell_main_delegate.h
index ab8b7e8..e569f087 100644
--- a/extensions/shell/test/test_shell_main_delegate.h
+++ b/extensions/shell/test/test_shell_main_delegate.h
@@ -34,7 +34,7 @@
 
   // ContentMainDelegate implementation:
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  void PostEarlyInitialization(bool is_running_tests) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
 #endif
 
  protected:
diff --git a/extensions/test/data/3000x3000.png b/extensions/test/data/3000x3000.png
new file mode 100644
index 0000000..ba8a1972
--- /dev/null
+++ b/extensions/test/data/3000x3000.png
Binary files differ
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.cc b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
index f0e5b63..09ba39a 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.cc
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
@@ -55,6 +55,7 @@
 #include "third_party/widevine/cdm/widevine_cdm_common.h"
 #include "ui/aura/screen_ozone.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/switches.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/ozone_switches.h"
@@ -167,9 +168,7 @@
     content::ContentBrowserClient* browser_client)
     : browser_client_(browser_client) {}
 
-WebEngineBrowserMainParts::~WebEngineBrowserMainParts() {
-  display::Screen::SetScreenInstance(nullptr);
-}
+WebEngineBrowserMainParts::~WebEngineBrowserMainParts() = default;
 
 std::vector<content::BrowserContext*>
 WebEngineBrowserMainParts::browser_contexts() const {
@@ -190,7 +189,6 @@
 }
 
 int WebEngineBrowserMainParts::PreMainMessageLoopRun() {
-  DCHECK(!screen_);
   DCHECK_EQ(context_bindings_.size(), 0u);
 
   // Initialize the |component_inspector_| to allow diagnostics to be published.
@@ -251,11 +249,7 @@
                           base::Unretained(this)));
 
   // Configure Ozone with an Aura implementation of the Screen abstraction.
-  std::unique_ptr<aura::ScreenOzone> screen_ozone =
-      std::make_unique<aura::ScreenOzone>();
-  screen_ozone.get()->Initialize();
-  screen_ = std::move(screen_ozone);
-  display::Screen::SetScreenInstance(screen_.get());
+  screen_ = std::make_unique<aura::ScopedScreenOzone>();
 
   // Create the FuchsiaCdmManager at startup rather than on-demand, to allow it
   // to perform potentially expensive startup work in the background.
@@ -312,7 +306,6 @@
   // that they may post cleanup tasks during teardown.
   // NOTE: Objects are destroyed in the reverse order of their creation.
   legacy_metrics_client_.reset();
-  screen_.reset();
   intl_profile_watcher_.reset();
 
   base::ImportantFileWriterCleaner::GetInstance().Stop();
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.h b/fuchsia/engine/browser/web_engine_browser_main_parts.h
index 681b71a..5915399 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.h
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.h
@@ -22,7 +22,7 @@
 }
 
 namespace display {
-class Screen;
+class ScopedNativeScreen;
 }
 
 namespace content {
@@ -120,7 +120,7 @@
 
   content::ContentBrowserClient* const browser_client_;
 
-  std::unique_ptr<display::Screen> screen_;
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
 
   // Used to publish diagnostics including the active Contexts and FrameHosts.
   std::unique_ptr<sys::ComponentInspector> component_inspector_;
diff --git a/fuchsia/engine/browser/web_engine_net_log_observer.cc b/fuchsia/engine/browser/web_engine_net_log_observer.cc
index 73c3223..3aec91ba 100644
--- a/fuchsia/engine/browser/web_engine_net_log_observer.cc
+++ b/fuchsia/engine/browser/web_engine_net_log_observer.cc
@@ -18,21 +18,17 @@
 
 namespace {
 
-std::unique_ptr<base::DictionaryValue> GetWebEngineConstants() {
-  std::unique_ptr<base::DictionaryValue> constants_dict =
-      base::DictionaryValue::From(
-          base::Value::ToUniquePtrValue(net::GetNetConstants()));
+std::unique_ptr<base::Value> GetWebEngineConstants() {
+  base::Value::Dict constants_dict = net::GetNetConstants();
 
-  base::DictionaryValue dict;
-  dict.SetKey("name", base::Value("WebEngine"));
-  dict.SetKey(
-      "command_line",
-      base::Value(
-          base::CommandLine::ForCurrentProcess()->GetCommandLineString()));
+  base::Value::Dict dict;
+  dict.Set("name", "WebEngine");
+  dict.Set("command_line",
+           base::CommandLine::ForCurrentProcess()->GetCommandLineString());
 
-  constants_dict->SetKey("clientInfo", std::move(dict));
+  constants_dict.Set("clientInfo", std::move(dict));
 
-  return constants_dict;
+  return std::make_unique<base::Value>(std::move(constants_dict));
 }
 
 }  // namespace
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h
index 7be22a33..7f4ac86 100644
--- a/headless/lib/browser/headless_browser_impl.h
+++ b/headless/lib/browser/headless_browser_impl.h
@@ -14,6 +14,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/task/single_thread_task_runner.h"
+#include "build/build_config.h"
 #include "headless/lib/browser/headless_devtools_manager_delegate.h"
 #include "headless/public/headless_devtools_target.h"
 #include "headless/public/headless_export.h"
@@ -28,6 +29,10 @@
 }  // namespace policy
 #endif
 
+#if BUILDFLAG(IS_MAC)
+#include "ui/display/screen.h"
+#endif
+
 namespace ui {
 class Compositor;
 }  // namespace ui
@@ -117,6 +122,10 @@
 #endif
 
  protected:
+#if BUILDFLAG(IS_MAC)
+  std::unique_ptr<display::ScopedNativeScreen> screen_;
+#endif
+
   base::OnceCallback<void(HeadlessBrowser*)> on_start_callback_;
   HeadlessBrowser::Options options_;
   raw_ptr<HeadlessBrowserMainParts> browser_main_parts_;  // Not owned.
diff --git a/headless/lib/browser/headless_browser_impl_mac.mm b/headless/lib/browser/headless_browser_impl_mac.mm
index 812572a..da3dee43 100644
--- a/headless/lib/browser/headless_browser_impl_mac.mm
+++ b/headless/lib/browser/headless_browser_impl_mac.mm
@@ -65,6 +65,7 @@
 }  // namespace
 
 void HeadlessBrowserImpl::PlatformInitialize() {
+  screen_ = std::make_unique<display::ScopedNativeScreen>();
   HeadlessPopUpMethods::Init();
 }
 
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index c73231c..b44025bf 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -468,7 +468,10 @@
 }
 
 void HeadlessContentMainDelegate::PostEarlyInitialization(
-    bool is_running_tests) {
+    InvokedIn invoked_in) {
+  if (invoked_in == InvokedIn::kChildProcess)
+    return;
+
   if (base::FeatureList::IsEnabled(features::kVirtualTime)) {
     // Only pass viz flags into the virtual time mode.
     const char* const switches[] = {
diff --git a/headless/lib/headless_content_main_delegate.h b/headless/lib/headless_content_main_delegate.h
index 9a26832..aac7b78 100644
--- a/headless/lib/headless_content_main_delegate.h
+++ b/headless/lib/headless_content_main_delegate.h
@@ -54,7 +54,7 @@
   content::ContentUtilityClient* CreateContentUtilityClient() override;
   content::ContentRendererClient* CreateContentRendererClient() override;
 
-  void PostEarlyInitialization(bool is_running_tests) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
 
   HeadlessBrowserImpl* browser() const { return browser_.get(); }
 
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index c54dcd3..1c3fc06e 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -29513,7 +29513,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:ios-asan"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-11"
+      dimensions: "os:Mac-12"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
@@ -29928,7 +29928,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:ios-m1-simulator-cronet"
       dimensions: "cpu:arm64"
-      dimensions: "os:Mac-11"
+      dimensions: "os:Mac-12"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
@@ -30667,7 +30667,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:ios15-beta-simulator"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-11"
+      dimensions: "os:Mac-12"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
@@ -36580,7 +36580,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:mac-arm64-on-arm64-rel-reclient"
       dimensions: "cpu:arm64"
-      dimensions: "os:Mac-11"
+      dimensions: "os:Mac-12"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/chromium/bootstrapper/${platform}"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 6f9ba85c..1491267 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1042,7 +1042,7 @@
     # same with mac-arm64-on-arm64-rel
     cores = None,  # crbug.com/1245114
     cpu = cpu.ARM64,
-    os = os.MAC_11,
+    os = os.MAC_12,
     console_view_entry = consoles.console_view_entry(
         category = "mac",
         short_name = "re",
@@ -1383,7 +1383,7 @@
         category = "cronet",
         short_name = "m1",
     ),
-    os = os.MAC_11,
+    os = os.MAC_12,
     cpu = cpu.ARM64,
     schedule = "0 1,5,9,13,17,21 * * *",
 )
@@ -1415,7 +1415,7 @@
             short_name = "ios15",
         ),
     ],
-    os = os.MAC_11,
+    os = os.MAC_12,
 )
 
 fyi_ios_builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index 14fde13..bc8d496 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -595,6 +595,6 @@
     goma_backend = goma.backend.RBE_PROD,
     sheriff_rotations = args.ignore_default(sheriff_rotations.IOS),
     cores = None,
-    os = os.MAC_11,
+    os = os.MAC_12,
     xcode = xcode.x13main,
 )
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 1e34f6d..463ebe5 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2416,6 +2416,9 @@
       <message name="IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC" desc="Detail text for the Safe Browsing check if the user has Safe Browsing Standard Protection enabled">
         Standard protection is on
       </message>
+      <message name="IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION" desc="Detail text for the Safe Browsing check if the user has Safe Browsing Standard Protection enabled">
+        Standard protection is on. For even more security, use Enhanced protection.
+      </message>
       <message name="IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_MANAGED_DESC" desc="Detail text for the Safe Browsing check if the user's Safe Browsing setting is managed by their administrator and disabled">
         Turned off by your administrator
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION.png.sha1
new file mode 100644
index 0000000..7dbd221
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION.png.sha1
@@ -0,0 +1 @@
+a9c8761216ac75ff1056afb403c62ab53bd789fd
\ No newline at end of file
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 2d80583..e69dcd5 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -265,6 +265,7 @@
     "//rlz/buildflags",
     "//services/network:network_service",
     "//ui/base",
+    "//ui/display",
   ]
 
   if (enable_rlz) {
diff --git a/ios/chrome/browser/ios_chrome_main_parts.mm b/ios/chrome/browser/ios_chrome_main_parts.mm
index 04fd297d..a2c1246 100644
--- a/ios/chrome/browser/ios_chrome_main_parts.mm
+++ b/ios/chrome/browser/ios_chrome_main_parts.mm
@@ -85,6 +85,10 @@
 #include "base/allocator/allocator_shim.h"
 #endif
 
+#if DCHECK_IS_ON()
+#include "ui/display/screen_base.h"
+#endif
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -125,7 +129,15 @@
   net::URLRequest::SetDefaultCookiePolicyToBlock();
 }
 
-IOSChromeMainParts::~IOSChromeMainParts() {}
+IOSChromeMainParts::~IOSChromeMainParts() {
+#if DCHECK_IS_ON()
+  // The screen object is never deleted on IOS. Make sure that all display
+  // observers are removed at the end.
+  display::ScreenBase* screen =
+      static_cast<display::ScreenBase*>(display::Screen::GetScreen());
+  DCHECK(!screen->HasDisplayObservers());
+#endif
+}
 
 void IOSChromeMainParts::PreEarlyInitialization() {
 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
index db34fbb..487ee651 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
@@ -426,11 +426,13 @@
       switch (self.safeBrowsingCheckRowState) {
         case SafeBrowsingCheckRowStateDefault:  // No tap action.
         case SafeBrowsingCheckRowStateRunning:  // No tap action.
-        case SafeBrowsingCheckRowStateSafe:     // No tap action.
         case SafeBrowsingCheckRowStateManaged:  // i tap: Managed state popover.
-        case SafeBrowsingCheckRowStateUnsafe:  // i tap: Show error popover with
-                                               // link to Safe Browsing toggle
-                                               // page.
+          break;
+        case SafeBrowsingCheckRowStateSafe:
+        case SafeBrowsingCheckRowStateUnsafe:  // Show Safe Browsing settings.
+          if (base::FeatureList::IsEnabled(
+                  safe_browsing::kEnhancedProtectionPhase2IOS))
+            [self.handler showSafeBrowsingPreferencePage];
           break;
       }
       break;
@@ -455,6 +457,15 @@
     case CheckStartItemType:
       return YES;
     case SafeBrowsingItemType:
+      if (base::FeatureList::IsEnabled(
+              safe_browsing::kEnhancedProtectionPhase2IOS)) {
+        return safe_browsing::GetSafeBrowsingState(*self.userPrefService) ==
+                   safe_browsing::SafeBrowsingState::STANDARD_PROTECTION ||
+               self.safeBrowsingCheckRowState ==
+                   SafeBrowsingCheckRowStateUnsafe;
+      } else {
+        return NO;
+      }
     case HeaderItem:
     case TimestampFooterItem:
       return NO;
@@ -1200,6 +1211,14 @@
       if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection)) {
         self.safeBrowsingCheckItem.detailText =
             [self safeBrowsingCheckItemDetailText];
+        if (base::FeatureList::IsEnabled(
+                safe_browsing::kEnhancedProtectionPhase2IOS)) {
+          if (safe_browsing::GetSafeBrowsingState(*self.userPrefService) ==
+              safe_browsing::SafeBrowsingState::STANDARD_PROTECTION) {
+            self.safeBrowsingCheckItem.accessoryType =
+                UITableViewCellAccessoryDisclosureIndicator;
+          }
+        }
       } else {
         self.safeBrowsingCheckItem.detailText = GetNSString(
             IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED_DESC);
@@ -1207,7 +1226,19 @@
       break;
     }
     case SafeBrowsingCheckRowStateUnsafe: {
-      self.safeBrowsingCheckItem.infoButtonHidden = NO;
+      if (base::FeatureList::IsEnabled(
+              safe_browsing::kEnhancedProtectionPhase2IOS)) {
+        UIImage* unSafeIconImage =
+            [[UIImage imageNamed:@"settings_unsafe_state"]
+                imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+        self.safeBrowsingCheckItem.trailingImage = unSafeIconImage;
+        self.safeBrowsingCheckItem.trailingImageTintColor =
+            [UIColor colorNamed:kRedColor];
+        self.safeBrowsingCheckItem.accessoryType =
+            UITableViewCellAccessoryDisclosureIndicator;
+      } else {
+        self.safeBrowsingCheckItem.infoButtonHidden = NO;
+      }
       self.safeBrowsingCheckItem.detailText = GetNSString(
           IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_DESC);
       break;
@@ -1224,6 +1255,11 @@
       safe_browsing::GetSafeBrowsingState(*self.userPrefService);
   switch (safeBrowsingState) {
     case safe_browsing::SafeBrowsingState::STANDARD_PROTECTION:
+      if (base::FeatureList::IsEnabled(
+              safe_browsing::kEnhancedProtectionPhase2IOS)) {
+        return GetNSString(
+            IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC_WITH_ENHANCED_PROTECTION);
+      }
       return GetNSString(
           IDS_IOS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_STANDARD_PROTECTION_ENABLED_DESC);
     case safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION:
diff --git a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
index f2eb3ec..350985e 100644
--- a/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
+++ b/ios/chrome/browser/ui/webui/net_export/net_export_ui.mm
@@ -99,7 +99,7 @@
 }
 
 NetExportMessageHandler::~NetExportMessageHandler() {
-  file_writer_->StopNetLog(nullptr);
+  file_writer_->StopNetLog();
 }
 
 void NetExportMessageHandler::RegisterMessages() {
@@ -162,7 +162,7 @@
 
 void NetExportMessageHandler::OnStopNetLog(const base::ListValue* list) {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  file_writer_->StopNetLog(nullptr);
+  file_writer_->StopNetLog();
 }
 
 void NetExportMessageHandler::OnSendNetLog(const base::ListValue* list) {
diff --git a/ios/testing/earl_grey/BUILD.gn b/ios/testing/earl_grey/BUILD.gn
index 1979419..c44d6498 100644
--- a/ios/testing/earl_grey/BUILD.gn
+++ b/ios/testing/earl_grey/BUILD.gn
@@ -61,5 +61,6 @@
     "//ios/third_party/edo",
     "//ios/web/common",
     "//testing/gtest:gtest",
+    "//ui/display",
   ]
 }
diff --git a/ios/testing/earl_grey/DEPS b/ios/testing/earl_grey/DEPS
new file mode 100644
index 0000000..e5069168
--- /dev/null
+++ b/ios/testing/earl_grey/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "base_earl_grey_test_case.mm": [
+    "+ui/display"
+  ]
+}
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 ecd38af..3a09405d 100644
--- a/ios/testing/earl_grey/base_earl_grey_test_case.mm
+++ b/ios/testing/earl_grey/base_earl_grey_test_case.mm
@@ -16,6 +16,10 @@
 #import "ios/testing/earl_grey/coverage_utils.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
 
+#if DCHECK_IS_ON()
+#include "ui/display/screen_base.h"
+#endif
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -79,6 +83,14 @@
 }
 
 + (void)tearDown {
+#if DCHECK_IS_ON()
+  // 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());
+#endif
   if ([[AppLaunchManager sharedManager] appIsLaunched]) {
     [CoverageUtils writeClangCoverageProfile];
     [CoverageUtils resetCoverageProfileCounters];
diff --git a/ios/web/shell/BUILD.gn b/ios/web/shell/BUILD.gn
index bdf5d2c9..a35ad69 100644
--- a/ios/web/shell/BUILD.gn
+++ b/ios/web/shell/BUILD.gn
@@ -63,6 +63,7 @@
     "//net",
     "//net:extras",
     "//ui/base",
+    "//ui/display",
   ]
 
   frameworks = [
diff --git a/ios/web/shell/shell_web_main_parts.mm b/ios/web/shell/shell_web_main_parts.mm
index 9833401f..0e9bbbf 100644
--- a/ios/web/shell/shell_web_main_parts.mm
+++ b/ios/web/shell/shell_web_main_parts.mm
@@ -6,6 +6,10 @@
 
 #include "ios/web/shell/shell_browser_state.h"
 
+#if DCHECK_IS_ON()
+#include "ui/display/screen_base.h"
+#endif
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -16,6 +20,13 @@
 }
 
 ShellWebMainParts::~ShellWebMainParts() {
+#if DCHECK_IS_ON()
+  // The screen object is never deleted on IOS. Make sure that all display
+  // observers are removed at the end.
+  display::ScreenBase* screen =
+      static_cast<display::ScreenBase*>(display::Screen::GetScreen());
+  DCHECK(!screen->HasDisplayObservers());
+#endif
 }
 
 void ShellWebMainParts::PreMainMessageLoopRun() {
diff --git a/ios/web/test/BUILD.gn b/ios/web/test/BUILD.gn
index 60324ccc8..fe065aa6 100644
--- a/ios/web/test/BUILD.gn
+++ b/ios/web/test/BUILD.gn
@@ -71,6 +71,7 @@
     "//net",
     "//third_party/ocmock",
     "//ui/base",
+    "//ui/display",
   ]
 
   sources = [
diff --git a/ios/web/test/web_int_test.mm b/ios/web/test/web_int_test.mm
index ad4cca2..896a5add 100644
--- a/ios/web/test/web_int_test.mm
+++ b/ios/web/test/web_int_test.mm
@@ -15,6 +15,10 @@
 #import "ios/web/public/test/web_view_interaction_test_util.h"
 #include "ios/web/public/web_state_observer.h"
 
+#if DCHECK_IS_ON()
+#include "ui/display/screen_base.h"
+#endif
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -81,6 +85,15 @@
                              [WKWebsiteDataStore allWebsiteDataTypes]);
 
   WebTest::TearDown();
+
+#if DCHECK_IS_ON()
+  // 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());
+#endif
 }
 
 bool WebIntTest::ExecuteBlockAndWaitForLoad(const GURL& url,
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 2fa51612..e93dd2fd 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -374,6 +374,7 @@
     "//services/network:network_service",
     "//third_party/abseil-cpp:absl",
     "//ui/base",
+    "//ui/display",
     "//url",
   ]
 
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index 3d26b42b..271ac1bb 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -69,3 +69,9 @@
   "+ui/base",
   "+ui/gfx",
 ]
+
+specific_include_rules = {
+  "web_view_web_main_parts.mm": [
+    "+ui/display"
+  ]
+}
diff --git a/ios/web_view/internal/web_view_web_main_parts.mm b/ios/web_view/internal/web_view_web_main_parts.mm
index f6a80877..534632d7 100644
--- a/ios/web_view/internal/web_view_web_main_parts.mm
+++ b/ios/web_view/internal/web_view_web_main_parts.mm
@@ -24,6 +24,10 @@
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/resource/resource_bundle.h"
 
+#if DCHECK_IS_ON()
+#include "ui/display/screen_base.h"
+#endif
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -33,7 +37,15 @@
 WebViewWebMainParts::WebViewWebMainParts()
     : field_trial_list_(/*entropy_provider=*/nullptr) {}
 
-WebViewWebMainParts::~WebViewWebMainParts() = default;
+WebViewWebMainParts::~WebViewWebMainParts() {
+#if DCHECK_IS_ON()
+  // The screen object is never deleted on IOS. Make sure that all display
+  // observers are removed at the end.
+  display::ScreenBase* screen =
+      static_cast<display::ScreenBase*>(display::Screen::GetScreen());
+  DCHECK(!screen->HasDisplayObservers());
+#endif
+}
 
 void WebViewWebMainParts::PreCreateMainMessageLoop() {
   l10n_util::OverrideLocaleWithCocoaLocale();
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index a3d1d0b..63edfa7 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -308,9 +308,7 @@
 void CameraHalDispatcherImpl::AddActiveClientObserver(
     CameraActiveClientObserver* observer) {
   base::AutoLock lock(opened_camera_id_map_lock_);
-  for (auto& opened_camera_id_pair : opened_camera_id_map_) {
-    const auto& camera_client_type = opened_camera_id_pair.first;
-    const auto& camera_id_set = opened_camera_id_pair.second;
+  for (auto& [camera_client_type, camera_id_set] : opened_camera_id_map_) {
     if (!camera_id_set.empty()) {
       observer->OnActiveClientChange(camera_client_type, /*is_active=*/true);
     }
@@ -707,9 +705,7 @@
   CAMERA_LOG(EVENT) << "Camera HAL server connection lost";
   camera_hal_server_.reset();
   camera_hal_server_callbacks_.reset();
-  for (auto& opened_camera_id_pair : opened_camera_id_map_) {
-    auto camera_client_type = opened_camera_id_pair.first;
-    const auto& camera_id_set = opened_camera_id_pair.second;
+  for (auto& [camera_client_type, camera_id_set] : opened_camera_id_map_) {
     if (!camera_id_set.empty()) {
       active_client_observers_->Notify(
           FROM_HERE, &CameraActiveClientObserver::OnActiveClientChange,
diff --git a/media/capture/video/chromeos/request_manager.cc b/media/capture/video/chromeos/request_manager.cc
index a55165b..8afdb6e0 100644
--- a/media/capture/video/chromeos/request_manager.cc
+++ b/media/capture/video/chromeos/request_manager.cc
@@ -457,10 +457,10 @@
 
   // Consume reprocess task.
   ReprocessJobInfo* reprocess_job_info;
-  for (auto& it : buffer_id_reprocess_job_info_map_) {
-    if (processing_buffer_ids_.count(it.first) == 0) {
-      *input_buffer_id = it.first;
-      reprocess_job_info = &it.second;
+  for (auto& [buffer_id, job_info] : buffer_id_reprocess_job_info_map_) {
+    if (processing_buffer_ids_.count(buffer_id) == 0) {
+      *input_buffer_id = buffer_id;
+      reprocess_job_info = &job_info;
       break;
     }
   }
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc
index d0fea45..fcbc0d1d 100644
--- a/media/capture/video/win/video_capture_device_mf_win.cc
+++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -256,9 +256,9 @@
       {MFVideoFormat_YV12, PIXEL_FORMAT_YV12},
       {GUID_ContainerFormatJpeg, PIXEL_FORMAT_MJPEG}};
 
-  for (const auto& kEntry : kPixelFormatMap) {
-    if (kEntry.mf_source_media_subtype == mf_source_media_subtype) {
-      return kEntry.pixel_format;
+  for (const auto& [source_media_subtype, pixel_format] : kPixelFormatMap) {
+    if (source_media_subtype == mf_source_media_subtype) {
+      return pixel_format;
     }
   }
   return PIXEL_FORMAT_UNKNOWN;
diff --git a/media/cast/net/cast_transport.h b/media/cast/net/cast_transport.h
index ebbd73d..9ee9e8b 100644
--- a/media/cast/net/cast_transport.h
+++ b/media/cast/net/cast_transport.h
@@ -33,10 +33,6 @@
 #include "media/cast/net/rtcp/rtcp_defines.h"
 #include "net/base/ip_endpoint.h"
 
-namespace base {
-class DictionaryValue;
-}  // namespace base
-
 namespace media {
 namespace cast {
 
@@ -159,7 +155,7 @@
   virtual void SendRtcpFromRtpReceiver() = 0;
 
   // Set options for the PacedSender and Wifi.
-  virtual void SetOptions(const base::DictionaryValue& options) = 0;
+  virtual void SetOptions(const base::Value::Dict& options) = 0;
 };
 
 }  // namespace cast
diff --git a/media/cast/net/cast_transport_impl.cc b/media/cast/net/cast_transport_impl.cc
index ef3f0686..ef2365e6 100644
--- a/media/cast/net/cast_transport_impl.cc
+++ b/media/cast/net/cast_transport_impl.cc
@@ -418,7 +418,7 @@
   valid_rtp_receiver_ssrcs_.insert(rtp_receiver_ssrc);
 }
 
-void CastTransportImpl::SetOptions(const base::DictionaryValue& options) {
+void CastTransportImpl::SetOptions(const base::Value::Dict& options) {
   // Set PacedSender options.
   int burst_size = LookupOptionWithDefault(options, kOptionPacerTargetBurstSize,
                                            media::cast::kTargetBurstSize);
@@ -431,10 +431,10 @@
 
   // Set Wifi options.
   int wifi_options = 0;
-  if (options.FindKey(kOptionWifiDisableScan)) {
+  if (options.contains(kOptionWifiDisableScan)) {
     wifi_options |= net::WIFI_OPTIONS_DISABLE_SCAN;
   }
-  if (options.FindKey(kOptionWifiMediaStreamingMode)) {
+  if (options.contains(kOptionWifiMediaStreamingMode)) {
     wifi_options |= net::WIFI_OPTIONS_MEDIA_STREAMING_MODE;
   }
   if (wifi_options)
diff --git a/media/cast/net/cast_transport_impl.h b/media/cast/net/cast_transport_impl.h
index 4be0ac3..60531d8 100644
--- a/media/cast/net/cast_transport_impl.h
+++ b/media/cast/net/cast_transport_impl.h
@@ -93,7 +93,7 @@
   //   "media_streaming_mode" (value ignored)
   //        - Turn media streaming mode on.
   // Note, these options may be ignored on some platforms.
-  void SetOptions(const base::DictionaryValue& options) final;
+  void SetOptions(const base::Value::Dict& options) final;
 
   // CastTransport implementation for receiving.
   void AddValidRtpReceiver(uint32_t rtp_sender_ssrc,
diff --git a/media/cast/net/cast_transport_impl_unittest.cc b/media/cast/net/cast_transport_impl_unittest.cc
index 85be53a1..7b02748 100644
--- a/media/cast/net/cast_transport_impl_unittest.cc
+++ b/media/cast/net/cast_transport_impl_unittest.cc
@@ -165,17 +165,17 @@
 }
 
 void CastTransportImplTest::InitWithOptions() {
-  std::unique_ptr<base::DictionaryValue> options(new base::DictionaryValue);
-  options->SetBoolean("disable_wifi_scan", true);
-  options->SetBoolean("media_streaming_mode", true);
-  options->SetInteger("pacer_target_burst_size", 20);
-  options->SetInteger("pacer_max_burst_size", 100);
+  base::Value::Dict options;
+  options.Set("disable_wifi_scan", true);
+  options.Set("media_streaming_mode", true);
+  options.Set("pacer_target_burst_size", 20);
+  options.Set("pacer_max_burst_size", 100);
   transport_ = new FakePacketSender();
   transport_sender_ = std::make_unique<CastTransportImpl>(
       &testing_clock_, base::TimeDelta(),
       std::make_unique<TransportClient>(nullptr),
       base::WrapUnique(transport_.get()), task_runner_);
-  transport_sender_->SetOptions(*options);
+  transport_sender_->SetOptions(options);
   task_runner_->RunTasks();
 }
 
diff --git a/media/cast/net/transport_util.cc b/media/cast/net/transport_util.cc
index ecba38c..0662bf3 100644
--- a/media/cast/net/transport_util.cc
+++ b/media/cast/net/transport_util.cc
@@ -8,15 +8,10 @@
 namespace cast {
 namespace transport_util {
 
-int LookupOptionWithDefault(const base::DictionaryValue& options,
+int LookupOptionWithDefault(const base::Value::Dict& options,
                             const std::string& path,
                             int default_value) {
-  int ret;
-  if (options.GetInteger(path, &ret)) {
-    return ret;
-  } else {
-    return default_value;
-  }
+  return options.FindInt(path).value_or(default_value);
 }
 
 }  // namespace transport_util
diff --git a/media/cast/net/transport_util.h b/media/cast/net/transport_util.h
index 7944386..b7859199 100644
--- a/media/cast/net/transport_util.h
+++ b/media/cast/net/transport_util.h
@@ -17,7 +17,7 @@
 const char kOptionPacerMaxBurstSize[] = "pacer_max_burst_size";
 const char kOptionPacerTargetBurstSize[] = "pacer_target_burst_size";
 
-int LookupOptionWithDefault(const base::DictionaryValue& options,
+int LookupOptionWithDefault(const base::Value::Dict& options,
                             const std::string& path,
                             int default_value);
 
diff --git a/media/cast/net/udp_transport_impl.cc b/media/cast/net/udp_transport_impl.cc
index 1a1102e..fdbe9b6 100644
--- a/media/cast/net/udp_transport_impl.cc
+++ b/media/cast/net/udp_transport_impl.cc
@@ -38,7 +38,7 @@
   return (addr.address().empty() || addr.address().IsZero()) && !addr.port();
 }
 
-int32_t GetTransportSendBufferSize(const base::DictionaryValue& options) {
+int32_t GetTransportSendBufferSize(const base::Value::Dict& options) {
   // Socket send buffer size needs to be at least greater than one burst
   // size.
   int32_t max_burst_size =
@@ -330,15 +330,15 @@
   }
 }
 
-void UdpTransportImpl::SetUdpOptions(const base::DictionaryValue& options) {
+void UdpTransportImpl::SetUdpOptions(const base::Value::Dict& options) {
   SetSendBufferSize(GetTransportSendBufferSize(options));
-  if (options.FindKey(kOptionDscp)) {
+  if (options.contains(kOptionDscp)) {
     // The default DSCP value for cast is AF41. Which gives it a higher
     // priority over other traffic.
     SetDscp(net::DSCP_AF41);
   }
 #if BUILDFLAG(IS_WIN)
-  if (!options.HasKey(kOptionDisableNonBlockingIO)) {
+  if (!options.contains(kOptionDisableNonBlockingIO)) {
     UseNonBlockingIO();
   }
 #endif
diff --git a/media/cast/net/udp_transport_impl.h b/media/cast/net/udp_transport_impl.h
index 82f8d9b..afefd29e 100644
--- a/media/cast/net/udp_transport_impl.h
+++ b/media/cast/net/udp_transport_impl.h
@@ -78,7 +78,7 @@
   //   "disable_non_blocking_io" (value ignored)
   //       - Windows only.  Turns off non-blocking IO for the socket.
   //         Note: Non-blocking IO is, by default, enabled on all platforms.
-  void SetUdpOptions(const base::DictionaryValue& options);
+  void SetUdpOptions(const base::Value::Dict& options);
 
   // This has to be called before |StartReceiving()| to change the
   // |send_buffer_size_|. Calling |SetUdpOptions()| will automatically call it.
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index 4af9b7ff..54d788b0 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -172,7 +172,7 @@
     transport_->SendRtcpFromRtpReceiver();
   }
 
-  void SetOptions(const base::DictionaryValue& options) final {}
+  void SetOptions(const base::Value::Dict& options) final {}
 
  private:
   std::unique_ptr<CastTransport> transport_;
diff --git a/media/cast/test/mock_cast_transport.h b/media/cast/test/mock_cast_transport.h
index 80164427..9f376b3 100644
--- a/media/cast/test/mock_cast_transport.h
+++ b/media/cast/test/mock_cast_transport.h
@@ -41,7 +41,7 @@
   MOCK_METHOD1(AddRtpReceiverReport,
                void(const RtcpReportBlock& rtp_report_block));
   MOCK_METHOD0(SendRtcpFromRtpReceiver, void());
-  MOCK_METHOD1(SetOptions, void(const base::DictionaryValue& options));
+  MOCK_METHOD1(SetOptions, void(const base::Value::Dict& options));
 };
 
 }  // namespace cast
diff --git a/media/device_monitors/device_monitor_udev.cc b/media/device_monitors/device_monitor_udev.cc
index e9151c2..94d9380 100644
--- a/media/device_monitors/device_monitor_udev.cc
+++ b/media/device_monitors/device_monitor_udev.cc
@@ -74,8 +74,8 @@
 void DeviceMonitorLinux::BlockingTaskRunnerHelper::Initialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::vector<device::UdevWatcher::Filter> filters;
-  for (const SubsystemMap& entry : kSubsystemMap) {
-    filters.emplace_back(entry.subsystem, entry.devtype);
+  for (const auto& [device_type, subsys, devtype] : kSubsystemMap) {
+    filters.emplace_back(subsys, devtype);
   }
   udev_watcher_ = device::UdevWatcher::StartWatching(this, filters);
 }
@@ -99,20 +99,19 @@
     device::ScopedUdevDevicePtr device) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  base::SystemMonitor::DeviceType device_type =
-      base::SystemMonitor::DEVTYPE_UNKNOWN;
+  base::SystemMonitor::DeviceType type = base::SystemMonitor::DEVTYPE_UNKNOWN;
   const std::string subsystem(device::udev_device_get_subsystem(device.get()));
-  for (const SubsystemMap& entry : kSubsystemMap) {
-    if (subsystem == entry.subsystem) {
-      device_type = entry.device_type;
+  for (const auto& [device_type, subsys, devtype] : kSubsystemMap) {
+    if (subsystem == subsys) {
+      type = device_type;
       break;
     }
   }
-  DCHECK_NE(device_type, base::SystemMonitor::DEVTYPE_UNKNOWN);
+  DCHECK_NE(type, base::SystemMonitor::DEVTYPE_UNKNOWN);
 
   // base::SystemMonitor takes care of notifying each observer in their own task
   // runner via base::ObserverListThreadSafe.
-  base::SystemMonitor::Get()->ProcessDevicesChanged(device_type);
+  base::SystemMonitor::Get()->ProcessDevicesChanged(type);
 }
 
 DeviceMonitorLinux::DeviceMonitorLinux()
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index e8040f344..a2df9fec 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -885,9 +885,9 @@
     return;
   }
   base::AutoLock auto_lock(lock_);
-  for (const auto& itr : source_state_map_) {
-    itr.second->OnMemoryPressure(currentMediaTime, memory_pressure_level,
-                                 force_instant_gc);
+  for (const auto& [source, state] : source_state_map_) {
+    state->OnMemoryPressure(currentMediaTime, memory_pressure_level,
+                            force_instant_gc);
   }
 }
 
diff --git a/media/filters/source_buffer_range.cc b/media/filters/source_buffer_range.cc
index 1412275..c11f26d 100644
--- a/media/filters/source_buffer_range.cc
+++ b/media/filters/source_buffer_range.cc
@@ -952,9 +952,9 @@
          << ", buffers.size()=" << buffers_.size()
          << ", keyframe_map_.size()=" << keyframe_map_.size()
          << ", keyframe_map_:\n";
-  for (const auto& entry : keyframe_map_) {
-    result << "\t pts " << entry.first.InMicroseconds()
-           << ", unadjusted idx = " << entry.second << "\n";
+  for (const auto& [time_delta, idx] : keyframe_map_) {
+    result << "\t pts " << time_delta.InMicroseconds()
+           << ", unadjusted idx = " << idx << "\n";
   }
 #endif  // !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
 
diff --git a/media/filters/source_buffer_state.cc b/media/filters/source_buffer_state.cc
index 9b1b37b..14b82f19 100644
--- a/media/filters/source_buffer_state.cc
+++ b/media/filters/source_buffer_state.cc
@@ -947,10 +947,9 @@
   DCHECK(timestamp_offset_during_append_);
   DCHECK(parsing_media_segment_);
 
-  for (const auto& it : buffer_queue_map) {
-    const StreamParser::BufferQueue& bufq = it.second;
-    DCHECK(!bufq.empty());
-    media_segment_has_data_for_track_[it.first] = true;
+  for (const auto& [track_id, buffer_queue] : buffer_queue_map) {
+    DCHECK(!buffer_queue.empty());
+    media_segment_has_data_for_track_[track_id] = true;
   }
 
   const base::TimeDelta timestamp_offset_before_processing =
@@ -963,12 +962,11 @@
       timestamp_offset_before_processing;
   if (generate_timestamps_flag()) {
     base::TimeDelta min_end_timestamp = kNoTimestamp;
-    for (const auto& it : buffer_queue_map) {
-      const StreamParser::BufferQueue& bufq = it.second;
-      DCHECK(!bufq.empty());
+    for (const auto& [track_id, buffer_queue] : buffer_queue_map) {
+      DCHECK(!buffer_queue.empty());
       if (min_end_timestamp == kNoTimestamp ||
-          EndTimestamp(bufq) < min_end_timestamp) {
-        min_end_timestamp = EndTimestamp(bufq);
+          EndTimestamp(buffer_queue) < min_end_timestamp) {
+        min_end_timestamp = EndTimestamp(buffer_queue);
         DCHECK_NE(kNoTimestamp, min_end_timestamp);
       }
     }
diff --git a/media/formats/mp2t/ts_section_pmt.cc b/media/formats/mp2t/ts_section_pmt.cc
index af9129f..1746bb8c 100644
--- a/media/formats/mp2t/ts_section_pmt.cc
+++ b/media/formats/mp2t/ts_section_pmt.cc
@@ -105,8 +105,10 @@
   RCHECK(bit_reader->ReadBits(32, &crc32));
 
   // Once the PMT has been proved to be correct, register the PIDs.
-  for (const auto& it : pid_map)
-    register_pes_cb_.Run(it.first, it.second.first, it.second.second);
+  for (const auto& [pid_es, stream_info] : pid_map) {
+    const auto& [stream_type, descriptors] = stream_info;
+    register_pes_cb_.Run(pid_es, stream_type, descriptors);
+  }
 
   return true;
 }
diff --git a/media/formats/webm/webm_cluster_parser_unittest.cc b/media/formats/webm/webm_cluster_parser_unittest.cc
index 13b24dbf..ab0f2eb 100644
--- a/media/formats/webm/webm_cluster_parser_unittest.cc
+++ b/media/formats/webm/webm_cluster_parser_unittest.cc
@@ -176,8 +176,8 @@
                    const BlockInfo* block_info,
                    int block_count) {
   int buffer_count = 0;
-  for (const auto& it : buffer_queue_map)
-    buffer_count += it.second.size();
+  for (const auto& [track_id, buffer_queue] : buffer_queue_map)
+    buffer_count += buffer_queue.size();
   if (block_count != buffer_count) {
     DVLOG(1) << __func__ << " : block_count (" << block_count
              << ") mismatches buffer_count (" << buffer_count << ")";
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 135352b..8a54ce2 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -1060,6 +1060,12 @@
                              base::Milliseconds(1), base::Milliseconds(100),
                              25);
 
+  // Attach the HDR metadata if the color space got this far and is still an HDR
+  // color space.  Note that it might be converted to something else along the
+  // way, often sRGB.  In that case, don't confuse things with HDR metadata.
+  if (frame->ColorSpace().IsHDR() && decoder_config_.hdr_metadata())
+    frame->set_hdr_metadata(decoder_config_.hdr_metadata());
+
   // No |frame| indicates an error creating it.
   if (!frame) {
     DLOG(ERROR) << __func__ << " |frame| is null";
diff --git a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
index e98d87752..f864c7c 100644
--- a/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
+++ b/media/gpu/v4l2/test/v4l2_ioctl_shim.cc
@@ -114,8 +114,8 @@
 }
 
 MmapedBuffer::~MmapedBuffer() {
-  for (const auto& plane : mmaped_planes_)
-    munmap(plane.start_addr, plane.length);
+  for (const auto& [start_addr, length] : mmaped_planes_)
+    munmap(start_addr, length);
 }
 
 V4L2Queue::V4L2Queue(enum v4l2_buf_type type,
diff --git a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
index 1ef8f3f..6d4e96c 100644
--- a/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.cc
@@ -564,9 +564,9 @@
     input_streamon_ = false;
   }
 
-  for (const auto& input_record : input_buffer_map_) {
+  for (const auto& [address, length, at_device] : input_buffer_map_) {
     for (size_t i = 0; i < input_buffer_num_planes_; ++i) {
-      device_->Munmap(input_record.address[i], input_record.length[i]);
+      device_->Munmap(address[i], length[i]);
     }
   }
 
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
index d6624d6..1ee2eba 100644
--- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
@@ -713,9 +713,9 @@
     input_streamon_ = false;
   }
 
-  for (const auto& input_record : input_buffer_map_) {
+  for (const auto& [address, length, at_device] : input_buffer_map_) {
     for (size_t i = 0; i < kMaxInputPlanes; ++i) {
-      device_->Munmap(input_record.address[i], input_record.length[i]);
+      device_->Munmap(address[i], length[i]);
     }
   }
 
@@ -743,9 +743,9 @@
     output_streamon_ = false;
   }
 
-  for (const auto& output_record : output_buffer_map_) {
+  for (const auto& [address, length, at_device] : output_buffer_map_) {
     for (size_t i = 0; i < output_buffer_num_planes_; ++i) {
-      device_->Munmap(output_record.address[i], output_record.length[i]);
+      device_->Munmap(address[i], length[i]);
     }
   }
 
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index e1f4879..722a4935 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -1219,8 +1219,9 @@
   if (output_buffer_map_.empty())
     return true;
 
-  for (auto& output_record : output_buffer_map_) {
-    picture_buffers_to_dismiss.push_back(output_record.picture_id);
+  for (const auto& [output_frame, picture_id, client_texture_id, texture_id,
+                    cleared, num_times_sent_to_client] : output_buffer_map_) {
+    picture_buffers_to_dismiss.push_back(picture_id);
   }
 
   if (dismiss) {
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 755090d..babf7e5f 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -1412,8 +1412,8 @@
   // Reset all our accounting info.
   while (!encoder_input_queue_.empty())
     encoder_input_queue_.pop();
-  for (auto& input_record : input_buffer_map_) {
-    input_record.frame = nullptr;
+  for (auto& [frame, ip_output_buffer_index] : input_buffer_map_) {
+    frame = nullptr;
   }
 
   bitstream_buffer_pool_.clear();
diff --git a/media/muxers/webm_muxer_unittest.cc b/media/muxers/webm_muxer_unittest.cc
index 45b8d3a..e23a386f 100644
--- a/media/muxers/webm_muxer_unittest.cc
+++ b/media/muxers/webm_muxer_unittest.cc
@@ -515,9 +515,7 @@
     return true;
   }
   bool OnNewBuffers(const media::StreamParser::BufferQueueMap& map) {
-    for (const auto& kv : map) {
-      int track_id = kv.first;
-      const media::StreamParser::BufferQueue& queue = kv.second;
+    for (const auto& [track_id, queue] : map) {
       for (const auto& stream_parser_buffer : queue) {
         buffer_timestamps_ms_[track_id].push_back(
             stream_parser_buffer->timestamp().InMilliseconds());
diff --git a/media/renderers/win/media_foundation_source_wrapper.cc b/media/renderers/win/media_foundation_source_wrapper.cc
index b1464b7..8d5d492 100644
--- a/media/renderers/win/media_foundation_source_wrapper.cc
+++ b/media/renderers/win/media_foundation_source_wrapper.cc
@@ -192,7 +192,7 @@
     }
 
     ComPtr<MediaFoundationStreamWrapper> stream = media_streams_[stream_id];
-    stream->SetFlushing(false);
+    stream->SetFlushed(false);
     if (selected) {
       MediaEventType event_type = MENewStream;
       if (stream->IsSelected()) {
@@ -556,7 +556,7 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   for (auto stream : media_streams_) {
-    stream->SetFlushing(true);
+    stream->SetFlushed(true);
   }
 }
 
diff --git a/media/renderers/win/media_foundation_stream_wrapper.cc b/media/renderers/win/media_foundation_stream_wrapper.cc
index 69ad479..2102ff8cc 100644
--- a/media/renderers/win/media_foundation_stream_wrapper.cc
+++ b/media/renderers/win/media_foundation_stream_wrapper.cc
@@ -227,17 +227,15 @@
   ProcessRequestsIfPossible();
 }
 
-void MediaFoundationStreamWrapper::SetFlushing(bool flushing) {
-  DVLOG_FUNC(2) << "flushing=" << flushing;
+void MediaFoundationStreamWrapper::SetFlushed(bool flushed) {
+  DVLOG_FUNC(2) << "flushed=" << flushed;
 
   base::AutoLock auto_lock(lock_);
-  flushing_ = flushing;
-  if (flushing_) {
-    while (!queued_buffers_.empty()) {
-      queued_buffers_.pop();
+  flushed_ = flushed;
+  if (flushed_) {
+    while (!post_flush_buffers_.empty()) {
+      post_flush_buffers_.pop();
     }
-  } else {
-    seek_awaiting_key_frame_ = true;
   }
 }
 
@@ -295,6 +293,7 @@
 
   {
     base::AutoLock auto_lock(lock_);
+
     if (state_ == State::kPaused || !enabled_)
       return;
 
@@ -304,7 +303,7 @@
   }
 
   if (ServicePostFlushSampleRequest()) {
-    // A sample has been consumed from the |queued_buffers_|.
+    // A sample has been consumed from the |post_flush_buffers_|.
     return;
   }
 
@@ -317,47 +316,16 @@
   pending_stream_read_ = true;
 }
 
-// If servicing the request fails, we'll end up re-attempting to service the
-// buffer(s) from queued_buffers_ after the demuxer read. There is an
-// assumption here that a failure to process a specific buffer from
-// queued_buffers_ is recoverable.
-HRESULT MediaFoundationStreamWrapper::ServiceSampleRequest() {
+HRESULT MediaFoundationStreamWrapper::ServiceSampleRequest(
+    IUnknown* token,
+    DecoderBuffer* buffer) {
   DVLOG_FUNC(3);
-  lock_.AssertAcquired();
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!queued_buffers_.empty());
-  DCHECK(!pending_sample_request_tokens_.empty());
-
-  DecoderBuffer* buffer = queued_buffers_.front().get();
-  IUnknown* token = pending_sample_request_tokens_.front().Get();
-
-  // Drain all non-key and non-EOS frames in a loop. Then if there are no
-  // frames left, return E_FAIL to trigger a new demuxer read; otherwise, use
-  // the new key frame to service the sample request or handle the EOS frame.
-  if (seek_awaiting_key_frame_) {
-    while (!queued_buffers_.empty()) {
-      buffer = queued_buffers_.front().get();
-
-      if (buffer->is_key_frame() || buffer->end_of_stream()) {
-        seek_awaiting_key_frame_ = false;
-        break;
-      } else {
-        queued_buffers_.pop();
-      }
-    }
-
-    if (seek_awaiting_key_frame_) {
-      DCHECK(queued_buffers_.empty());
-      return E_FAIL;
-    }
-
-    DCHECK(buffer->is_key_frame() || buffer->end_of_stream());
-  }
+  lock_.AssertAcquired();
 
   if (buffer->end_of_stream()) {
     if (!enabled_) {
       DVLOG_FUNC(2) << "Ignoring EOS for disabled stream";
-      queued_buffers_.pop();
       // token not dropped to reflect an outstanding request that stream wrapper
       // should service when the stream is enabled
       return S_OK;
@@ -365,7 +333,6 @@
     DVLOG_FUNC(2) << "End of stream";
     RETURN_IF_FAILED(mf_media_event_queue_->QueueEventParamUnk(
         MEEndOfStream, GUID_NULL, S_OK, nullptr));
-
     stream_ended_ = true;
     if (parent_source_) {
       static_cast<MediaFoundationSourceWrapper*>(parent_source_.Get())
@@ -376,10 +343,6 @@
                   << ", is_key_frame=" << buffer->is_key_frame();
     ComPtr<IMFSample> mf_sample;
     RETURN_IF_FAILED(GenerateSampleFromDecoderBuffer(buffer, &mf_sample));
-
-    // The MF pipeline should usually provide a token when requesting a sample,
-    // but the API contract doesn't guarantee it and this could change. (see
-    // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfmediastream-requestsample)
     if (token) {
       RETURN_IF_FAILED(mf_sample->SetUnknown(MFSampleExtension_Token, token));
     }
@@ -389,7 +352,6 @@
   }
 
   pending_sample_request_tokens_.pop();
-  queued_buffers_.pop();
 
   return S_OK;
 }
@@ -399,16 +361,20 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   base::AutoLock auto_lock(lock_);
-  if ((flushing_ && state_ != State::kStarted) || queued_buffers_.empty()) {
+  if ((flushed_ && state_ != State::kStarted) || post_flush_buffers_.empty()) {
     return false;
   }
 
-  HRESULT hr = ServiceSampleRequest();
+  DCHECK(!pending_sample_request_tokens_.empty());
+  ComPtr<IUnknown> request_token = pending_sample_request_tokens_.front();
+  HRESULT hr = ServiceSampleRequest(request_token.Get(),
+                                    post_flush_buffers_.front().get());
   if (FAILED(hr)) {
     DLOG(WARNING) << "Failed to service post flush sample: " << PrintHr(hr);
     return false;
   }
 
+  post_flush_buffers_.pop();
   return true;
 }
 
@@ -434,6 +400,7 @@
     DCHECK(pending_stream_read_);
     pending_stream_read_ = false;
 
+    ComPtr<IUnknown> token = pending_sample_request_tokens_.front();
     HRESULT hr = S_OK;
 
     if (status == DemuxerStream::Status::kOk) {
@@ -442,10 +409,19 @@
         ReportEncryptionType(buffer);
       }
 
-      // Push |buffer| to process later.
-      DCHECK(buffer != nullptr);
-      DVLOG_FUNC(3) << "push buffer.";
-      queued_buffers_.push(buffer);
+      // Push |buffer| to process later if needed. Otherwise, process it
+      // immediately.
+      if (flushed_ || !post_flush_buffers_.empty()) {
+        DVLOG_FUNC(3) << "push buffer.";
+        post_flush_buffers_.push(buffer);
+      } else {
+        hr = ServiceSampleRequest(token.Get(), buffer.get());
+        if (FAILED(hr)) {
+          DLOG(ERROR) << __func__
+                      << ": ServiceSampleRequest failed: " << PrintHr(hr);
+          return;
+        }
+      }
     } else if (status == DemuxerStream::Status::kConfigChanged) {
       DVLOG_FUNC(2) << "Stream config changed, AreFormatChangesEnabled="
                     << AreFormatChangesEnabled();
diff --git a/media/renderers/win/media_foundation_stream_wrapper.h b/media/renderers/win/media_foundation_stream_wrapper.h
index 3b855c04..22cf6c3 100644
--- a/media/renderers/win/media_foundation_stream_wrapper.h
+++ b/media/renderers/win/media_foundation_stream_wrapper.h
@@ -70,7 +70,7 @@
   bool IsSelected();
   bool IsEnabled();
   void SetEnabled(bool enabled);
-  void SetFlushing(bool flushing);
+  void SetFlushed(bool flushed);
 
   // TODO: revisting inheritance and potentially replacing it with composition.
 
@@ -116,7 +116,8 @@
   HRESULT GenerateStreamDescriptor();
   HRESULT GenerateSampleFromDecoderBuffer(DecoderBuffer* buffer,
                                           IMFSample** sample_out);
-  HRESULT ServiceSampleRequest() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  HRESULT ServiceSampleRequest(IUnknown* token, DecoderBuffer* buffer)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
   // Returns true when a sample request has been serviced.
   bool ServicePostFlushSampleRequest();
   virtual HRESULT GetMediaType(IMFMediaType** media_type_out) = 0;
@@ -147,13 +148,9 @@
 
   // Indicates whether the Chromium pipeline has flushed the renderer
   // (prior to a seek).
-  // Since SetFlushing() can be invoked by media stack thread or MF threadpool
-  // thread, |flushing_| and |queued_buffers_| are protected by lock.
-  bool flushing_ GUARDED_BY(lock_) = false;
-
-  // Indicates whether the stream has just performed a seek and is
-  // awaiting a KeyFrame before rendering further.
-  bool seek_awaiting_key_frame_ GUARDED_BY(lock_) = false;
+  // Since SetFlushed() can be invoked by media stack thread or MF threadpool
+  // thread, |flushed_| and |post_flush_buffers_| are protected by lock.
+  bool flushed_ GUARDED_BY(lock_) = false;
 
   int stream_id_;
 
@@ -174,8 +171,10 @@
   bool stream_ended_ = false;
   GUID last_key_id_ = GUID_NULL;
 
-  // Save media::DecoderBuffer from OnDemuxerStreamRead call.
-  std::queue<scoped_refptr<DecoderBuffer>> queued_buffers_ GUARDED_BY(lock_);
+  // Save media::DecoderBuffer from OnDemuxerStreamRead call when we are in
+  // progress of a flush operation.
+  std::queue<scoped_refptr<DecoderBuffer>> post_flush_buffers_
+      GUARDED_BY(lock_);
 
   bool encryption_type_reported_ = false;
 
diff --git a/net/log/file_net_log_observer.cc b/net/log/file_net_log_observer.cc
index 05bf79f6..bde6ccc 100644
--- a/net/log/file_net_log_observer.cc
+++ b/net/log/file_net_log_observer.cc
@@ -491,7 +491,7 @@
       file_writer_(std::move(file_writer)),
       capture_mode_(capture_mode) {
   if (!constants)
-    constants = base::Value::ToUniquePtrValue(GetNetConstants());
+    constants = std::make_unique<base::Value>(GetNetConstants());
 
   DCHECK(constants->is_dict());
   DCHECK(!constants->GetDict().Find("logCaptureMode"));
diff --git a/net/log/net_log_util.cc b/net/log/net_log_util.cc
index 38d1e00..92309fe0 100644
--- a/net/log/net_log_util.cc
+++ b/net/log/net_log_util.cc
@@ -133,7 +133,7 @@
 
 }  // namespace
 
-base::Value GetNetConstants() {
+base::Value::Dict GetNetConstants() {
   base::Value::Dict constants_dict;
 
   // Version of the file format.
@@ -345,16 +345,15 @@
   // Additional trials may be enabled later in the browser session.
   constants_dict.Set(kNetInfoFieldTrials, GetActiveFieldTrialList());
 
-  return base::Value(std::move(constants_dict));
+  return constants_dict;
 }
 
-NET_EXPORT base::Value GetNetInfo(URLRequestContext* context) {
+NET_EXPORT base::Value::Dict GetNetInfo(URLRequestContext* context) {
   // May only be called on the context's thread.
   context->AssertCalledOnValidThread();
 
-  base::Value net_info =
+  base::Value::Dict net_info_dict =
       context->proxy_resolution_service()->GetProxyNetLogValues();
-  base::Value::Dict& net_info_dict = net_info.GetDict();
 
   // Log Host Resolver info.
   {
@@ -507,7 +506,7 @@
   // the start of this browser session (crbug.com/1133396).
   net_info_dict.Set(kNetInfoFieldTrials, GetActiveFieldTrialList());
 
-  return base::Value(std::move(net_info_dict));
+  return net_info_dict;
 }
 
 NET_EXPORT void CreateNetLogEntriesForActiveObjects(
diff --git a/net/log/net_log_util.h b/net/log/net_log_util.h
index 569be89..de000357 100644
--- a/net/log/net_log_util.h
+++ b/net/log/net_log_util.h
@@ -18,13 +18,13 @@
 // Utility methods for creating NetLog dumps.
 
 // Creates a dictionary containing a legend for net/ constants.
-NET_EXPORT base::Value GetNetConstants();
+NET_EXPORT base::Value::Dict GetNetConstants();
 
 // Retrieves a dictionary containing information about the current state of
 // |context|.
 //
 // May only be called on |context|'s thread.
-NET_EXPORT base::Value GetNetInfo(URLRequestContext* context);
+NET_EXPORT base::Value::Dict GetNetInfo(URLRequestContext* context);
 
 // Takes in a set of contexts and a NetLog::Observer, and passes in
 // NetLog::Entries to the observer for certain NetLogSources with pending
diff --git a/net/log/net_log_util_unittest.cc b/net/log/net_log_util_unittest.cc
index 6975389..9b3a0c8 100644
--- a/net/log/net_log_util_unittest.cc
+++ b/net/log/net_log_util_unittest.cc
@@ -50,20 +50,19 @@
 
   // Get NetInfo when there's no cache backend (It's only created on first use).
   EXPECT_FALSE(http_cache->GetCurrentBackend());
-  base::Value net_info_without_cache(GetNetInfo(context.get()));
+  base::Value::Dict net_info_without_cache(GetNetInfo(context.get()));
   EXPECT_FALSE(http_cache->GetCurrentBackend());
-  EXPECT_GT(net_info_without_cache.GetDict().size(), 0u);
+  EXPECT_GT(net_info_without_cache.size(), 0u);
 
   // Force creation of a cache backend, and get NetInfo again.
   disk_cache::Backend* backend = nullptr;
   EXPECT_EQ(OK, context->http_transaction_factory()->GetCache()->GetBackend(
                     &backend, TestCompletionCallback().callback()));
   EXPECT_TRUE(http_cache->GetCurrentBackend());
-  base::Value net_info_with_cache = GetNetInfo(context.get());
-  EXPECT_GT(net_info_with_cache.GetDict().size(), 0u);
+  base::Value::Dict net_info_with_cache = GetNetInfo(context.get());
+  EXPECT_GT(net_info_with_cache.size(), 0u);
 
-  EXPECT_EQ(net_info_without_cache.GetDict().size(),
-            net_info_with_cache.GetDict().size());
+  EXPECT_EQ(net_info_without_cache.size(), net_info_with_cache.size());
 }
 
 // Verify that active Field Trials are reflected.
diff --git a/net/proxy_resolution/configured_proxy_resolution_service.cc b/net/proxy_resolution/configured_proxy_resolution_service.cc
index 2c02537..04d8766 100644
--- a/net/proxy_resolution/configured_proxy_resolution_service.cc
+++ b/net/proxy_resolution/configured_proxy_resolution_service.cc
@@ -1363,18 +1363,18 @@
   ApplyProxyConfigIfAvailable();
 }
 
-base::Value ConfiguredProxyResolutionService::GetProxyNetLogValues() {
-  base::Value net_info_dict(base::Value::Type::DICTIONARY);
+base::Value::Dict ConfiguredProxyResolutionService::GetProxyNetLogValues() {
+  base::Value::Dict net_info_dict;
 
   // Log Proxy Settings.
   {
-    base::Value dict(base::Value::Type::DICTIONARY);
+    base::Value::Dict dict;
     if (fetched_config_)
-      dict.SetKey("original", fetched_config_->value().ToValue());
+      dict.Set("original", fetched_config_->value().ToValue());
     if (config_)
-      dict.SetKey("effective", config_->value().ToValue());
+      dict.Set("effective", config_->value().ToValue());
 
-    net_info_dict.SetKey(kNetInfoProxySettings, std::move(dict));
+    net_info_dict.Set(kNetInfoProxySettings, std::move(dict));
   }
 
   // Log Bad Proxies.
@@ -1393,7 +1393,7 @@
       list.Append(std::move(dict));
     }
 
-    net_info_dict.SetKey(kNetInfoBadProxies, std::move(list));
+    net_info_dict.Set(kNetInfoBadProxies, std::move(list));
   }
 
   return net_info_dict;
diff --git a/net/proxy_resolution/configured_proxy_resolution_service.h b/net/proxy_resolution/configured_proxy_resolution_service.h
index 80b9626..054b75d 100644
--- a/net/proxy_resolution/configured_proxy_resolution_service.h
+++ b/net/proxy_resolution/configured_proxy_resolution_service.h
@@ -176,7 +176,7 @@
   void ForceReloadProxyConfig();
 
   // ProxyResolutionService
-  base::Value GetProxyNetLogValues() override;
+  base::Value::Dict GetProxyNetLogValues() override;
 
   // ProxyResolutionService
   [[nodiscard]] bool CastToConfiguredProxyResolutionService(
diff --git a/net/proxy_resolution/proxy_resolution_service.h b/net/proxy_resolution/proxy_resolution_service.h
index c914455..6f9147b 100644
--- a/net/proxy_resolution/proxy_resolution_service.h
+++ b/net/proxy_resolution/proxy_resolution_service.h
@@ -93,7 +93,7 @@
 
   // Returns proxy related debug information to be included in the NetLog. The
   // data should be appropriate for any capture mode (sensitivity level).
-  virtual base::Value GetProxyNetLogValues() = 0;
+  virtual base::Value::Dict GetProxyNetLogValues() = 0;
 
   // Returns true if |this| is an instance of ConfiguredProxyResolutionService
   // and assigns |this| to the out parameter. Otherwise returns false and sets
diff --git a/net/proxy_resolution/win/windows_system_proxy_resolution_service.cc b/net/proxy_resolution/win/windows_system_proxy_resolution_service.cc
index 514610a..f29b9ad 100644
--- a/net/proxy_resolution/win/windows_system_proxy_resolution_service.cc
+++ b/net/proxy_resolution/win/windows_system_proxy_resolution_service.cc
@@ -131,10 +131,9 @@
   return proxy_retry_info_;
 }
 
-base::Value WindowsSystemProxyResolutionService::GetProxyNetLogValues() {
+base::Value::Dict WindowsSystemProxyResolutionService::GetProxyNetLogValues() {
   // TODO (https://crbug.com/1032820): Implement net logs.
-  base::Value net_info_dict(base::Value::Type::DICTIONARY);
-  return net_info_dict;
+  return base::Value::Dict();
 }
 
 bool WindowsSystemProxyResolutionService::
diff --git a/net/proxy_resolution/win/windows_system_proxy_resolution_service.h b/net/proxy_resolution/win/windows_system_proxy_resolution_service.h
index 3d10b12..8c2331e 100644
--- a/net/proxy_resolution/win/windows_system_proxy_resolution_service.h
+++ b/net/proxy_resolution/win/windows_system_proxy_resolution_service.h
@@ -63,7 +63,7 @@
       const NetLogWithSource& net_log) override;
   void ClearBadProxiesCache() override;
   const ProxyRetryInfoMap& proxy_retry_info() const override;
-  base::Value GetProxyNetLogValues() override;
+  base::Value::Dict GetProxyNetLogValues() override;
   [[nodiscard]] bool CastToConfiguredProxyResolutionService(
       ConfiguredProxyResolutionService** configured_proxy_resolution_service)
       override;
diff --git a/remoting/ios/DEPS b/remoting/ios/DEPS
index 3b6691ff..1ef6988 100644
--- a/remoting/ios/DEPS
+++ b/remoting/ios/DEPS
@@ -15,4 +15,5 @@
   "+third_party/ocmock",
   "+third_party/protobuf/src",
   "+services/network/public/cpp",
+  "+ui/display",
 ]
diff --git a/remoting/ios/facade/BUILD.gn b/remoting/ios/facade/BUILD.gn
index 9ae2b2b..1ed965e 100644
--- a/remoting/ios/facade/BUILD.gn
+++ b/remoting/ios/facade/BUILD.gn
@@ -56,6 +56,7 @@
     "//testing/gtest",
     "//third_party/ocmock",
     "//ui/base",
+    "//ui/display",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/remoting/ios/facade/host_list_service_unittest.mm b/remoting/ios/facade/host_list_service_unittest.mm
index d8304324..e0412c93 100644
--- a/remoting/ios/facade/host_list_service_unittest.mm
+++ b/remoting/ios/facade/host_list_service_unittest.mm
@@ -29,6 +29,7 @@
 #include "testing/platform_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/display/screen.h"
 
 #define EXPECT_HOST_LIST_STATE(expected) \
   EXPECT_EQ(expected, host_list_service_.state())
@@ -83,6 +84,7 @@
  private:
   base::CallbackListSubscription host_list_state_subscription_;
   base::CallbackListSubscription fetch_failure_subscription_;
+  display::ScopedNativeScreen screen_;
 };
 
 HostListServiceTest::HostListServiceTest()
diff --git a/services/network/net_log_exporter.cc b/services/network/net_log_exporter.cc
index 97f46fb..de66d4e 100644
--- a/services/network/net_log_exporter.cc
+++ b/services/network/net_log_exporter.cc
@@ -39,7 +39,7 @@
 }
 
 void NetLogExporter::Start(base::File destination,
-                           base::Value extra_constants,
+                           base::Value::Dict extra_constants,
                            net::NetLogCaptureMode capture_mode,
                            uint64_t max_file_size,
                            StartCallback callback) {
@@ -77,25 +77,21 @@
   }
 }
 
-void NetLogExporter::Stop(base::Value polled_data_value,
+void NetLogExporter::Stop(base::Value::Dict polled_data,
                           StopCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  base::DictionaryValue* polled_data = nullptr;
-  bool ok = polled_data_value.GetAsDictionary(&polled_data);
-  DCHECK(ok);  // mojo is supposed to enforce that.
 
   if (state_ != STATE_RUNNING) {
     std::move(callback).Run(net::ERR_UNEXPECTED);
     return;
   }
 
-  base::Value net_info =
+  base::Value::Dict net_info =
       net::GetNetInfo(network_context_->url_request_context());
-  if (polled_data)
-    net_info.MergeDictionary(polled_data);
+  net_info.Merge(polled_data);
 
   file_net_observer_->StopObserving(
-      base::Value::ToUniquePtrValue(std::move(net_info)),
+      std::make_unique<base::Value>(std::move(net_info)),
       base::BindOnce([](StopCallback sc) { std::move(sc).Run(net::OK); },
                      std::move(callback)));
   file_net_observer_ = nullptr;
@@ -133,7 +129,7 @@
 
 void NetLogExporter::StartWithScratchDirOrCleanup(
     base::WeakPtr<NetLogExporter> object,
-    base::Value extra_constants,
+    base::Value::Dict extra_constants,
     net::NetLogCaptureMode capture_mode,
     uint64_t max_file_size,
     StartCallback callback,
@@ -156,15 +152,12 @@
 }
 
 void NetLogExporter::StartWithScratchDir(
-    base::Value extra_constants_value,
+    base::Value::Dict extra_constants,
     net::NetLogCaptureMode capture_mode,
     uint64_t max_file_size,
     StartCallback callback,
     const base::FilePath& scratch_dir_path) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  base::DictionaryValue* extra_constants = nullptr;
-  bool ok = extra_constants_value.GetAsDictionary(&extra_constants);
-  DCHECK(ok);  // mojo is supposed to enforce that before Start() is invoked.
 
   if (scratch_dir_path.empty() && max_file_size != kUnlimitedFileSize) {
     state_ = STATE_IDLE;
@@ -175,21 +168,19 @@
 
   state_ = STATE_RUNNING;
 
-  std::unique_ptr<base::DictionaryValue> constants =
-      base::DictionaryValue::From(
-          base::Value::ToUniquePtrValue(net::GetNetConstants()));
-
-  if (extra_constants)
-    constants->MergeDictionary(extra_constants);
+  base::Value::Dict constants = net::GetNetConstants();
+  constants.Merge(extra_constants);
+  std::unique_ptr<base::Value> constants_value =
+      std::make_unique<base::Value>(std::move(constants));
 
   if (max_file_size != kUnlimitedFileSize) {
     file_net_observer_ = net::FileNetLogObserver::CreateBoundedPreExisting(
         scratch_dir_path, std::move(destination_), max_file_size, capture_mode,
-        std::move(constants));
+        std::move(constants_value));
   } else {
     DCHECK(scratch_dir_path.empty());
     file_net_observer_ = net::FileNetLogObserver::CreateUnboundedPreExisting(
-        std::move(destination_), capture_mode, std::move(constants));
+        std::move(destination_), capture_mode, std::move(constants_value));
   }
 
   // There might not be a NetworkService object e.g. on iOS; in that case
diff --git a/services/network/net_log_exporter.h b/services/network/net_log_exporter.h
index 084047a..3b5a64b 100644
--- a/services/network/net_log_exporter.h
+++ b/services/network/net_log_exporter.h
@@ -38,11 +38,11 @@
   ~NetLogExporter() override;
 
   void Start(base::File destination,
-             base::Value extra_constants,
+             base::Value::Dict extra_constants,
              net::NetLogCaptureMode capture_mode,
              uint64_t max_file_size,
              StartCallback callback) override;
-  void Stop(base::Value polled_data, StopCallback callback) override;
+  void Stop(base::Value::Dict polled_data, StopCallback callback) override;
 
   // Sets a callback that will be used to create a scratch directory instead
   // of the normal codepath. For test use only.
@@ -59,13 +59,13 @@
 
   static void StartWithScratchDirOrCleanup(
       base::WeakPtr<NetLogExporter> object,
-      base::Value extra_constants,
+      base::Value::Dict extra_constants,
       net::NetLogCaptureMode capture_mode,
       uint64_t max_file_size,
       StartCallback callback,
       const base::FilePath& scratch_dir_path);
 
-  void StartWithScratchDir(base::Value extra_constants,
+  void StartWithScratchDir(base::Value::Dict extra_constants,
                            net::NetLogCaptureMode capture_mode,
                            uint64_t max_file_size,
                            StartCallback callback,
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 29f18b24..9fca09b 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -3168,10 +3168,10 @@
                       base::File::FLAG_CREATE | base::File::FLAG_WRITE);
   ASSERT_TRUE(out_file.IsValid());
 
-  base::Value dict_start(base::Value::Type::DICTIONARY);
+  base::Value::Dict dict_start;
   const char kKeyEarly[] = "early";
   const char kValEarly[] = "morning";
-  dict_start.SetKey(kKeyEarly, base::Value(kValEarly));
+  dict_start.Set(kKeyEarly, kValEarly);
 
   net::TestCompletionCallback start_callback;
   net_log_exporter->Start(std::move(out_file), std::move(dict_start),
@@ -3179,10 +3179,10 @@
                           start_callback.callback());
   EXPECT_EQ(net::OK, start_callback.WaitForResult());
 
-  base::Value dict_late(base::Value::Type::DICTIONARY);
+  base::Value::Dict dict_late;
   const char kKeyLate[] = "late";
   const char kValLate[] = "snowval";
-  dict_late.SetKey(kKeyLate, base::Value(kValLate));
+  dict_late.Set(kKeyLate, kValLate);
 
   net::TestCompletionCallback stop_callback;
   net_log_exporter->Stop(std::move(dict_late), stop_callback.callback());
@@ -3219,15 +3219,14 @@
   ASSERT_TRUE(out_file.IsValid());
 
   net::TestCompletionCallback start_callback;
-  net_log_exporter->Start(
-      std::move(out_file), base::Value(base::Value::Type::DICTIONARY),
-      net::NetLogCaptureMode::kDefault,
-      mojom::NetLogExporter::kUnlimitedFileSize, start_callback.callback());
+  net_log_exporter->Start(std::move(out_file), base::Value::Dict(),
+                          net::NetLogCaptureMode::kDefault,
+                          mojom::NetLogExporter::kUnlimitedFileSize,
+                          start_callback.callback());
   EXPECT_EQ(net::OK, start_callback.WaitForResult());
 
   net::TestCompletionCallback stop_callback;
-  net_log_exporter->Stop(base::Value(base::Value::Type::DICTIONARY),
-                         stop_callback.callback());
+  net_log_exporter->Stop(base::Value::Dict(), stop_callback.callback());
   EXPECT_EQ(net::OK, stop_callback.WaitForResult());
 
   // Check that file got written.
@@ -3251,8 +3250,7 @@
       net_log_exporter.BindNewPipeAndPassReceiver());
 
   net::TestCompletionCallback stop_callback;
-  net_log_exporter->Stop(base::Value(base::Value::Type::DICTIONARY),
-                         stop_callback.callback());
+  net_log_exporter->Stop(base::Value::Dict(), stop_callback.callback());
   EXPECT_EQ(net::ERR_UNEXPECTED, stop_callback.WaitForResult());
 
   base::FilePath temp_path;
@@ -3262,9 +3260,9 @@
   ASSERT_TRUE(temp_file.IsValid());
 
   net::TestCompletionCallback start_callback;
-  net_log_exporter->Start(
-      std::move(temp_file), base::Value(base::Value::Type::DICTIONARY),
-      net::NetLogCaptureMode::kDefault, 100 * 1024, start_callback.callback());
+  net_log_exporter->Start(std::move(temp_file), base::Value::Dict(),
+                          net::NetLogCaptureMode::kDefault, 100 * 1024,
+                          start_callback.callback());
   EXPECT_EQ(net::OK, start_callback.WaitForResult());
 
   // Can't start twice.
@@ -3275,9 +3273,9 @@
   ASSERT_TRUE(temp_file2.IsValid());
 
   net::TestCompletionCallback start_callback2;
-  net_log_exporter->Start(
-      std::move(temp_file2), base::Value(base::Value::Type::DICTIONARY),
-      net::NetLogCaptureMode::kDefault, 100 * 1024, start_callback2.callback());
+  net_log_exporter->Start(std::move(temp_file2), base::Value::Dict(),
+                          net::NetLogCaptureMode::kDefault, 100 * 1024,
+                          start_callback2.callback());
   EXPECT_EQ(net::ERR_UNEXPECTED, start_callback2.WaitForResult());
 
   base::DeleteFile(temp_path);
@@ -3319,9 +3317,9 @@
                        base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
   ASSERT_TRUE(temp_file.IsValid());
 
-  net_log_exporter->Start(
-      std::move(temp_file), base::Value(base::Value::Type::DICTIONARY),
-      net::NetLogCaptureMode::kDefault, 100, base::BindOnce([](int) {}));
+  net_log_exporter->Start(std::move(temp_file), base::Value::Dict(),
+                          net::NetLogCaptureMode::kDefault, 100,
+                          base::BindOnce([](int) {}));
   net_log_exporter = nullptr;
   block_mktemp.Signal();
 
@@ -5078,11 +5076,11 @@
       start_param = result;
       run_loop.Quit();
     });
-    net_log_exporter->Start(
-        std::move(net_log_file),
-        /*extra_constants=*/base::Value(base::Value::Type::DICTIONARY),
-        net::NetLogCaptureMode::kDefault,
-        network::mojom::NetLogExporter::kUnlimitedFileSize, start_callback);
+    net_log_exporter->Start(std::move(net_log_file),
+                            /*extra_constants=*/base::Value::Dict(),
+                            net::NetLogCaptureMode::kDefault,
+                            network::mojom::NetLogExporter::kUnlimitedFileSize,
+                            start_callback);
     run_loop.Run();
     EXPECT_EQ(net::OK, start_param);
   }
@@ -5101,8 +5099,7 @@
       run_loop.Quit();
     });
     net_log_exporter->Stop(
-        /*polled_data=*/base::Value(base::Value::Type::DICTIONARY),
-        stop_callback);
+        /*polled_data=*/base::Value::Dict(), stop_callback);
     run_loop.Run();
     EXPECT_EQ(net::OK, stop_param);
   }
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 9ee7946..0516443 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -491,15 +491,13 @@
 
 void NetworkService::StartNetLog(base::File file,
                                  net::NetLogCaptureMode capture_mode,
-                                 base::Value client_constants) {
-  DCHECK(client_constants.is_dict());
-  std::unique_ptr<base::DictionaryValue> constants =
-      base::DictionaryValue::From(
-          base::Value::ToUniquePtrValue(net::GetNetConstants()));
-  constants->MergeDictionary(&client_constants);
+                                 base::Value::Dict client_constants) {
+  base::Value::Dict constants = net::GetNetConstants();
+  constants.Merge(client_constants);
 
   file_net_log_observer_ = net::FileNetLogObserver::CreateUnboundedPreExisting(
-      std::move(file), capture_mode, std::move(constants));
+      std::move(file), capture_mode,
+      std::make_unique<base::Value>(std::move(constants)));
   file_net_log_observer_->StartObserving(net_log_);
 }
 
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 6683c76..2a903fd 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -142,7 +142,7 @@
 #endif
   void StartNetLog(base::File file,
                    net::NetLogCaptureMode capture_mode,
-                   base::Value constants) override;
+                   base::Value::Dict constants) override;
   void AttachNetLogProxy(
       mojo::PendingRemote<mojom::NetLogProxySource> proxy_source,
       mojo::PendingReceiver<mojom::NetLogProxySink>) override;
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index 3acb252..e62b9e25 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -1081,8 +1081,8 @@
   base::FilePath log_dir = temp_dir.GetPath();
   base::FilePath log_path = log_dir.Append(FILE_PATH_LITERAL("test_log.json"));
 
-  base::DictionaryValue dict;
-  dict.SetString("amiatest", "iamatest");
+  base::Value::Dict dict;
+  dict.Set("amiatest", "iamatest");
 
   base::File log_file(log_path,
                       base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
@@ -1102,7 +1102,8 @@
   std::unique_ptr<base::Value> log_dict =
       deserializer.Deserialize(nullptr, nullptr);
   ASSERT_TRUE(log_dict);
-  ASSERT_EQ(log_dict->FindKey("constants")->FindKey("amiatest")->GetString(),
+  ASSERT_TRUE(log_dict->is_dict());
+  ASSERT_EQ(*log_dict->GetDict().FindStringByDottedPath("constants.amiatest"),
             "iamatest");
 }
 
diff --git a/services/network/public/cpp/client_hints.cc b/services/network/public/cpp/client_hints.cc
index da24d493..0583ee8cd 100644
--- a/services/network/public/cpp/client_hints.cc
+++ b/services/network/public/cpp/client_hints.cc
@@ -67,7 +67,7 @@
 
 namespace {
 
-struct ClientHintNameCompator {
+struct ClientHintNameComparator {
   bool operator()(const std::string& lhs, const std::string& rhs) const {
     return base::CompareCaseInsensitiveASCII(lhs, rhs) < 0;
   }
@@ -75,7 +75,7 @@
 
 using DecodeMap = base::flat_map<std::string,
                                  network::mojom::WebClientHintsType,
-                                 ClientHintNameCompator>;
+                                 ClientHintNameComparator>;
 
 DecodeMap MakeDecodeMap() {
   DecodeMap result;
diff --git a/services/network/public/mojom/net_log.mojom b/services/network/public/mojom/net_log.mojom
index aa668db..08492c9d 100644
--- a/services/network/public/mojom/net_log.mojom
+++ b/services/network/public/mojom/net_log.mojom
@@ -40,7 +40,7 @@
   // Returns network error code.
   Start(
     mojo_base.mojom.File destination,
-    mojo_base.mojom.DeprecatedDictionaryValue extra_constants,
+    mojo_base.mojom.DictionaryValue extra_constants,
     NetLogCaptureMode capture_mode,
     uint64 max_file_size) => (int32 net_error);
 
@@ -50,7 +50,7 @@
   //
   // Returns network error code; if successful this will occur only after
   // the file has been fully written.
-  Stop(mojo_base.mojom.DeprecatedDictionaryValue polled_values)
+  Stop(mojo_base.mojom.DictionaryValue polled_values)
       => (int32 net_error);
 };
 
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index f947e9b..0ca0994 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -186,7 +186,7 @@
   // the key "clientInfo".
   StartNetLog(mojo_base.mojom.File file,
               NetLogCaptureMode capture_mode,
-              mojo_base.mojom.DeprecatedDictionaryValue constants);
+              mojo_base.mojom.DictionaryValue constants);
 
   // Attaches an external source of NetLog events. Control events will be sent
   // to the |proxy_source| pipe indicating when netlogging is active, the
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9c66fad..c66efa71 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -32246,7 +32246,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32258,7 +32258,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "absl_hardening_tests iPhone 6s 14.4",
+        "name": "absl_hardening_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32284,14 +32284,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -32350,7 +32350,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32362,7 +32362,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPad Air 2 14.4",
+        "name": "base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32388,14 +32388,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -32454,7 +32454,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32466,7 +32466,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s 14.4",
+        "name": "base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32492,14 +32492,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -32558,7 +32558,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32570,7 +32570,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s Plus 14.4",
+        "name": "base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32596,14 +32596,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -32662,7 +32662,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32674,7 +32674,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone SE (1st generation) 14.4",
+        "name": "base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32700,14 +32700,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -32766,7 +32766,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32778,7 +32778,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_crypto_tests iPhone 6s 14.4",
+        "name": "boringssl_crypto_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32804,14 +32804,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -32870,7 +32870,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32882,7 +32882,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_ssl_tests iPhone 6s 14.4",
+        "name": "boringssl_ssl_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -32908,14 +32908,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -32974,7 +32974,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -32986,7 +32986,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPad Air 2 14.4",
+        "name": "components_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33012,14 +33012,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -33078,7 +33078,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33090,7 +33090,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s 14.4",
+        "name": "components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33116,14 +33116,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -33182,7 +33182,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33194,7 +33194,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s Plus 14.4",
+        "name": "components_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33220,14 +33220,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -33286,7 +33286,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33298,7 +33298,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone SE (1st generation) 14.4",
+        "name": "components_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33324,14 +33324,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -33390,7 +33390,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33402,7 +33402,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "crypto_unittests iPhone 6s 14.4",
+        "name": "crypto_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33428,14 +33428,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://crypto:crypto_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -33494,7 +33494,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33506,7 +33506,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPad Air 2 14.4",
+        "name": "gfx_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33532,14 +33532,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -33598,7 +33598,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33610,7 +33610,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s 14.4",
+        "name": "gfx_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33636,14 +33636,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -33702,7 +33702,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33714,7 +33714,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s Plus 14.4",
+        "name": "gfx_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33740,14 +33740,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -33806,7 +33806,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33818,7 +33818,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone SE (1st generation) 14.4",
+        "name": "gfx_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33844,14 +33844,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -33910,7 +33910,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -33922,7 +33922,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "google_apis_unittests iPhone 6s 14.4",
+        "name": "google_apis_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -33948,14 +33948,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://google_apis:google_apis_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -34014,7 +34014,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34027,7 +34027,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34053,14 +34053,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -34120,7 +34120,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34133,7 +34133,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34159,14 +34159,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -34226,7 +34226,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34239,7 +34239,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34265,14 +34265,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -34332,7 +34332,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34345,7 +34345,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34371,15 +34371,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -34440,7 +34440,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34453,7 +34453,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34479,15 +34479,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -34548,7 +34548,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34561,7 +34561,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34587,15 +34587,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -34656,7 +34656,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34669,7 +34669,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34695,15 +34695,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -34764,7 +34764,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34777,7 +34777,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34803,15 +34803,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -34872,7 +34872,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34885,7 +34885,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -34911,15 +34911,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -34980,7 +34980,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -34993,7 +34993,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35019,15 +35019,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -35088,7 +35088,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35101,7 +35101,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35127,15 +35127,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -35196,7 +35196,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35209,7 +35209,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35235,15 +35235,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -35304,7 +35304,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35317,7 +35317,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35343,14 +35343,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -35410,7 +35410,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35423,7 +35423,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35449,14 +35449,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -35516,7 +35516,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35529,7 +35529,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35555,14 +35555,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -35622,7 +35622,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35635,7 +35635,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35661,15 +35661,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -35730,7 +35730,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35743,7 +35743,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35769,15 +35769,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -35838,7 +35838,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35851,7 +35851,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35877,15 +35877,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -35946,7 +35946,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -35958,7 +35958,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPad Air 2 14.4",
+        "name": "ios_chrome_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -35984,14 +35984,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -36050,7 +36050,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36062,7 +36062,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s 14.4",
+        "name": "ios_chrome_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36088,14 +36088,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -36154,7 +36154,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36166,7 +36166,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s Plus 14.4",
+        "name": "ios_chrome_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36192,14 +36192,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -36258,7 +36258,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36270,7 +36270,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36296,14 +36296,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -36362,7 +36362,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36375,7 +36375,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36401,14 +36401,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -36468,7 +36468,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36481,7 +36481,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36507,14 +36507,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -36574,7 +36574,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36587,7 +36587,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36613,14 +36613,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -36680,7 +36680,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36692,7 +36692,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_components_unittests iPhone 6s 14.4",
+        "name": "ios_components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36718,14 +36718,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/components:ios_components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -36784,7 +36784,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36796,7 +36796,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_net_unittests iPhone 6s 14.4",
+        "name": "ios_net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36822,15 +36822,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/net:ios_net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -36890,7 +36890,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -36902,7 +36902,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_remoting_unittests iPhone 6s 14.4",
+        "name": "ios_remoting_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -36928,14 +36928,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://remoting/ios:ios_remoting_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -36994,7 +36994,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37007,7 +37007,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_showcase_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37033,14 +37033,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -37100,7 +37100,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37113,7 +37113,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone 7 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37139,14 +37139,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -37206,7 +37206,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37219,7 +37219,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone X 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37245,14 +37245,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -37312,7 +37312,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37324,7 +37324,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_testing_unittests iPhone 6s 14.4",
+        "name": "ios_testing_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37350,14 +37350,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/testing:ios_testing_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -37416,7 +37416,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37428,7 +37428,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPad Air 2 14.4",
+        "name": "ios_web_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37454,14 +37454,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -37520,7 +37520,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37532,7 +37532,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s 14.4",
+        "name": "ios_web_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37558,14 +37558,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -37624,7 +37624,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37636,7 +37636,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37662,14 +37662,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -37728,7 +37728,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37740,7 +37740,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37766,14 +37766,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -37832,7 +37832,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37845,7 +37845,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37871,14 +37871,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -37938,7 +37938,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -37951,7 +37951,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -37977,14 +37977,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -38044,7 +38044,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38057,7 +38057,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 7 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38083,14 +38083,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -38150,7 +38150,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38162,7 +38162,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPad Air 2 14.4",
+        "name": "ios_web_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38188,14 +38188,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -38254,7 +38254,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38266,7 +38266,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s 14.4",
+        "name": "ios_web_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38292,14 +38292,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -38358,7 +38358,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38370,7 +38370,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38396,14 +38396,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -38462,7 +38462,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38474,7 +38474,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38500,14 +38500,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -38566,7 +38566,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38578,7 +38578,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPad Air 2 14.4",
+        "name": "ios_web_view_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38604,14 +38604,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -38670,7 +38670,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38682,7 +38682,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s 14.4",
+        "name": "ios_web_view_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38708,14 +38708,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -38774,7 +38774,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38786,7 +38786,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38812,14 +38812,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -38878,7 +38878,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38890,7 +38890,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -38916,14 +38916,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -38982,7 +38982,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -38994,7 +38994,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPad Air 2 14.4",
+        "name": "ios_web_view_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39020,14 +39020,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -39086,7 +39086,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39098,7 +39098,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s 14.4",
+        "name": "ios_web_view_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39124,14 +39124,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -39190,7 +39190,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39202,7 +39202,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39228,14 +39228,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -39294,7 +39294,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39306,7 +39306,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39332,14 +39332,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -39398,7 +39398,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39410,7 +39410,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "net_unittests iPhone 6s 14.4",
+        "name": "net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39436,14 +39436,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://net:net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -39502,7 +39502,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39514,7 +39514,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "services_unittests iPhone 6s 14.4",
+        "name": "services_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39540,14 +39540,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://services:services_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -39606,7 +39606,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39618,7 +39618,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPad Air 2 14.4",
+        "name": "skia_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39644,14 +39644,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -39710,7 +39710,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39722,7 +39722,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s 14.4",
+        "name": "skia_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39748,14 +39748,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -39814,7 +39814,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39826,7 +39826,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s Plus 14.4",
+        "name": "skia_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39852,14 +39852,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -39918,7 +39918,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -39930,7 +39930,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone SE (1st generation) 14.4",
+        "name": "skia_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -39956,14 +39956,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -40022,7 +40022,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40034,7 +40034,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "sql_unittests iPhone 6s 14.4",
+        "name": "sql_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40060,14 +40060,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://sql:sql_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -40126,7 +40126,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40138,7 +40138,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPad Air 2 14.4",
+        "name": "ui_base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40164,14 +40164,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -40230,7 +40230,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40242,7 +40242,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s 14.4",
+        "name": "ui_base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40268,14 +40268,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -40334,7 +40334,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40346,7 +40346,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s Plus 14.4",
+        "name": "ui_base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40372,14 +40372,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -40438,7 +40438,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40450,7 +40450,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone SE (1st generation) 14.4",
+        "name": "ui_base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40476,14 +40476,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -40542,7 +40542,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -40554,7 +40554,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "url_unittests iPhone 6s 14.4",
+        "name": "url_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40580,14 +40580,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://url:url_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -40650,7 +40650,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -40665,7 +40665,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "absl_hardening_tests iPhone 6s 14.4",
+        "name": "absl_hardening_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40691,14 +40691,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -40760,7 +40760,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -40775,7 +40775,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPad Air 2 14.4",
+        "name": "base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40801,14 +40801,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -40870,7 +40870,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -40885,7 +40885,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s 14.4",
+        "name": "base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -40911,14 +40911,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -40980,7 +40980,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -40995,7 +40995,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s Plus 14.4",
+        "name": "base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41021,14 +41021,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -41090,7 +41090,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41105,7 +41105,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone SE (1st generation) 14.4",
+        "name": "base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41131,14 +41131,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -41200,7 +41200,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41215,7 +41215,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_crypto_tests iPhone 6s 14.4",
+        "name": "boringssl_crypto_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41241,14 +41241,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -41310,7 +41310,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41325,7 +41325,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_ssl_tests iPhone 6s 14.4",
+        "name": "boringssl_ssl_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41351,14 +41351,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -41420,7 +41420,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41435,7 +41435,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPad Air 2 14.4",
+        "name": "components_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41461,14 +41461,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -41530,7 +41530,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41545,7 +41545,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s 14.4",
+        "name": "components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41571,14 +41571,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -41640,7 +41640,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41655,7 +41655,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s Plus 14.4",
+        "name": "components_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41681,14 +41681,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -41750,7 +41750,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41765,7 +41765,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone SE (1st generation) 14.4",
+        "name": "components_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41791,14 +41791,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -41860,7 +41860,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41875,7 +41875,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "crypto_unittests iPhone 6s 14.4",
+        "name": "crypto_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -41901,14 +41901,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://crypto:crypto_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -41970,7 +41970,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -41985,7 +41985,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPad Air 2 14.4",
+        "name": "gfx_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42011,14 +42011,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -42080,7 +42080,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42095,7 +42095,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s 14.4",
+        "name": "gfx_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42121,14 +42121,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -42190,7 +42190,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42205,7 +42205,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s Plus 14.4",
+        "name": "gfx_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42231,14 +42231,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -42300,7 +42300,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42315,7 +42315,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone SE (1st generation) 14.4",
+        "name": "gfx_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42341,14 +42341,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -42410,7 +42410,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42425,7 +42425,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "google_apis_unittests iPhone 6s 14.4",
+        "name": "google_apis_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42451,14 +42451,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://google_apis:google_apis_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -42520,7 +42520,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42536,7 +42536,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42562,14 +42562,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -42632,7 +42632,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42648,7 +42648,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42674,14 +42674,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -42744,7 +42744,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42760,7 +42760,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42786,14 +42786,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -42856,7 +42856,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42872,7 +42872,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -42898,15 +42898,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -42970,7 +42970,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -42986,7 +42986,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43012,15 +43012,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -43084,7 +43084,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43100,7 +43100,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43126,15 +43126,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -43198,7 +43198,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43214,7 +43214,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43240,15 +43240,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -43312,7 +43312,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43328,7 +43328,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43354,15 +43354,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -43426,7 +43426,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43442,7 +43442,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43468,15 +43468,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -43540,7 +43540,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43556,7 +43556,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43582,15 +43582,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -43654,7 +43654,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43670,7 +43670,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43696,15 +43696,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -43768,7 +43768,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43784,7 +43784,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43810,15 +43810,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -43882,7 +43882,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -43898,7 +43898,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -43924,14 +43924,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -43994,7 +43994,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44010,7 +44010,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44036,14 +44036,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -44106,7 +44106,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44122,7 +44122,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44148,14 +44148,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -44218,7 +44218,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44234,7 +44234,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44260,15 +44260,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -44332,7 +44332,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44348,7 +44348,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44374,15 +44374,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -44446,7 +44446,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44462,7 +44462,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44488,15 +44488,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -44560,7 +44560,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44575,7 +44575,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPad Air 2 14.4",
+        "name": "ios_chrome_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44601,14 +44601,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -44670,7 +44670,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44685,7 +44685,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s 14.4",
+        "name": "ios_chrome_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44711,14 +44711,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -44780,7 +44780,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44795,7 +44795,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s Plus 14.4",
+        "name": "ios_chrome_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44821,14 +44821,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -44890,7 +44890,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -44905,7 +44905,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -44931,14 +44931,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -45000,7 +45000,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45016,7 +45016,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45042,14 +45042,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -45112,7 +45112,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45128,7 +45128,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45154,14 +45154,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -45224,7 +45224,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45240,7 +45240,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45266,14 +45266,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -45336,7 +45336,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45351,7 +45351,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_components_unittests iPhone 6s 14.4",
+        "name": "ios_components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45377,14 +45377,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/components:ios_components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -45446,7 +45446,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45461,7 +45461,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_net_unittests iPhone 6s 14.4",
+        "name": "ios_net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45487,15 +45487,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/net:ios_net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -45558,7 +45558,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45573,7 +45573,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_remoting_unittests iPhone 6s 14.4",
+        "name": "ios_remoting_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45599,14 +45599,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://remoting/ios:ios_remoting_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -45668,7 +45668,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45684,7 +45684,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_showcase_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45710,14 +45710,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -45780,7 +45780,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45796,7 +45796,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone 7 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45822,14 +45822,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -45892,7 +45892,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -45908,7 +45908,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone X 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -45934,14 +45934,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -46004,7 +46004,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46019,7 +46019,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_testing_unittests iPhone 6s 14.4",
+        "name": "ios_testing_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46045,14 +46045,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/testing:ios_testing_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -46114,7 +46114,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46129,7 +46129,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPad Air 2 14.4",
+        "name": "ios_web_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46155,14 +46155,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -46224,7 +46224,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46239,7 +46239,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s 14.4",
+        "name": "ios_web_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46265,14 +46265,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -46334,7 +46334,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46349,7 +46349,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46375,14 +46375,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -46444,7 +46444,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46459,7 +46459,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46485,14 +46485,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -46554,7 +46554,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46570,7 +46570,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46596,14 +46596,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -46666,7 +46666,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46682,7 +46682,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46708,14 +46708,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -46778,7 +46778,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46794,7 +46794,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 7 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46820,14 +46820,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -46890,7 +46890,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -46905,7 +46905,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPad Air 2 14.4",
+        "name": "ios_web_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -46931,14 +46931,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -47000,7 +47000,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47015,7 +47015,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s 14.4",
+        "name": "ios_web_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47041,14 +47041,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -47110,7 +47110,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47125,7 +47125,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47151,14 +47151,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -47220,7 +47220,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47235,7 +47235,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47261,14 +47261,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -47330,7 +47330,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47345,7 +47345,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPad Air 2 14.4",
+        "name": "ios_web_view_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47371,14 +47371,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -47440,7 +47440,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47455,7 +47455,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s 14.4",
+        "name": "ios_web_view_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47481,14 +47481,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -47550,7 +47550,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47565,7 +47565,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47591,14 +47591,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -47660,7 +47660,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47675,7 +47675,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47701,14 +47701,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -47770,7 +47770,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47785,7 +47785,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPad Air 2 14.4",
+        "name": "ios_web_view_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47811,14 +47811,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -47880,7 +47880,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -47895,7 +47895,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s 14.4",
+        "name": "ios_web_view_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -47921,14 +47921,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -47990,7 +47990,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48005,7 +48005,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48031,14 +48031,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -48100,7 +48100,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48115,7 +48115,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48141,14 +48141,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -48210,7 +48210,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48225,7 +48225,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "net_unittests iPhone 6s 14.4",
+        "name": "net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48251,14 +48251,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://net:net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -48320,7 +48320,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48335,7 +48335,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "services_unittests iPhone 6s 14.4",
+        "name": "services_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48361,14 +48361,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://services:services_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -48430,7 +48430,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48445,7 +48445,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPad Air 2 14.4",
+        "name": "skia_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48471,14 +48471,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -48540,7 +48540,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48555,7 +48555,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s 14.4",
+        "name": "skia_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48581,14 +48581,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -48650,7 +48650,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48665,7 +48665,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s Plus 14.4",
+        "name": "skia_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48691,14 +48691,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -48760,7 +48760,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48775,7 +48775,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone SE (1st generation) 14.4",
+        "name": "skia_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48801,14 +48801,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -48870,7 +48870,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48885,7 +48885,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "sql_unittests iPhone 6s 14.4",
+        "name": "sql_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -48911,14 +48911,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://sql:sql_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -48980,7 +48980,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -48995,7 +48995,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPad Air 2 14.4",
+        "name": "ui_base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -49021,14 +49021,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -49090,7 +49090,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -49105,7 +49105,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s 14.4",
+        "name": "ui_base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -49131,14 +49131,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -49200,7 +49200,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -49215,7 +49215,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s Plus 14.4",
+        "name": "ui_base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -49241,14 +49241,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -49310,7 +49310,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -49325,7 +49325,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone SE (1st generation) 14.4",
+        "name": "ui_base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -49351,14 +49351,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -49420,7 +49420,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--args-json",
           "{\"test_args\": [\"--write-compiled-tests-json-to-writable-path\"]}",
           "--out-dir",
@@ -49435,7 +49435,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "url_unittests iPhone 6s 14.4",
+        "name": "url_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -49461,14 +49461,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://url:url_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index fda648b..bb8771e6 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -8866,7 +8866,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -8879,7 +8879,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "absl_hardening_tests iPhone 6s 14.4",
+        "name": "absl_hardening_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -8905,14 +8905,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -8972,7 +8972,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -8985,7 +8985,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPad Air 2 14.4",
+        "name": "base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9011,14 +9011,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -9078,7 +9078,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9091,7 +9091,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s 14.4",
+        "name": "base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9117,14 +9117,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -9184,7 +9184,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9197,7 +9197,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone 6s Plus 14.4",
+        "name": "base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9223,14 +9223,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -9290,7 +9290,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9303,7 +9303,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "base_unittests iPhone SE (1st generation) 14.4",
+        "name": "base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9329,14 +9329,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://base:base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -9396,7 +9396,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9409,7 +9409,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_crypto_tests iPhone 6s 14.4",
+        "name": "boringssl_crypto_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9435,14 +9435,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -9502,7 +9502,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9515,7 +9515,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_ssl_tests iPhone 6s 14.4",
+        "name": "boringssl_ssl_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9541,14 +9541,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -9608,7 +9608,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9621,7 +9621,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPad Air 2 14.4",
+        "name": "components_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9647,14 +9647,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -9714,7 +9714,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9727,7 +9727,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s 14.4",
+        "name": "components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9753,14 +9753,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -9820,7 +9820,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9833,7 +9833,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone 6s Plus 14.4",
+        "name": "components_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9859,14 +9859,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -9926,7 +9926,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -9939,7 +9939,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "components_unittests iPhone SE (1st generation) 14.4",
+        "name": "components_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -9965,14 +9965,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://components:components_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -10032,7 +10032,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10045,7 +10045,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "crypto_unittests iPhone 6s 14.4",
+        "name": "crypto_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10071,14 +10071,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://crypto:crypto_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10138,7 +10138,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10151,7 +10151,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPad Air 2 14.4",
+        "name": "gfx_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10177,14 +10177,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -10244,7 +10244,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10257,7 +10257,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s 14.4",
+        "name": "gfx_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10283,14 +10283,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10350,7 +10350,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10363,7 +10363,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone 6s Plus 14.4",
+        "name": "gfx_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10389,14 +10389,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -10456,7 +10456,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10469,7 +10469,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "gfx_unittests iPhone SE (1st generation) 14.4",
+        "name": "gfx_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10495,14 +10495,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/gfx:gfx_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -10562,7 +10562,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10575,7 +10575,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "google_apis_unittests iPhone 6s 14.4",
+        "name": "google_apis_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10601,14 +10601,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://google_apis:google_apis_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10668,7 +10668,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10682,7 +10682,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10708,15 +10708,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10778,7 +10778,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10792,7 +10792,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10818,15 +10818,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10888,7 +10888,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -10902,7 +10902,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -10928,15 +10928,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -10998,7 +10998,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11011,7 +11011,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPad Air 2 14.4",
+        "name": "ios_chrome_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11037,14 +11037,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -11104,7 +11104,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11117,7 +11117,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s 14.4",
+        "name": "ios_chrome_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11143,14 +11143,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -11210,7 +11210,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11223,7 +11223,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone 6s Plus 14.4",
+        "name": "ios_chrome_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11249,14 +11249,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -11316,7 +11316,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11329,7 +11329,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11355,14 +11355,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test:ios_chrome_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -11422,7 +11422,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11435,7 +11435,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_components_unittests iPhone 6s 14.4",
+        "name": "ios_components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11461,14 +11461,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/components:ios_components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -11528,7 +11528,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11541,7 +11541,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_net_unittests iPhone 6s 14.4",
+        "name": "ios_net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11567,15 +11567,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/net:ios_net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -11636,7 +11636,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11649,7 +11649,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_remoting_unittests iPhone 6s 14.4",
+        "name": "ios_remoting_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11675,14 +11675,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://remoting/ios:ios_remoting_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -11742,7 +11742,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11755,7 +11755,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_testing_unittests iPhone 6s 14.4",
+        "name": "ios_testing_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11781,14 +11781,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/testing:ios_testing_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -11848,7 +11848,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11861,7 +11861,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPad Air 2 14.4",
+        "name": "ios_web_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11887,14 +11887,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -11954,7 +11954,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -11967,7 +11967,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s 14.4",
+        "name": "ios_web_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -11993,14 +11993,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -12060,7 +12060,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12073,7 +12073,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12099,14 +12099,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -12166,7 +12166,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12179,7 +12179,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12205,14 +12205,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -12272,7 +12272,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12286,7 +12286,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12312,14 +12312,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -12380,7 +12380,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12393,7 +12393,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPad Air 2 14.4",
+        "name": "ios_web_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12419,14 +12419,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -12486,7 +12486,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12499,7 +12499,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s 14.4",
+        "name": "ios_web_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12525,14 +12525,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -12592,7 +12592,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12605,7 +12605,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12631,14 +12631,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -12698,7 +12698,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12711,7 +12711,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12737,14 +12737,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web:ios_web_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -12804,7 +12804,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12817,7 +12817,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPad Air 2 14.4",
+        "name": "ios_web_view_inttests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12843,14 +12843,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -12910,7 +12910,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -12923,7 +12923,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s 14.4",
+        "name": "ios_web_view_inttests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -12949,14 +12949,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -13016,7 +13016,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13029,7 +13029,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_inttests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13055,14 +13055,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -13122,7 +13122,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13135,7 +13135,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_inttests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13161,14 +13161,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_inttests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -13228,7 +13228,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13241,7 +13241,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPad Air 2 14.4",
+        "name": "ios_web_view_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13267,14 +13267,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -13334,7 +13334,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13347,7 +13347,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s 14.4",
+        "name": "ios_web_view_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13373,14 +13373,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -13440,7 +13440,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13453,7 +13453,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone 6s Plus 14.4",
+        "name": "ios_web_view_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13479,14 +13479,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -13546,7 +13546,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13559,7 +13559,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.4",
+        "name": "ios_web_view_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13585,14 +13585,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web_view:ios_web_view_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -13652,7 +13652,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13665,7 +13665,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "net_unittests iPhone 6s 14.4",
+        "name": "net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13691,14 +13691,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://net:net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -13758,7 +13758,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13771,7 +13771,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "services_unittests iPhone 6s 14.4",
+        "name": "services_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13797,14 +13797,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://services:services_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -13864,7 +13864,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13877,7 +13877,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPad Air 2 14.4",
+        "name": "skia_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -13903,14 +13903,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -13970,7 +13970,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -13983,7 +13983,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s 14.4",
+        "name": "skia_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14009,14 +14009,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -14076,7 +14076,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14089,7 +14089,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone 6s Plus 14.4",
+        "name": "skia_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14115,14 +14115,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -14182,7 +14182,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14195,7 +14195,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "skia_unittests iPhone SE (1st generation) 14.4",
+        "name": "skia_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14221,14 +14221,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://skia:skia_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -14288,7 +14288,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14301,7 +14301,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "sql_unittests iPhone 6s 14.4",
+        "name": "sql_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14327,14 +14327,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://sql:sql_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -14394,7 +14394,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14407,7 +14407,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPad Air 2 14.4",
+        "name": "ui_base_unittests iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14433,14 +14433,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -14500,7 +14500,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14513,7 +14513,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s 14.4",
+        "name": "ui_base_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14539,14 +14539,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -14606,7 +14606,7 @@
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14619,7 +14619,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone 6s Plus 14.4",
+        "name": "ui_base_unittests iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14645,14 +14645,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
@@ -14712,7 +14712,7 @@
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14725,7 +14725,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ui_base_unittests iPhone SE (1st generation) 14.4",
+        "name": "ui_base_unittests iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14751,14 +14751,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ui/base:ui_base_unittests/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
@@ -14818,7 +14818,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14831,7 +14831,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "url_unittests iPhone 6s 14.4",
+        "name": "url_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14857,14 +14857,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://url:url_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
@@ -14931,7 +14931,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -14945,7 +14945,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -14971,14 +14971,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -15039,7 +15039,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15053,7 +15053,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15079,14 +15079,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -15147,7 +15147,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15161,7 +15161,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15187,14 +15187,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -15255,7 +15255,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15269,7 +15269,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15295,15 +15295,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -15365,7 +15365,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15379,7 +15379,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15405,15 +15405,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -15475,7 +15475,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15489,7 +15489,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15515,15 +15515,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -15585,7 +15585,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15599,7 +15599,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15625,15 +15625,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -15695,7 +15695,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15709,7 +15709,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15735,15 +15735,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -15805,7 +15805,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15819,7 +15819,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15845,15 +15845,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -15915,7 +15915,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -15929,7 +15929,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -15955,15 +15955,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -16025,7 +16025,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16039,7 +16039,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16065,14 +16065,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -16133,7 +16133,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16147,7 +16147,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16173,14 +16173,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -16241,7 +16241,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16255,7 +16255,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16281,14 +16281,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -16349,7 +16349,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16363,7 +16363,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16389,15 +16389,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -16459,7 +16459,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16473,7 +16473,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16499,15 +16499,15 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -16569,7 +16569,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16583,7 +16583,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16609,14 +16609,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -16677,7 +16677,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16691,7 +16691,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16717,14 +16717,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -16785,7 +16785,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16799,7 +16799,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone X 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16825,14 +16825,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -16893,7 +16893,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -16907,7 +16907,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_showcase_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -16933,14 +16933,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -17001,7 +17001,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17015,7 +17015,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone 7 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17041,14 +17041,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -17109,7 +17109,7 @@
           "--platform",
           "iPhone X",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17123,7 +17123,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone X 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone X 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17149,14 +17149,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone X 14.4"
+        "variant_id": "iPhone X 14.5"
       },
       {
         "args": [
@@ -17217,7 +17217,7 @@
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17231,7 +17231,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17257,14 +17257,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
@@ -17325,7 +17325,7 @@
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17339,7 +17339,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 7 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17365,14 +17365,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -17440,7 +17440,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17452,7 +17452,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "absl_hardening_tests iPhone 6s 14.4",
+        "name": "absl_hardening_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17478,21 +17478,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17504,7 +17504,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_crypto_tests iPhone 6s 14.4",
+        "name": "boringssl_crypto_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17530,21 +17530,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17556,7 +17556,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "boringssl_ssl_tests iPhone 6s 14.4",
+        "name": "boringssl_ssl_tests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17582,21 +17582,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17608,7 +17608,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "crypto_unittests iPhone 6s 14.4",
+        "name": "crypto_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17634,21 +17634,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://crypto:crypto_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17660,7 +17660,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "google_apis_unittests iPhone 6s 14.4",
+        "name": "google_apis_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17686,21 +17686,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://google_apis:google_apis_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17713,7 +17713,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_bookmarks_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17739,21 +17739,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_bookmarks_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17766,7 +17766,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17792,22 +17792,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17820,7 +17820,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17846,22 +17846,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17874,7 +17874,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone 6s Plus 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17900,22 +17900,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17928,7 +17928,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_integration_eg2tests_module iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_integration_eg2tests_module iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -17954,22 +17954,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 8
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_integration_eg2tests_module/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -17982,7 +17982,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_settings_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_settings_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18008,22 +18008,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_settings_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18036,7 +18036,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18062,22 +18062,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18090,7 +18090,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18116,22 +18116,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18144,7 +18144,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 6s Plus 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18170,22 +18170,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18198,7 +18198,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_signin_eg2tests_module iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_signin_eg2tests_module iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18224,22 +18224,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 5
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18252,7 +18252,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_smoke_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_smoke_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18278,21 +18278,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_smoke_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18305,7 +18305,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18331,22 +18331,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18359,7 +18359,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18385,22 +18385,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18413,7 +18413,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone 6s Plus 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18439,22 +18439,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18467,7 +18467,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_ui_eg2tests_module iPhone SE (1st generation) 14.4",
+        "name": "ios_chrome_ui_eg2tests_module iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18493,22 +18493,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 12
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_ui_eg2tests_module/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18521,7 +18521,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_chrome_web_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_chrome_web_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18547,21 +18547,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18573,7 +18573,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_components_unittests iPhone 6s 14.4",
+        "name": "ios_components_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18599,21 +18599,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/components:ios_components_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 7",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18626,7 +18626,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_crash_xcuitests_module iPhone 7 14.4",
+        "name": "ios_crash_xcuitests_module iPhone 7 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18652,14 +18652,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://third_party/crashpad/crashpad/test/ios:ios_crash_xcuitests_module/",
-        "variant_id": "iPhone 7 14.4"
+        "variant_id": "iPhone 7 14.5"
       },
       {
         "args": [
@@ -18719,7 +18719,7 @@
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18731,7 +18731,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_net_unittests iPhone 6s 14.4",
+        "name": "ios_net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18757,22 +18757,22 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 3
         },
         "test_id_prefix": "ninja://ios/net:ios_net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18784,7 +18784,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_remoting_unittests iPhone 6s 14.4",
+        "name": "ios_remoting_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18810,21 +18810,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://remoting/ios:ios_remoting_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18837,7 +18837,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_showcase_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_showcase_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18863,21 +18863,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/showcase:ios_showcase_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18889,7 +18889,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_testing_unittests iPhone 6s 14.4",
+        "name": "ios_testing_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18915,21 +18915,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/testing:ios_testing_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPad Air 2",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18942,7 +18942,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.4",
+        "name": "ios_web_shell_eg2tests_module iPad Air 2 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -18968,21 +18968,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPad Air 2 14.4"
+        "variant_id": "iPad Air 2 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -18995,7 +18995,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19021,21 +19021,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s Plus",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19048,7 +19048,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone 6s Plus 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone 6s Plus 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19074,21 +19074,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone 6s Plus 14.4"
+        "variant_id": "iPhone 6s Plus 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone SE (1st generation)",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19101,7 +19101,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "ios_web_shell_eg2tests_module iPhone SE (1st generation) 14.4",
+        "name": "ios_web_shell_eg2tests_module iPhone SE (1st generation) 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19127,21 +19127,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://ios/web/shell/test:ios_web_shell_eg2tests_module/",
-        "variant_id": "iPhone SE (1st generation) 14.4"
+        "variant_id": "iPhone SE (1st generation) 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19153,7 +19153,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "net_unittests iPhone 6s 14.4",
+        "name": "net_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19179,21 +19179,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://net:net_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19205,7 +19205,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "services_unittests iPhone 6s 14.4",
+        "name": "services_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19231,21 +19231,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://services:services_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19257,7 +19257,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "sql_unittests iPhone 6s 14.4",
+        "name": "sql_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19283,21 +19283,21 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://sql:sql_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       },
       {
         "args": [
           "--platform",
           "iPhone 6s",
           "--version",
-          "14.4",
+          "14.5",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
@@ -19309,7 +19309,7 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
         },
-        "name": "url_unittests iPhone 6s 14.4",
+        "name": "url_unittests iPhone 6s 14.5",
         "resultdb": {
           "enable": true,
           "has_native_resultdb_integration": true
@@ -19335,14 +19335,14 @@
               "path": "Xcode.app"
             },
             {
-              "name": "runtime_ios_14_4",
-              "path": "Runtime-ios-14.4"
+              "name": "runtime_ios_14_5",
+              "path": "Runtime-ios-14.5"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test_id_prefix": "ninja://url:url_unittests/",
-        "variant_id": "iPhone 6s 14.4"
+        "variant_id": "iPhone 6s 14.5"
       }
     ]
   },
diff --git a/testing/buildbot/filters/android.emulator_11.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_11.chrome_public_test_apk.filter
index 33f2434..6cb73233 100644
--- a/testing/buildbot/filters/android.emulator_11.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_11.chrome_public_test_apk.filter
@@ -84,9 +84,6 @@
 -org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AddressAccessoryIntegrationTest.testFillsSuggestionOnClick
 -org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.CreditCardAccessoryIntegrationTest.testFillsSuggestionOnClick
 
-# crbug.com/1231646
--org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsMediatorTest.testShowAreaSelectionDone
-
 # crbug.com/1231652
 -org.chromium.chrome.browser.autofill.settings.AutofillProfilesFragmentTest.testKeyboardShownOnDpadCenter
 
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 7e3c7c90..62be8a0 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
@@ -55,9 +55,6 @@
 -org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AddressAccessoryIntegrationTest.testFillsSuggestionOnClick
 -org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.CreditCardAccessoryIntegrationTest.testFillsSuggestionOnClick
 
-# crbug.com/1231646
--org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsMediatorTest.testShowAreaSelectionDone
-
 # crbug.com/1231652
 -org.chromium.chrome.browser.autofill.settings.AutofillProfilesFragmentTest.testKeyboardShownOnDpadCenter
 
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 5e50873..95a85d7 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -6986,7 +6986,7 @@
       'ios_common_tests': {
         'variants': [
           'SIM_IPHONE_6S_15_2',
-          'SIM_IPHONE_6S_14_4',
+          'SIM_IPHONE_6S_14_5',
         ],
       },
       'ios_eg2_cq_tests': {
@@ -6995,9 +6995,9 @@
           'SIM_IPHONE_6S_15_2',
           'SIM_IPHONE_7_15_2',
           'SIM_IPAD_AIR_2_15_2',
-          'SIM_IPHONE_6S_14_4',
-          'SIM_IPHONE_7_14_4',
-          'SIM_IPAD_AIR_2_14_4',
+          'SIM_IPHONE_6S_14_5',
+          'SIM_IPHONE_7_14_5',
+          'SIM_IPAD_AIR_2_14_5',
         ],
       },
       'ios_eg2_tests': {
@@ -7006,9 +7006,9 @@
           'SIM_IPHONE_7_15_2',
           'SIM_IPAD_AIR_2_15_2',
           'SIM_IPHONE_X_15_2',
-          'SIM_IPHONE_7_14_4',
-          'SIM_IPAD_AIR_2_14_4',
-          'SIM_IPHONE_X_14_4',
+          'SIM_IPHONE_7_14_5',
+          'SIM_IPAD_AIR_2_14_5',
+          'SIM_IPHONE_X_14_5',
         ],
       },
       'ios_screen_size_dependent_tests': {
@@ -7017,10 +7017,10 @@
           'SIM_IPHONE_6S_15_2',
           'SIM_IPHONE_SE_1ST_GEN_15_2',
           'SIM_IPAD_AIR_2_15_2',
-          'SIM_IPHONE_6S_PLUS_14_4',
-          'SIM_IPHONE_6S_14_4',
-          'SIM_IPHONE_SE_1ST_GEN_14_4',
-          'SIM_IPAD_AIR_2_14_4',
+          'SIM_IPHONE_6S_PLUS_14_5',
+          'SIM_IPHONE_6S_14_5',
+          'SIM_IPHONE_SE_1ST_GEN_14_5',
+          'SIM_IPAD_AIR_2_14_5',
         ],
       },
     },
@@ -7083,9 +7083,9 @@
           'SIM_IPHONE_7_15_2',
           'SIM_IPAD_AIR_2_15_2',
           'SIM_IPHONE_X_15_2',
-          'SIM_IPHONE_7_14_4',
-          'SIM_IPAD_AIR_2_14_4',
-          'SIM_IPHONE_X_14_4',
+          'SIM_IPHONE_7_14_5',
+          'SIM_IPAD_AIR_2_14_5',
+          'SIM_IPHONE_X_14_5',
         ]
       },
       'ios_eg2_cq_tests': {
@@ -7093,8 +7093,8 @@
         'variants': [
           'SIM_IPHONE_7_15_2',
           'SIM_IPAD_AIR_2_15_2',
-          'SIM_IPHONE_7_14_4',
-          'SIM_IPAD_AIR_2_14_4',
+          'SIM_IPHONE_7_14_5',
+          'SIM_IPAD_AIR_2_14_5',
         ]
       }
     },
@@ -7127,29 +7127,29 @@
     'ios_simulator_noncq_tests': {
       'ios_common_tests': {
         'variants': [
-          'SIM_IPHONE_6S_14_4',
+          'SIM_IPHONE_6S_14_5',
         ]
       },
       'ios_eg2_tests': {
         'mixins': ['xcode_parallelization'],
         'variants': [
-          'SIM_IPHONE_6S_14_4',
+          'SIM_IPHONE_6S_14_5',
         ]
       },
       'ios_eg2_cq_tests': {
         'mixins': ['xcode_parallelization'],
         'variants': [
-          'SIM_IPHONE_6S_PLUS_14_4',
-          'SIM_IPHONE_6S_14_4',
-          'SIM_IPHONE_SE_1ST_GEN_14_4',
-          'SIM_IPAD_AIR_2_14_4',
+          'SIM_IPHONE_6S_PLUS_14_5',
+          'SIM_IPHONE_6S_14_5',
+          'SIM_IPHONE_SE_1ST_GEN_14_5',
+          'SIM_IPAD_AIR_2_14_5',
         ]
       },
       'ios_crash_xcuitests': {
         'mixins': ['xcode_parallelization'],
         'variants': [
           'SIM_IPHONE_7_15_2',
-          'SIM_IPHONE_7_14_4',
+          'SIM_IPHONE_7_14_5',
         ]
       },
     },
@@ -7158,14 +7158,14 @@
     'ios_simulator_tests': {
       'ios_common_tests': {
         'variants': [
-          'SIM_IPHONE_6S_14_4',
+          'SIM_IPHONE_6S_14_5',
           'SIM_IPHONE_6S_15_2',
         ]
       },
       'ios_eg2_cq_tests': {
         'mixins': ['xcode_parallelization'],
         'variants': [
-          'SIM_IPHONE_6S_14_4',
+          'SIM_IPHONE_6S_14_5',
           'SIM_IPHONE_6S_15_2',
         ]
       },
@@ -7175,10 +7175,10 @@
           'SIM_IPHONE_6S_15_2',
           'SIM_IPHONE_SE_1ST_GEN_15_2',
           'SIM_IPAD_AIR_2_15_2',
-          'SIM_IPHONE_6S_PLUS_14_4',
-          'SIM_IPHONE_6S_14_4',
-          'SIM_IPHONE_SE_1ST_GEN_14_4',
-          'SIM_IPAD_AIR_2_14_4'
+          'SIM_IPHONE_6S_PLUS_14_5',
+          'SIM_IPHONE_6S_14_5',
+          'SIM_IPHONE_SE_1ST_GEN_14_5',
+          'SIM_IPAD_AIR_2_14_5'
         ]
       }
     },
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 1131b876..05ebc9fb 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -110,18 +110,6 @@
       'mac_retina_nvidia_gpu_stable',
     ],
   },
-  'SIM_IPAD_AIR_2_14_4': {
-    'args': [
-      '--platform',
-      'iPad Air 2',
-      '--version',
-      '14.4'
-    ],
-    'identifier': 'iPad Air 2 14.4',
-    'mixins': [
-      'ios_runtime_cache_14_4',
-    ],
-  },
   'SIM_IPAD_AIR_2_14_5': {
     'args': [
       '--platform',
@@ -208,18 +196,6 @@
       'ios_runtime_cache_14_5',
     ],
   },
-  'SIM_IPHONE_6S_14_4': {
-    'args': [
-      '--platform',
-      'iPhone 6s',
-      '--version',
-      '14.4',
-    ],
-    'identifier': 'iPhone 6s 14.4',
-    'mixins': [
-      'ios_runtime_cache_14_4',
-    ],
-  },
   'SIM_IPHONE_6S_14_5': {
     'args': [
       '--platform',
@@ -256,18 +232,6 @@
       'ios_runtime_cache_15_5',
     ],
   },
-  'SIM_IPHONE_6S_PLUS_14_4': {
-    'args': [
-      '--platform',
-      'iPhone 6s Plus',
-      '--version',
-      '14.4',
-    ],
-    'identifier': 'iPhone 6s Plus 14.4',
-    'mixins': [
-      'ios_runtime_cache_14_4',
-    ],
-  },
   'SIM_IPHONE_6S_PLUS_14_5': {
     'args': [
       '--platform',
@@ -304,18 +268,6 @@
       'ios_runtime_cache_15_5',
     ],
   },
-  'SIM_IPHONE_7_14_4': {
-    'args': [
-      '--platform',
-      'iPhone 7',
-      '--version',
-      '14.4',
-    ],
-    'identifier': 'iPhone 7 14.4',
-    'mixins': [
-      'ios_runtime_cache_14_4',
-    ],
-  },
   'SIM_IPHONE_7_14_5': {
     'args': [
       '--platform',
@@ -352,18 +304,6 @@
       'ios_runtime_cache_15_5',
     ],
   },
-  'SIM_IPHONE_SE_1ST_GEN_14_4': {
-    'args': [
-      '--platform',
-      'iPhone SE (1st generation)',
-      '--version',
-      '14.4',
-    ],
-    'identifier': 'iPhone SE (1st generation) 14.4',
-    'mixins': [
-      'ios_runtime_cache_14_4',
-    ],
-  },
   'SIM_IPHONE_SE_1ST_GEN_14_5': {
     'args': [
       '--platform',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 179d10b..f6e2a71 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3432,9 +3432,13 @@
                     "name": "UseDnsHttpsSvcb",
                     "params": {
                         "UseDnsHttpsSvcbEnableInsecure": "true",
-                        "UseDnsHttpsSvcbExtraTimeAbsolute": "500ms",
-                        "UseDnsHttpsSvcbExtraTimePercent": "50",
-                        "UseDnsHttpsSvcbHttpUpgrade": "true"
+                        "UseDnsHttpsSvcbHttpUpgrade": "true",
+                        "UseDnsHttpsSvcbInsecureExtraTimeMax": "500ms",
+                        "UseDnsHttpsSvcbInsecureExtraTimeMin": "300ms",
+                        "UseDnsHttpsSvcbInsecureExtraTimePercent": "50",
+                        "UseDnsHttpsSvcbSecureExtraTimeMax": "500ms",
+                        "UseDnsHttpsSvcbSecureExtraTimeMin": "300ms",
+                        "UseDnsHttpsSvcbSecureExtraTimePercent": "50"
                     },
                     "enable_features": [
                         "UseDnsHttpsSvcb"
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 97263e9b5..b1ed2c9 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -996,7 +996,7 @@
 // have their rendering throttled on display:none or zero-area.
 const base::Feature kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes{
     "ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes",
-    base::FEATURE_ENABLED_BY_DEFAULT};
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Kill switch for the Interest Group API, i.e. if disabled, the
 // API exposure will be disabled regardless of the OT config.
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index c15df96..be2e45e4 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -659,11 +659,6 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kElementSuperRareData;
 
-BLINK_COMMON_EXPORT extern const base::Feature kClientHintsPartitionedCookies;
-BLINK_COMMON_EXPORT extern const base::Feature kScaleTileMemoryLimit;
-BLINK_COMMON_EXPORT
-extern const base::FeatureParam<double> kScaleTileMemoryLimitFactor;
-
 // If enabled, the client hints cache will be loaded on browser restarts.
 BLINK_COMMON_EXPORT extern const base::Feature kDurableClientHintsCache;
 
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index d521eae..e8aab442 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -445,8 +445,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_descriptor_base.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_layout_descriptor.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_layout_descriptor.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_predefined_color_space.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_predefined_color_space.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_primitive_state.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_primitive_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_programmable_stage.cc",
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index ae22f5e..fd88a0fc7 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1385,6 +1385,7 @@
       default_value: "StyleContentAlignmentData(ContentPosition::kNormal, ContentDistributionType::kDefault, OverflowAlignment::kDefault)",
       type_name: "StyleContentAlignmentData",
       converter: "ConvertContentAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "align-items",
@@ -1395,6 +1396,7 @@
       default_value: "StyleSelfAlignmentData(ItemPosition::kNormal, OverflowAlignment::kDefault)",
       type_name: "StyleSelfAlignmentData",
       converter: "ConvertSelfOrDefaultAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "alignment-baseline",
@@ -1416,6 +1418,7 @@
       default_value: "StyleSelfAlignmentData(ItemPosition::kAuto, OverflowAlignment::kDefault)",
       type_name: "StyleSelfAlignmentData",
       converter: "ConvertSelfOrDefaultAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "anchor-name",
@@ -2855,6 +2858,7 @@
       default_value: "StyleContentAlignmentData(ContentPosition::kNormal, ContentDistributionType::kDefault, OverflowAlignment::kDefault)",
       type_name: "StyleContentAlignmentData",
       converter: "ConvertContentAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "justify-items",
@@ -2865,6 +2869,7 @@
       default_value: "StyleSelfAlignmentData(ItemPosition::kLegacy, OverflowAlignment::kDefault)",
       type_name: "StyleSelfAlignmentData",
       converter: "ConvertSelfOrDefaultAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "justify-self",
@@ -2875,6 +2880,7 @@
       default_value: "StyleSelfAlignmentData(ItemPosition::kAuto, OverflowAlignment::kDefault)",
       type_name: "StyleSelfAlignmentData",
       converter: "ConvertSelfOrDefaultAlignmentData",
+      valid_for_position_fallback: true,
     },
     {
       name: "left",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index aa2c54b..a4926dc0 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8419,8 +8419,6 @@
 
 void Document::CheckPartitionedCookiesOriginTrial(
     const ResourceResponse& response) {
-  // if (!cookie_jar_)
-  //   return;
   cookie_jar_->CheckPartitionedCookiesOriginTrial(response);
 }
 
diff --git a/third_party/blink/renderer/core/frame/attribution_response_parsing.cc b/third_party/blink/renderer/core/frame/attribution_response_parsing.cc
index fd7fdc5..7c67e37 100644
--- a/third_party/blink/renderer/core/frame/attribution_response_parsing.cc
+++ b/third_party/blink/renderer/core/frame/attribution_response_parsing.cc
@@ -31,10 +31,13 @@
 
 namespace {
 
-bool ParseAttributionAggregatableKey(const JSONObject* object,
+bool ParseAttributionAggregatableKey(const JSONValue* value,
                                      absl::uint128* out) {
+  if (!value)
+    return false;
+
   String key_piece;
-  if (!object->GetString("key_piece", &key_piece))
+  if (!value->AsString(&key_piece))
     return false;
 
   // Final keys will be restricted to a maximum of 128 bits and the hex strings
@@ -155,11 +158,11 @@
           kExclusiveMaxHistogramValue,
       "Bump the version for histogram Conversions.AggregatableKeysPerSource");
 
-  const auto* array = JSONArray::Cast(json.get());
-  if (!array)
+  const auto* object = JSONObject::Cast(json.get());
+  if (!object)
     return false;
 
-  const wtf_size_t num_keys = array->size();
+  const wtf_size_t num_keys = object->size();
   if (num_keys > kMaxAttributionAggregatableKeysPerSourceOrTrigger)
     return false;
 
@@ -169,22 +172,18 @@
   aggregation_keys.ReserveCapacityForSize(num_keys);
 
   for (wtf_size_t i = 0; i < num_keys; ++i) {
-    JSONValue* value = array->at(i);
+    JSONObject::Entry entry = object->at(i);
+    String key_id = entry.first;
+    JSONValue* value = entry.second;
     DCHECK(value);
 
-    const auto* object = JSONObject::Cast(value);
-    if (!object)
-      return false;
-
-    String key_id;
-    if (!object->GetString("id", &key_id) ||
-        key_id.CharactersSizeInBytes() >
-            kMaxBytesPerAttributionAggregatableKeyId) {
+    if (key_id.CharactersSizeInBytes() >
+        kMaxBytesPerAttributionAggregatableKeyId) {
       return false;
     }
 
     absl::uint128 key;
-    if (!ParseAttributionAggregatableKey(object, &key))
+    if (!ParseAttributionAggregatableKey(value, &key))
       return false;
 
     aggregation_keys.insert(std::move(key_id), key);
@@ -397,7 +396,7 @@
 
     auto data = mojom::blink::AttributionAggregatableTriggerData::New();
 
-    if (!ParseAttributionAggregatableKey(object, &data->key))
+    if (!ParseAttributionAggregatableKey(object->Get("key_piece"), &data->key))
       return false;
 
     JSONArray* source_keys_val = object->GetArray("source_keys");
diff --git a/third_party/blink/renderer/core/frame/attribution_response_parsing_test.cc b/third_party/blink/renderer/core/frame/attribution_response_parsing_test.cc
index 5391c456..d7b1afa 100644
--- a/third_party/blink/renderer/core/frame/attribution_response_parsing_test.cc
+++ b/third_party/blink/renderer/core/frame/attribution_response_parsing_test.cc
@@ -90,33 +90,21 @@
   } kTestCases[] = {
       {"Empty header", "", false, {}},
       {"Invalid JSON", "{", false, {}},
-      {"Not an array", "{}", false, {}},
-      {"Element not a dictionary", R"([123])", false, {}},
-      {"Missing id field", R"([{"key_piece":"0x159"}])", false, {}},
-      {"id not a string", R"([{"id":123}])", false, {}},
-      {"Missing key_piece field", R"([{"id":"key"}])", false, {}},
-      {"key_piece not a string",
-       R"([{"id":"key","key_piece":123}])",
-       false,
-       {}},
-      {"Invalid key", R"([{"id":"key","key_piece":"0xG59"}])", false, {}},
+      {"Not a dictionary", "[]", false, {}},
+      {"key not a string", R"({"key":123})", false, {}},
+      {"Invalid key", R"({"key":"0xG59"})", false, {}},
       {"One valid key",
-       R"([{"id":"key","key_piece":"0x159"}])",
+       R"({"key":"0x159"})",
        true,
        {{"key", absl::MakeUint128(/*high=*/0, /*low=*/345)}}},
       {"Two valid keys",
-       R"([{"id":"key1","key_piece":"0x159"},
-           {"id":"key2","key_piece":"0x50000000000000159"}])",
+       R"({"key1":"0x159","key2":"0x50000000000000159"})",
        true,
        {
            {"key1", absl::MakeUint128(/*high=*/0, /*low=*/345)},
            {"key2", absl::MakeUint128(/*high=*/5, /*low=*/345)},
        }},
-      {"Second key invalid",
-       R"([{"id":"key1","key_piece":"0x159"},
-           {"id":"key2","key_piece":""}])",
-       false,
-       {}},
+      {"Second key invalid", R"({"key1":"0x159","key2":""})", false, {}},
   };
 
   for (const auto& test_case : kTestCases) {
@@ -137,14 +125,11 @@
     wtf_size_t key_size;
 
     String GetHeader() const {
-      JSONArray array;
+      JSONObject object;
       for (wtf_size_t i = 0u; i < key_count; ++i) {
-        auto object = std::make_unique<JSONObject>();
-        object->SetString("key_piece", "0x1");
-        object->SetString("id", GetKey(i));
-        array.PushObject(std::move(object));
+        object.SetString(GetKey(i), "0x1");
       }
-      return array.ToJSONString();
+      return object.ToJSONString();
     }
 
     WTF::HashMap<String, absl::uint128> GetAggregationKeys() const {
@@ -1227,14 +1212,11 @@
 
 TEST(AttributionResponseParsingTest, SourceAggregatableKeysHistogram) {
   const auto make_aggregatable_source_with_keys = [](wtf_size_t n) {
-    JSONArray array;
+    JSONObject object;
     for (wtf_size_t i = 0; i < n; ++i) {
-      auto object = std::make_unique<JSONObject>();
-      object->SetString("id", String::Number(i));
-      object->SetString("key_piece", "0x1");
-      array.PushObject(std::move(object));
+      object.SetString(String::Number(i), "0x1");
     }
-    return array.ToJSONString();
+    return object.ToJSONString();
   };
 
   const struct {
diff --git a/third_party/blink/renderer/core/frame/attribution_src/attribution_aggregatable_source_registration_corpus/all_params.textproto b/third_party/blink/renderer/core/frame/attribution_src/attribution_aggregatable_source_registration_corpus/all_params.textproto
index c667cba..84e0485d7 100644
--- a/third_party/blink/renderer/core/frame/attribution_src/attribution_aggregatable_source_registration_corpus/all_params.textproto
+++ b/third_party/blink/renderer/core/frame/attribution_src/attribution_aggregatable_source_registration_corpus/all_params.textproto
@@ -1,41 +1,17 @@
-array_value {
-  value {
-    object_value {
-      field {
-        name: "id"
-        value {
-          string_value {
-            value: "a"
-          }
-        }
-      }
-      field {
-        name: "key_piece"
-        value {
-          string_value {
-            value: "0x1"
-          }
-        }
+object_value {
+  field {
+    name: "a"
+    value {
+      string_value {
+        value: "0x1"
       }
     }
   }
-  value {
-    object_value {
-      field {
-        name: "id"
-        value {
-          string_value {
-            value: "b"
-          }
-        }
-      }
-      field {
-        name: "key_piece"
-        value {
-          string_value {
-            value: "0x11"
-          }
-        }
+  field {
+    name: "b"
+    value {
+      string_value {
+        value: "0x11"
       }
     }
   }
diff --git a/third_party/blink/renderer/core/html/forms/file_chooser.cc b/third_party/blink/renderer/core/html/forms/file_chooser.cc
index cbf940f5..b0b75f7d 100644
--- a/third_party/blink/renderer/core/html/forms/file_chooser.cc
+++ b/third_party/blink/renderer/core/html/forms/file_chooser.cc
@@ -78,8 +78,7 @@
     return false;
   chrome_client_impl_ = chrome_client_impl;
   frame->GetBrowserInterfaceBroker().GetInterface(
-      file_chooser_.BindNewPipeAndPassReceiver(
-          frame->GetTaskRunner(TaskType::kInternalDefault)));
+      file_chooser_.BindNewPipeAndPassReceiver());
   file_chooser_.set_disconnect_handler(
       WTF::Bind(&FileChooser::DidCloseChooser, WTF::Unretained(this)));
   file_chooser_->OpenFileChooser(
@@ -99,8 +98,7 @@
     return;
   DCHECK(!chrome_client_impl_);
   frame->GetBrowserInterfaceBroker().GetInterface(
-      file_chooser_.BindNewPipeAndPassReceiver(
-          frame->GetTaskRunner(TaskType::kInternalDefault)));
+      file_chooser_.BindNewPipeAndPassReceiver());
   file_chooser_.set_disconnect_handler(
       WTF::Bind(&FileChooser::DidCloseChooser, WTF::Unretained(this)));
   file_chooser_->EnumerateChosenDirectory(
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
index 434982e..544f400 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -606,11 +606,17 @@
 }
 
 static void* OpenFunc(const char* uri) {
-  DCHECK(XMLDocumentParserScope::current_document_);
+  Document* document = XMLDocumentParserScope::current_document_;
+  DCHECK(document);
   DCHECK_EQ(CurrentThread(), g_libxml_loader_thread);
 
   KURL url(NullURL(), uri);
 
+  // If the document has no ExecutionContext, it's detached. Detached documents
+  // aren't allowed to fetch.
+  if (!document->GetExecutionContext())
+    return &g_global_descriptor;
+
   if (!ShouldAllowExternalLoad(url))
     return &g_global_descriptor;
 
@@ -618,7 +624,6 @@
   scoped_refptr<const SharedBuffer> data;
 
   {
-    Document* document = XMLDocumentParserScope::current_document_;
     XMLDocumentParserScope scope(nullptr);
     // FIXME: We should restore the original global error handler as well.
     ResourceLoaderOptions options(
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 0e87bee..8bef4c5d 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -715,6 +715,8 @@
   if (allow_vea_encoder &&
       CanUseAcceleratedEncoder(codec_profile.codec_id, input_size.width(),
                                input_size.height())) {
+    // TODO(b/227350897): remove once codec histogram is verified working
+    UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", true);
     UmaHistogramForCodec(true, codec_profile.codec_id);
 
     const auto vea_profile =
@@ -733,6 +735,8 @@
         bits_per_second, vea_profile, codec_profile.level, input_size,
         use_import_mode, main_task_runner_);
   } else {
+    // TODO(b/227350897): remove once codec histogram is verified working
+    UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", false);
     UmaHistogramForCodec(false, codec_profile.codec_id);
     switch (codec_profile.codec_id) {
 #if BUILDFLAG(RTC_USE_H264)
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
index befbb40a..4650bea6 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context.cc
@@ -169,11 +169,6 @@
 }
 
 void WebGLRenderingContext::RegisterContextExtensions() {
-  // Register extensions.
-  static const char* const kBothPrefixes[] = {
-      "", "WEBKIT_", nullptr,
-  };
-
   RegisterExtension(angle_instanced_arrays_);
   RegisterExtension(ext_blend_min_max_);
   RegisterExtension(ext_color_buffer_half_float_);
@@ -185,8 +180,7 @@
   RegisterExtension(ext_shader_texture_lod_);
   RegisterExtension(ext_texture_compression_bptc_);
   RegisterExtension(ext_texture_compression_rgtc_);
-  RegisterExtension(ext_texture_filter_anisotropic_, kApprovedExtension,
-                    kBothPrefixes);
+  RegisterExtension(ext_texture_filter_anisotropic_, kApprovedExtension);
   RegisterExtension(exts_rgb_);
   RegisterExtension(khr_parallel_shader_compile_);
   RegisterExtension(oes_element_index_uint_);
@@ -201,16 +195,14 @@
   RegisterExtension(webgl_compressed_texture_astc_);
   RegisterExtension(webgl_compressed_texture_etc_);
   RegisterExtension(webgl_compressed_texture_etc1_);
-  RegisterExtension(webgl_compressed_texture_pvrtc_, kApprovedExtension,
-                    kBothPrefixes);
-  RegisterExtension(webgl_compressed_texture_s3tc_, kApprovedExtension,
-                    kBothPrefixes);
+  RegisterExtension(webgl_compressed_texture_pvrtc_, kApprovedExtension);
+  RegisterExtension(webgl_compressed_texture_s3tc_, kApprovedExtension);
   RegisterExtension(webgl_compressed_texture_s3tc_srgb_);
   RegisterExtension(webgl_debug_renderer_info_);
   RegisterExtension(webgl_debug_shaders_);
-  RegisterExtension(webgl_depth_texture_, kApprovedExtension, kBothPrefixes);
+  RegisterExtension(webgl_depth_texture_, kApprovedExtension);
   RegisterExtension(webgl_draw_buffers_);
-  RegisterExtension(webgl_lose_context_, kApprovedExtension, kBothPrefixes);
+  RegisterExtension(webgl_lose_context_, kApprovedExtension);
   RegisterExtension(webgl_multi_draw_);
   RegisterExtension(webgl_video_texture_, kDraftExtension);
   RegisterExtension(webgl_webcodecs_video_frame_, kDraftExtension);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index f15f260..585419a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -3201,23 +3201,10 @@
   return ContextGL()->GetError();
 }
 
-const char* const* WebGLRenderingContextBase::ExtensionTracker::Prefixes()
-    const {
-  static const char* const kUnprefixed[] = {
-      "",
-      nullptr,
-  };
-  return prefixes_ ? prefixes_ : kUnprefixed;
-}
-
-bool WebGLRenderingContextBase::ExtensionTracker::MatchesNameWithPrefixes(
+bool WebGLRenderingContextBase::ExtensionTracker::MatchesName(
     const String& name) const {
-  const char* const* prefix_set = Prefixes();
-  for (; *prefix_set; ++prefix_set) {
-    String prefixed_name = String(*prefix_set) + ExtensionName();
-    if (DeprecatedEqualIgnoringCase(prefixed_name, name)) {
-      return true;
-    }
+  if (DeprecatedEqualIgnoringCase(ExtensionName(), name)) {
+    return true;
   }
   return false;
 }
@@ -3256,7 +3243,7 @@
 
   if (!isContextLost()) {
     for (ExtensionTracker* tracker : extensions_) {
-      if (tracker->MatchesNameWithPrefixes(name)) {
+      if (tracker->MatchesName(name)) {
         if (ExtensionSupportedAndAllowed(tracker)) {
           extension = tracker->GetExtension(this);
           if (extension) {
@@ -3995,11 +3982,7 @@
 
   for (ExtensionTracker* tracker : extensions_) {
     if (ExtensionSupportedAndAllowed(tracker)) {
-      const char* const* prefixes = tracker->Prefixes();
-      for (; *prefixes; ++prefixes) {
-        String prefixed_name = String(*prefixes) + tracker->ExtensionName();
-        result.push_back(prefixed_name);
-      }
+      result.push_back(tracker->ExtensionName());
     }
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 895af18c..bc1235e 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -949,17 +949,15 @@
   class ExtensionTracker : public GarbageCollected<ExtensionTracker>,
                            public NameClient {
    public:
-    ExtensionTracker(ExtensionFlags flags, const char* const* prefixes)
+    explicit ExtensionTracker(ExtensionFlags flags)
         : draft_(flags & kDraftExtension),
-          developer_(flags & kDeveloperExtension),
-          prefixes_(prefixes) {}
+          developer_(flags & kDeveloperExtension) {}
     ~ExtensionTracker() override = default;
 
     bool Draft() const { return draft_; }
     bool Developer() const { return developer_; }
 
-    const char* const* Prefixes() const;
-    bool MatchesNameWithPrefixes(const String&) const;
+    bool MatchesName(const String&) const;
 
     virtual WebGLExtension* GetExtension(WebGLRenderingContextBase*) = 0;
     virtual bool Supported(WebGLRenderingContextBase*) const = 0;
@@ -977,17 +975,13 @@
    private:
     bool draft_;
     bool developer_;
-    const char* const* prefixes_;
   };
 
   template <typename T>
   class TypedExtensionTracker final : public ExtensionTracker {
    public:
-    TypedExtensionTracker(Member<T>& extension_field,
-                          ExtensionFlags flags,
-                          const char* const* prefixes)
-        : ExtensionTracker(flags, prefixes),
-          extension_field_(extension_field) {}
+    TypedExtensionTracker(Member<T>& extension_field, ExtensionFlags flags)
+        : ExtensionTracker(flags), extension_field_(extension_field) {}
 
     WebGLExtension* GetExtension(WebGLRenderingContextBase* context) override {
       if (!extension_) {
@@ -1034,10 +1028,9 @@
 
   template <typename T>
   void RegisterExtension(Member<T>& extension_ptr,
-                         ExtensionFlags flags = kApprovedExtension,
-                         const char* const* prefixes = nullptr) {
-    extensions_.push_back(MakeGarbageCollected<TypedExtensionTracker<T>>(
-        extension_ptr, flags, prefixes));
+                         ExtensionFlags flags = kApprovedExtension) {
+    extensions_.push_back(
+        MakeGarbageCollected<TypedExtensionTracker<T>>(extension_ptr, flags));
   }
 
   bool ExtensionSupportedAndAllowed(const ExtensionTracker*);
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
index 556396d7..0df1828 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_index_format.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_load_op.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_pipeline_statistic_name.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_predefined_color_space.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_primitive_topology.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_query_type.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_sampler_binding_type.h"
@@ -32,6 +31,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_dimension.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_format.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_step_mode.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 
 namespace blink {
 
@@ -433,11 +433,12 @@
   }
 }
 
-WGPUPredefinedColorSpace AsDawnEnum(
-    const V8GPUPredefinedColorSpace& webgpu_enum) {
-  switch (webgpu_enum.AsEnum()) {
-    case V8GPUPredefinedColorSpace::Enum::kSRGB:
+WGPUPredefinedColorSpace AsDawnEnum(PredefinedColorSpace color_space) {
+  switch (color_space) {
+    case PredefinedColorSpace::kSRGB:
       return WGPUPredefinedColorSpace_Srgb;
+    default:
+      return WGPUPredefinedColorSpace_Undefined;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h
index c6fe91b8..1d55520 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h
+++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.h
@@ -21,7 +21,6 @@
 class V8GPULoadOp;
 class V8GPUFeatureName;
 class V8GPUIndexFormat;
-class V8GPUPredefinedColorSpace;
 class V8GPUPrimitiveTopology;
 class V8GPUBlendFactor;
 class V8GPUBlendOperation;
@@ -33,6 +32,7 @@
 class V8GPUFrontFace;
 class V8GPUTextureAspect;
 class V8GPUErrorFilter;
+enum class PredefinedColorSpace;
 
 // Convert WebGPU bitfield values to Dawn enums. These have the same value.
 template <typename DawnFlags>
@@ -60,8 +60,6 @@
 WGPUStoreOp AsDawnEnum(const V8GPUStoreOp& webgpu_enum);
 WGPULoadOp AsDawnEnum(const V8GPULoadOp& webgpu_enum);
 WGPUIndexFormat AsDawnEnum(const V8GPUIndexFormat& webgpu_enum);
-WGPUPredefinedColorSpace AsDawnEnum(
-    const V8GPUPredefinedColorSpace& webgpu_enum);
 WGPUFeatureName AsDawnEnum(const V8GPUFeatureName& webgpu_enum);
 WGPUPrimitiveTopology AsDawnEnum(const V8GPUPrimitiveTopology& webgpu_enum);
 WGPUBlendFactor AsDawnEnum(const V8GPUBlendFactor& webgpu_enum);
@@ -74,7 +72,7 @@
 WGPUFrontFace AsDawnEnum(const V8GPUFrontFace& webgpu_enum);
 WGPUTextureAspect AsDawnEnum(const V8GPUTextureAspect& webgpu_enum);
 WGPUErrorFilter AsDawnEnum(const V8GPUErrorFilter& webgpu_enum);
-
+WGPUPredefinedColorSpace AsDawnEnum(PredefinedColorSpace color_space);
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_DAWN_ENUM_CONVERSIONS_H_
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_configuration.idl b/third_party/blink/renderer/modules/webgpu/gpu_canvas_configuration.idl
index 5f29ac9..f221f5c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_configuration.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_configuration.idl
@@ -14,7 +14,7 @@
     required GPUTextureFormat format;
     GPUTextureUsageFlags usage = 16;  // GPUTextureUsage.RENDER_ATTACHMENT
     sequence<GPUTextureFormat> viewFormats = [];
-    GPUPredefinedColorSpace colorSpace = "srgb";
+    PredefinedColorSpace colorSpace = "srgb";
     GPUCanvasAlphaMode alphaMode;
 
     // TODO(crbug.com/1069302): Remove the following after a deprecation period.
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index 7efb175..5ba2733 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -231,10 +231,15 @@
     return;
   }
 
-  // Once colorSpaces other than sRGB are defined, we'll need to ensure they're
-  // supported here.
-  DCHECK_EQ(AsDawnEnum(descriptor->colorSpace()),
-            WGPUPredefinedColorSpace_Srgb);
+  // TODO(crbug.com/1241375): Support additional color spaces for external
+  // textures.
+  if (descriptor->colorSpace().AsEnum() !=
+      V8PredefinedColorSpace::Enum::kSRGB) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kOperationError,
+        "colorSpace !== 'srgb' isn't supported yet.");
+    return;
+  }
 
   // Set the size while configuring.
   if (descriptor->hasSize()) {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
index 10af7db..a41405e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_htmlvideoelement_videoframe.h"
 #include "third_party/blink/renderer/core/dom/scripted_animation_controller.h"
+#include "third_party/blink/renderer/core/html/canvas/predefined_color_space.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
@@ -18,6 +19,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_supported_features.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture_view.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
@@ -183,13 +185,27 @@
     ExceptionState& exception_state) {
   DCHECK(media_video_frame);
 
-  gfx::ColorSpace srcColorSpace = media_video_frame->ColorSpace();
-  gfx::ColorSpace dstColorSpace;
-  switch (webgpu_desc->colorSpace().AsEnum()) {
-    case V8GPUPredefinedColorSpace::Enum::kSRGB:
-      dstColorSpace = gfx::ColorSpace::CreateSRGB();
+  // TODO(crbug.com/1330250): Support additional color spaces for external
+  // textures.
+  if (webgpu_desc->colorSpace().AsEnum() !=
+      V8PredefinedColorSpace::Enum::kSRGB) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kOperationError,
+        "colorSpace !== 'srgb' isn't supported yet.");
+    return nullptr;
   }
 
+  PredefinedColorSpace dst_predefined_color_space;
+  if (!ValidateAndConvertColorSpace(webgpu_desc->colorSpace(),
+                                    dst_predefined_color_space,
+                                    exception_state)) {
+    return nullptr;
+  }
+
+  gfx::ColorSpace srcColorSpace = media_video_frame->ColorSpace();
+  gfx::ColorSpace dstColorSpace =
+      PredefinedColorSpaceToGfxColorSpace(dst_predefined_color_space);
+
   // TODO(crbug.com/1306753): Use SharedImageProducer and CompositeSharedImage
   // rather than check 'is_webgpu_compatible'.
   bool device_support_zero_copy =
@@ -221,7 +237,7 @@
     WGPUExternalTextureDescriptor external_texture_desc = {};
     external_texture_desc.plane0 = plane0;
     external_texture_desc.plane1 = plane1;
-    external_texture_desc.colorSpace = AsDawnEnum(webgpu_desc->colorSpace());
+    external_texture_desc.colorSpace = AsDawnEnum(dst_predefined_color_space);
 
     std::array<float, 12> yuvToRgbMatrix =
         GetYUVToRGBMatrix(srcColorSpace, media_video_frame->BitDepth());
@@ -310,7 +326,7 @@
 
   WGPUExternalTextureDescriptor dawn_desc = {};
   dawn_desc.plane0 = plane0;
-  dawn_desc.colorSpace = AsDawnEnum(webgpu_desc->colorSpace());
+  dawn_desc.colorSpace = AsDawnEnum(dst_predefined_color_space);
 
   ColorSpaceConversionConstants colorSpaceConversionConstants =
       GetColorSpaceConversionConstants(srcColorSpace, dstColorSpace);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
index a54804c..d278c3c5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture_descriptor.idl
@@ -6,5 +6,5 @@
 
 dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase {
     required (HTMLVideoElement or VideoFrame) source;
-    GPUPredefinedColorSpace colorSpace = "srgb";
+    PredefinedColorSpace colorSpace = "srgb";
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture_tagged.idl b/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture_tagged.idl
index 79d2303..7c69a552 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture_tagged.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_image_copy_texture_tagged.idl
@@ -4,11 +4,7 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-enum GPUPredefinedColorSpace {
-    "srgb"
-};
-
 dictionary GPUImageCopyTextureTagged : GPUImageCopyTexture  {
-    GPUPredefinedColorSpace colorSpace = "srgb";
+    PredefinedColorSpace colorSpace = "srgb";
     boolean premultipliedAlpha = false;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
index eb22d92..e2a9933 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h"
 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
+#include "third_party/blink/renderer/core/html/canvas/predefined_color_space.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
@@ -99,17 +100,6 @@
   }
 }
 
-PredefinedColorSpace GetPredefinedColorSpace(
-    WGPUPredefinedColorSpace color_space) {
-  switch (color_space) {
-    case WGPUPredefinedColorSpace_Srgb:
-      return PredefinedColorSpace::kSRGB;
-    default:
-      NOTREACHED();
-      return PredefinedColorSpace::kSRGB;
-  }
-}
-
 WGPUTextureFormat SkColorTypeToDawnColorFormat(SkColorType sk_color_type) {
   switch (sk_color_type) {
     case SkColorType::kRGBA_8888_SkColorType:
@@ -512,6 +502,12 @@
     return;
   }
 
+  PredefinedColorSpace color_space;
+  if (!ValidateAndConvertColorSpace(destination->colorSpace(), color_space,
+                                    exception_state)) {
+    return;
+  }
+
   // Issue the noop copy to continue validation to destination textures
   if (dawn_copy_size.width == 0 || dawn_copy_size.height == 0 ||
       dawn_copy_size.depthOrArrayLayers == 0) {
@@ -520,13 +516,10 @@
         "({width|height|depthOrArrayLayers} equals to 0).");
   }
 
-  WGPUPredefinedColorSpace dawn_predefined_color_space =
-      AsDawnEnum(destination->colorSpace());
-
   if (!UploadContentToTexture(
           static_bitmap_image.get(), origin_in_external_image, dawn_copy_size,
-          dawn_destination, destination->premultipliedAlpha(),
-          dawn_predefined_color_space, copyImage->flipY())) {
+          dawn_destination, destination->premultipliedAlpha(), color_space,
+          copyImage->flipY())) {
     exception_state.ThrowTypeError(
         "Failed to copy content from external image.");
     return;
@@ -538,7 +531,7 @@
                                       const WGPUExtent3D& copy_size,
                                       const WGPUImageCopyTexture& destination,
                                       bool dst_premultiplied_alpha,
-                                      WGPUPredefinedColorSpace dst_color_space,
+                                      PredefinedColorSpace dst_color_space,
                                       bool flipY) {
   PaintImage paint_image = image->PaintImageForCurrentFrame();
   SkColorType source_color_type = paint_image.GetSkImageInfo().colorType();
@@ -572,8 +565,8 @@
   if (sk_src_color_space == nullptr) {
     sk_src_color_space = SkColorSpace::MakeSRGB();
   }
-  sk_sp<SkColorSpace> sk_dst_color_space = PredefinedColorSpaceToSkColorSpace(
-      GetPredefinedColorSpace(dst_color_space));
+  sk_sp<SkColorSpace> sk_dst_color_space =
+      PredefinedColorSpaceToSkColorSpace(dst_color_space);
   std::array<float, 7> gamma_decode_params;
   std::array<float, 7> gamma_encode_params;
   std::array<float, 9> conversion_matrix;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.h b/third_party/blink/renderer/modules/webgpu/gpu_queue.h
index f3bbaf4e..428bfab 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.h
@@ -84,7 +84,7 @@
                               const WGPUExtent3D& copy_size,
                               const WGPUImageCopyTexture& destination,
                               bool dst_premultiplied_alpha,
-                              WGPUPredefinedColorSpace dst_color_space,
+                              PredefinedColorSpace dst_color_space,
                               bool flipY);
   void WriteBufferImpl(GPUBuffer* buffer,
                        uint64_t buffer_offset,
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 3b0a432..dca6254 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3345,6 +3345,27 @@
 crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac10.15 ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac11 ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac12 ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac12-arm64 ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-ruby/intra-base-white-space-001.html [ Failure ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/fetch/api/basic/request-upload.h2.any.worker.html [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/loading/early-hints/coep-early-hints-none-final-require-corp.h2.window.html [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/loading/early-hints/iframe-pdf.h2.window.html [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/loading/early-hints/preconnect-in-early-hints.h2.window.html [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Close-1000-reason.any.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Close-2999-reason.any.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Close-delayed.any.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Create-valid-url-protocol-string.any.worker.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Create-valid-url-protocol.any.worker.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Send-0byte-data.any.worker.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/Send-unpaired-surrogates.any.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/cookies/003.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html?wpt_flags=h2 [ Timeout ]
+crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/interfaces/WebSocket/send/009.html?wpt_flags=h2 [ Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html?pen [ Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/fetch/private-network-access/fetch.window.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/content-security-policy/wasm-unsafe-eval/postMessage-wasm-module.html [ Timeout ]
@@ -6248,12 +6269,17 @@
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-021.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-025.html [ Failure ]
 crbug.com/1249176 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-004.html [ Failure Pass ]
+crbug.com/1249176 [ Mac11-arm64 ] compositing/overflow/rotate-clip.html [ Failure ]
+crbug.com/1249176 [ Mac12-arm64 ] compositing/overflow/rotate-clip.html [ Failure ]
+crbug.com/1249176 [ Mac11-arm64 ] compositing/overflow/rotate-then-clip.html [ Failure ]
+crbug.com/1249176 [ Mac12-arm64 ] compositing/overflow/rotate-then-clip.html [ Failure ]
+crbug.com/1249176 [ Mac11-arm64 ] media/video-replaces-poster.html [ Skip ]
+crbug.com/1249176 [ Mac12-arm64 ] media/video-replaces-poster.html [ Skip ]
+crbug.com/1249176 [ Mac11-arm64 ] virtual/gpu-rasterization/images/color-jpeg-with-color-profile.html [ Failure ]
+crbug.com/1249176 [ Mac12-arm64 ] virtual/gpu-rasterization/images/color-jpeg-with-color-profile.html [ Failure ]
 
 # Failures that surfaced on the mac12-arm64 waterfall
-crbug.com/1249176 [ Mac12-arm64 ] compositing/overflow/rotate-clip.html [ Failure ]
-crbug.com/1249176 [ Mac12-arm64 ] compositing/overflow/rotate-then-clip.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] media/color-profile-video-seek.html [ Failure ]
-crbug.com/1249176 [ Mac12-arm64 ] media/video-replaces-poster.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] media/video-zoom.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] paint/markers/suggestion-marker-basic.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] virtual/exotic-color-space/images/color-profile-background-image-cover.html [ Failure ]
@@ -6270,7 +6296,6 @@
 crbug.com/1249176 [ Mac12-arm64 ] virtual/exotic-color-space/images/yuv-decode-eligible/color-profile-layer.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] virtual/exotic-color-space/images/yuv-decode-eligible/webp-color-profile-lossy.html [ Failure ]
 crbug.com/1249176 [ Mac12-arm64 ] virtual/exotic-color-space/images/yuv-decode-eligible/webp-no-color-profile-lossy.html [ Failure ]
-crbug.com/1249176 [ Mac12-arm64 ] virtual/gpu-rasterization/images/color-jpeg-with-color-profile.html [ Failure ]
 
 # Flakes that surfaced on the mac12 and mac12-arm64 waterfall
 crbug.com/1249176 [ Mac12 ] external/wpt/html/browsers/browsing-the-web/back-forward-cache/service-worker-controlled-after-restore.https.html [ Failure Pass ]
@@ -7066,6 +7091,10 @@
 crbug.com/1325307 fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html [ Skip ]
 crbug.com/1325307 fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html [ Skip ]
 
+# suppress geolocation failures
+crbug.com/1330988 http/tests/geolocation-api/geolocation-default-feature-policy.https.sub.html [ Failure ]
+crbug.com/1330988 http/tests/security/powerfulFeatureRestrictions/geolocation-on-secure-origin-in-secure-origin.html [ Failure ]
+
 # Sheriff 2022-05-30
 crbug.com/1330238 [ Mac ] http/tests/devtools/elements/styles-3/styles-computed-trace.js [ Failure Pass Timeout ]
 
@@ -7073,10 +7102,10 @@
 crbug.com/1330300 fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html [ Pass Timeout ]
 
 # Sheriff 2022-05-31
-crbug.com/1330555 external/wpt/service-workers/service-worker/resource-timing-fetch-variants.https.html [ Pass Failure ]
+crbug.com/1330555 external/wpt/service-workers/service-worker/resource-timing-fetch-variants.https.html [ Failure Pass ]
 
 # fast/canvas/OffscreenCanvas-2d-drawImage.html
-crbug.com/1273409 [ Mac11 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ]
-crbug.com/1273409 [ Mac11-arm64 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ]
-crbug.com/1273409 [ Linux ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ]
-crbug.com/1273409 [ Win10.20h2 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ]
+crbug.com/1273409 [ Mac11 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Failure Pass ]
+crbug.com/1273409 [ Mac11-arm64 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Failure Pass ]
+crbug.com/1273409 [ Linux ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Failure Pass ]
+crbug.com/1273409 [ Win10.20h2 ] fast/canvas/OffscreenCanvas-2d-drawImage.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 1870067..8598d39 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -427,7 +427,9 @@
               "http/tests/inspector-protocol",
               "http/tests/origin_trials",
               "http/tests/workers",
-              "inspector-protocol/worker"],
+              "inspector-protocol/worker",
+              "wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html"
+            ],
     "args": ["--enable-features=PlzDedicatedWorker"]
   },
   {
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version
index d1bc72e..b333b84 100644
--- a/third_party/blink/web_tests/external/Version
+++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@
-Version: fecd856ffe33aac9d46231b70d1768feebc87dfe
+Version: e66c00f9f6c2fead2cc2516aa1ab792245b483c2
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index b3a8437..0130c62 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -3241,6 +3241,20 @@
        {}
       ]
      ],
+     "delete-in-dd-editing-host-after-selectall-with-focus.html": [
+      "585cd17bb82d8b763168cb14b52fe7d18ec457aa",
+      [
+       null,
+       {}
+      ]
+     ],
+     "delete-in-dd-editing-host-after-selectall-without-focus.html": [
+      "a45f2dad821074ac860579c60b3655eec96fc97b",
+      [
+       null,
+       {}
+      ]
+     ],
      "delete-in-empty-editable-list-followed-by-non-editable-listitem.html": [
       "9e872f5ac47a1f6bda848dfe4b61efcf6679a966",
       [
@@ -3290,6 +3304,20 @@
        {}
       ]
      ],
+     "forwarddelete-in-list-editing-host-after-selectall-with-focus.html": [
+      "266cc4fb600227ed134c062d6c01cf52a9f1abed",
+      [
+       null,
+       {}
+      ]
+     ],
+     "forwarddelete-in-list-editing-host-after-selectall-without-focus.html": [
+      "de10e8b8a9716bfd1b3c34be23cff17aad107f0a",
+      [
+       null,
+       {}
+      ]
+     ],
      "forwarddelete-in-text-in-span-in-editable-documentElement.html": [
       "26f2f64b81f1e2b02496c6131cc58cf2460c2d5a",
       [
@@ -3444,6 +3472,13 @@
        {}
       ]
      ],
+     "move-editing-host-to-subdocument-when-textarea-has-focus.html": [
+      "b7d2e2f90270f96e063c1871d8b3e9cdec328bfc",
+      [
+       null,
+       {}
+      ]
+     ],
      "move-legend-followed-by-textarea-into-orphan-div.html": [
       "462ff37fd628fcd3e807b535befc13268ad14c6e",
       [
@@ -152008,6 +152043,19 @@
        {}
       ]
      ],
+     "intra-base-white-space-001.html": [
+      "86468376c3211db6dbe6e8fa53b6186b4214af34",
+      [
+       null,
+       [
+        [
+         "/css/css-ruby/reference/intra-base-white-space-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "nested-ruby-pairing-001.html": [
       "d502dbca9b2d4c8a6e47668a2158a3f4d0995105",
       [
@@ -229526,6 +229574,19 @@
       ],
       {}
      ]
+    ],
+    "forced-colors-mode-53.html": [
+     "4726c4bb0a5524f3c8319863511939cb9fd26b88",
+     [
+      null,
+      [
+       [
+        "/forced-colors-mode/forced-colors-mode-53-ref.html",
+        "=="
+       ]
+      ],
+      {}
+     ]
     ]
    },
    "html": {
@@ -235237,7 +235298,7 @@
       },
       "the-selectmenu-element": {
        "selectmenu-option-arbitrary-content-displayed.tentative.html": [
-        "047236bde27a4c4f1f611235e884765797e18cc6",
+        "d32ea7c6d3606dd58f57180575bda5c5189879db",
         [
          null,
          [
@@ -236237,7 +236298,7 @@
      },
      "popups": {
       "popup-backdrop-appearance.tentative.html": [
-       "7dcd401b4c92381dd4aca796378d1b3d32836f7c",
+       "0b348f85d0103c36ea71e6c7f420df3709c0bb9b",
        [
         null,
         [
@@ -236250,7 +236311,7 @@
        ]
       ],
       "popup-defaultopen-display.tentative.html": [
-       "179e07189b31ec4b97ef3aa6ca61765388b781f8",
+       "562137ab56bd5970ddcf52de339bc5586a2ec5b9",
        [
         null,
         [
@@ -236263,7 +236324,7 @@
        ]
       ],
       "popup-hidden-display.tentative.html": [
-       "6ca84dc106be7cb9730d9968efa3c73563a46e71",
+       "2bd2dc473894bd50f417e7a15ab4d31bc83abe68",
        [
         null,
         [
@@ -236276,7 +236337,7 @@
        ]
       ],
       "popup-inside-display-none.tentative.html": [
-       "2230d77a3d9c4a815b313685dd3d5073f5041cea",
+       "c93bf163d93b799abd23fd3226850ec2c9b89793",
        [
         null,
         [
@@ -236289,7 +236350,7 @@
        ]
       ],
       "popup-open-display.tentative.html": [
-       "c14997be4ffd97c57176fff152bd5b70466efe16",
+       "674af1902d943dcb84ab97dda5c9f60f1796e941",
        [
         null,
         [
@@ -236302,7 +236363,7 @@
        ]
       ],
       "popup-open-overflow-display.tentative.html": [
-       "5d4a13987e395be0d9aa49d0bdbaf6df7445a340",
+       "32f42dfcea2f04611ec1b74d944897433bc87f51",
        [
         null,
         [
@@ -236315,7 +236376,7 @@
        ]
       ],
       "popup-stacking-context.tentative.html": [
-       "b38cfe4dc4f35b3f12bf0074e6b5be304ed2c58a",
+       "f3fd0bf2fa992c5b36f5d5f0b1896eb7f7695ac2",
        [
         null,
         [
@@ -251814,7 +251875,7 @@
       []
      ],
      "fedcm-helper.js": [
-      "428a2fc847708377594817cb01d7a009cc43a35c",
+      "1017427c5c28f582c92ba356af2153e4f9851a84",
       []
      ],
      "fedcm-mock.js": [
@@ -280628,6 +280689,10 @@
        "72a55541bcba241cdced59588e46118a40c8528c",
        []
       ],
+      "intra-base-white-space-001-ref.html": [
+       "4615b53ea745212373844aa82ad84eb14dd747a5",
+       []
+      ],
       "rb-display-001-ref.html": [
        "f8ed4022bcca8be6dc4b0de2a5cc4d7897e16c86",
        []
@@ -295044,14 +295109,6 @@
       []
      ]
     },
-    "tools": {
-     "_virtualenv": {
-      ".gitignore": [
-       "ede80b85f0f30f7d19ce1a46d6b421fac3c1f82f",
-       []
-      ]
-     }
-    },
     "vendor-imports": {
      "mozilla": {
       "mozilla-central-reftests": {
@@ -299424,7 +299481,7 @@
         []
        ],
        "header-refresh.optional.sub.html": [
-        "ff497b5915b969b9226521e11eee91dd5dabf2eb",
+        "ec963d5cc002a978bd38e6a8c3428428af8bf990",
         []
        ],
        "script-module-import-dynamic.sub.html": [
@@ -299714,7 +299771,7 @@
     },
     "script-tests": {
      "FileSystemBaseHandle-remove.js": [
-      "2306bde7cdb87b6e893a92389200ce4fa7fe36ec",
+      "95196db62b3c8b884dedcc5cf4427cb68721dd51",
       []
      ],
      "FileSystemDirectoryHandle-move.js": [
@@ -299725,6 +299782,22 @@
    },
    "focus": {
     "support": {
+     "activeelement-after-calling-window-focus-inner.html": [
+      "1fa14d4b8a24de267e2ffa0b37bdeefc78c00562",
+      []
+     ],
+     "activeelement-after-calling-window-focus-middle.sub.html": [
+      "c5a0d60a71de3708c429769c221c5e38555a9964",
+      []
+     ],
+     "activeelement-after-calling-window-focus-outer-different.sub.html": [
+      "0c2f8f792da46107b5dc98e6b69d9fc0f6bb9f06",
+      []
+     ],
+     "activeelement-after-calling-window-focus-outer-same.sub.html": [
+      "cabdb26b347e0505f2bf131632b48cad008ca850",
+      []
+     ],
      "activeelement-after-focusing-different-site-iframe-inner-contentwindow.html": [
       "bc78e6e0538c4dd22a3563f1b56bc755d468e767",
       []
@@ -300912,6 +300985,10 @@
      "5d684be9d0b0ab1f573fae70f7a8105bbfd47fe1",
      []
     ],
+    "forced-colors-mode-53-ref.html": [
+     "443bc21680bcfae65c70fc3bbd2bf2b0a0282f41",
+     []
+    ],
     "resources": {
      "float-image.jpg": [
       "ab06d5f94d16e22bb08fad79d6fef662b2a7de5a",
@@ -301072,7 +301149,7 @@
       []
      ],
      "FileSystemWritableFileStream-write.js": [
-      "ea4915a14105497c06b3d6fea4197a60469b6d62",
+      "287c4ae80eaeb78b17f40de1872d0806ac21a8b7",
       []
      ],
      "FileSystemWritableFileStream.js": [
@@ -305283,10 +305360,18 @@
       "46ad58d83bf6e98913ca4c564b7acb8f19fa0093",
       []
      ],
+     "popup-unsafe-none-with-cross-origin.https.html.headers": [
+      "073ce7adfbd81cb7c0b2f91f96c8349b6677f26c",
+      []
+     ],
      "popup-unsafe-none-with-same-origin.https.html.headers": [
       "073ce7adfbd81cb7c0b2f91f96c8349b6677f26c",
       []
      ],
+     "popup-unsafe-none-with-same-site.https.html.headers": [
+      "073ce7adfbd81cb7c0b2f91f96c8349b6677f26c",
+      []
+     ],
      "popup-with-structured-header.https.html.headers": [
       "46ad58d83bf6e98913ca4c564b7acb8f19fa0093",
       []
@@ -305411,7 +305496,7 @@
        []
       ],
       "popup-test.js": [
-       "4bf38a3abfd7088c50708479919df5a7a2039021",
+       "3da5ca11fe5881a6bd228e1c3757bf6523becc62",
        []
       ],
       "postback.html": [
@@ -311800,7 +311885,7 @@
       },
       "the-selectmenu-element": {
        "selectmenu-option-arbitrary-content-displayed-ref.tentative.html": [
-        "f92786a82122acff64f7252fa71660bd6c5aa6cc",
+        "918ce36d2b53b3002343afe2b401c4364e8edbec",
         []
        ],
        "selectmenu-option-arbitrary-content-not-displayed-ref.tentative.html": [
@@ -312199,7 +312284,7 @@
      },
      "popups": {
       "popup-backdrop-appearance-ref.tentative.html": [
-       "9ae95c2f8ffd2d03d90b6eca4a1f3834bfc3cf42",
+       "0327f3886fbceec18f21e2146a91a59053bfc954",
        []
       ],
       "popup-defaultopen-display-ref.tentative.html": [
@@ -312219,7 +312304,7 @@
        []
       ],
       "popup-open-overflow-display-ref.tentative.html": [
-       "bc52cf5455590016bfc09c070dfc83ea6d708ff7",
+       "7a350ea281dc68dfdb4d5f669955cce1d6ff5a5c",
        []
       ],
       "popup-stacking-context-ref.tentative.html": [
@@ -324161,7 +324246,7 @@
      []
     ],
     "idlharness.js": [
-     "b5eed06ce3e1380bc6bc1e8b75e2c545249fdc18",
+     "b3fe8034e2323e0ddf4c00816f457e4b60c106d0",
      []
     ],
     "idlharness.js.headers": [
@@ -367387,14 +367472,14 @@
      ]
     ],
     "fedcm-logout.sub.https.html": [
-     "7024638a127dcd8e579083813c031e048b0fbeb5",
+     "ad775d8bd21107ab0e79194536e95667ddcec43c",
      [
       null,
       {}
      ]
     ],
     "fedcm-network-requests.sub.https.html": [
-     "09841893ae385f4c04e864db8f1a1d4fa0987d3e",
+     "16da68b807932edd0128f15c25884f68d6da1f64",
      [
       null,
       {}
@@ -403689,6 +403774,13 @@
        }
       ]
      ],
+     "selectall-without-focus.html": [
+      "0db01014c103cd1750fca52d36a9b471edc6d4ee",
+      [
+       null,
+       {}
+      ]
+     ],
      "setting-value-of-textcontrol-immediately-after-hidden.html": [
       "f8a867f0782ae6d0066326aa58aec431a46e67db",
       [
@@ -428915,17 +429007,21 @@
        ]
       ],
       "header-refresh.https.optional.sub.html": [
-       "c303d871413d5c181d299e3c6a4ac6a7c2d6c4db",
+       "e63ee423cd74a925d60084aa6aef27fae0daff73",
        [
         null,
-        {}
+        {
+         "timeout": "long"
+        }
        ]
       ],
       "header-refresh.optional.sub.html": [
-       "56f24663e1d0192efc89569da8b84fee5e8a9298",
+       "4674ada9c6da1566e1031a347d2512086966f9e7",
        [
         null,
-        {}
+        {
+         "timeout": "long"
+        }
        ]
       ],
       "script-module-import-dynamic.https.sub.html": [
@@ -430400,7 +430496,7 @@
      ]
     ],
     "sandboxed_FileSystemBaseHandle-remove.https.any.js": [
-     "6044f65ae6b21ad675627aa105e333a253318b7f",
+     "19c48df438f00c785fefe318fa4b904daac1c63b",
      [
       "file-system-access/sandboxed_FileSystemBaseHandle-remove.https.any.html",
       {
@@ -430497,6 +430593,15 @@
     ]
    },
    "focus": {
+    "activeelement-after-calling-window-focus.sub.html": [
+     "f854ffb36ce462f0caaffc9996d2a0425e8e6356",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "activeelement-after-focusing-different-site-iframe-contentwindow.html": [
      "b16280acbd7a85abb183d6c23c7508f6ce2fe17f",
      [
@@ -433755,6 +433860,15 @@
          }
         ]
        ],
+       "storage-events.html": [
+        "6957496c3077acd5e87fa3127febfbcbbfb80099",
+        [
+         null,
+         {
+          "timeout": "long"
+         }
+        ]
+       ],
        "timers.html": [
         "aab650f36e5f58d064f1dd8b08d98e1bf7b010e8",
         [
@@ -458686,9 +458800,27 @@
       ]
      ],
      "header-parsing-failures.https.html": [
-      "6deebf26d50737d02c77e3ce2de6f4862b92b1c0",
+      "1973550103225d8843cd52d796e13aa64d228a78",
       [
-       null,
+       "html/cross-origin-opener-policy/header-parsing-failures.https.html?1-4",
+       {
+        "timeout": "long"
+       }
+      ],
+      [
+       "html/cross-origin-opener-policy/header-parsing-failures.https.html?12-last",
+       {
+        "timeout": "long"
+       }
+      ],
+      [
+       "html/cross-origin-opener-policy/header-parsing-failures.https.html?5-8",
+       {
+        "timeout": "long"
+       }
+      ],
+      [
+       "html/cross-origin-opener-policy/header-parsing-failures.https.html?9-12",
        {
         "timeout": "long"
        }
@@ -459060,7 +459192,7 @@
       ]
      ],
      "popup-unsafe-none-with-cross-origin.https.html": [
-      "26a273a6de5b411a3553e8a0e3d6366e2aa8c034",
+      "c776f4450ff221ce286af9eeeb3ba9f1edba0db1",
       [
        null,
        {
@@ -459087,7 +459219,7 @@
       ]
      ],
      "popup-unspecified-with-cross-origin.https.html": [
-      "26a273a6de5b411a3553e8a0e3d6366e2aa8c034",
+      "c776f4450ff221ce286af9eeeb3ba9f1edba0db1",
       [
        null,
        {
@@ -459096,7 +459228,7 @@
       ]
      ],
      "popup-unspecified-with-same-origin.https.html": [
-      "ca69369c8496d6a9f4613c7cea48f21678b7a0e2",
+      "7b3f4d94718e79bf6f748c99aa3075640a57ee67",
       [
        null,
        {
@@ -459105,7 +459237,7 @@
       ]
      ],
      "popup-unspecified-with-same-site.https.html": [
-      "7360674c975bee1e37c5ae6ca29b637ece85af93",
+      "7d734fa27f2603f6c4a1cdeefa1d29623f3d5d24",
       [
        null,
        {
@@ -459114,7 +459246,7 @@
       ]
      ],
      "popup-with-structured-header.https.html": [
-      "4066595b8978b410156cbf0287b2df00816eb092",
+      "729be3c4aade82c4ede2c52a9b328f70ec2cd181",
       [
        null,
        {
@@ -470530,7 +470662,7 @@
         ]
        ],
        "selectmenu-many-options.tentative.html": [
-        "2abb9d07e6863b8910cb7190dfbc8086bad39156",
+        "765845f0cb4df26f2189c08b14f70c24398e9dc6",
         [
          null,
          {
@@ -470539,7 +470671,7 @@
         ]
        ],
        "selectmenu-nested.tentative.html": [
-        "fdbf50b93902db06136e89d7f77f2f9803101247",
+        "bb80b706d054d36dcd70ab2e36bca4dbe1ee4f55",
         [
          null,
          {
@@ -470557,7 +470689,7 @@
         ]
        ],
        "selectmenu-parts-structure.tentative.html": [
-        "7a11b57fcb786e78c190ccd39635311b73069ed6",
+        "2f907c4fb5307d0f17fb49dd2ba68ab859adcb6f",
         [
          null,
          {
@@ -470566,7 +470698,7 @@
         ]
        ],
        "selectmenu-popup-position-with-zoom.tentative.html": [
-        "740be4bc76fbd8816d990d3cf044727498d6e56f",
+        "faebbf571cdc857469ede500c61c3ad49c0c3c81",
         [
          null,
          {
@@ -470575,7 +470707,7 @@
         ]
        ],
        "selectmenu-popup-position.tentative.html": [
-        "6ad7833046274a5867067003616939a24382bb23",
+        "acb661f9eb631d981146ff7ae3f770244999dc16",
         [
          null,
          {
@@ -470584,7 +470716,7 @@
         ]
        ],
        "selectmenu-popup.tentative.html": [
-        "d8abcb72d5a6292b823754670b34b76b40267c60",
+        "96288838c789683d437c353923886cf54f79a018",
         [
          null,
          {
@@ -470600,7 +470732,7 @@
         ]
        ],
        "selectmenu-shadow-root-replacement.tentative.html": [
-        "cad488fb41e58490452631633a653feb1bde19fc",
+        "b505e58ee2837b922616ee8d594c2c790fc185cd",
         [
          null,
          {
@@ -470616,7 +470748,7 @@
         ]
        ],
        "selectmenu-value-selectedOption.tentative.html": [
-        "f477ddb90dda9a04d6386c87deae83cbc94f272e",
+        "b131559d032beb73a8fc7946e2b79e9771254c5f",
         [
          null,
          {}
@@ -471539,14 +471671,14 @@
      },
      "popups": {
       "popup-anchor-idl-property.tentative.html": [
-       "e5d9ca8c486e7b7e62da100e299b99bc6685b706",
+       "fa4441d8bcdf1b27432efaf72e5a19b71cd3e2c5",
        [
         null,
         {}
        ]
       ],
       "popup-anchor-nesting.tentative.html": [
-       "c7ebe58ec7c466a89d66a6bcc082a9172bfa3af8",
+       "ee903c48ed08e65a8a4c5b7ba7119bfa92f7e50e",
        [
         null,
         {
@@ -471555,7 +471687,7 @@
        ]
       ],
       "popup-attribute-basic.tentative.html": [
-       "661c63fec446b6fdce2327fdec452a4e5576c6d7",
+       "2c9c23c500d7cf2ca2efe62ec8b58099b3c9d299",
        [
         null,
         {}
@@ -471569,28 +471701,28 @@
        ]
       ],
       "popup-defaultopen-2.tentative.html": [
-       "bf44092c09c8dc14e59a2272737ae80402ba6598",
+       "36b621f2cf0381272ab44d5e5f9a6c2cfd41de1f",
        [
         null,
         {}
        ]
       ],
       "popup-defaultopen.tentative.html": [
-       "12cf5452fac9c42c21edd30ebe428967f0a267dc",
+       "ec1275e7ea8e652cdb5f3fa4fa6a41cf5c08bd6e",
        [
         null,
         {}
        ]
       ],
       "popup-events.tentative.html": [
-       "7be1dae00bca10153b63e6af322f785d86207424",
+       "5fa7c911217291f634057977939e446064ef232e",
        [
         null,
         {}
        ]
       ],
       "popup-focus.tentative.html": [
-       "0612313ec904a4177e4079da59d1d3ee95427dcc",
+       "85f328f0e10345bb03e29ccf3f210226e47380ec",
        [
         null,
         {
@@ -471600,7 +471732,7 @@
        ]
       ],
       "popup-invoking-attribute.tentative.html": [
-       "2cac8d15abbd5c2885b8507138b9f9ef6d3e9227",
+       "4a40768647156a678d18199f239164f3eddfe33a",
        [
         null,
         {
@@ -471610,14 +471742,14 @@
        ]
       ],
       "popup-light-dismiss-on-scroll.tentative.html": [
-       "10276edbb338445bcaf75143400cb7f378a44b38",
+       "12615b7e2e1a21899d22d7625e2f7ce383e9e337",
        [
         null,
         {}
        ]
       ],
       "popup-light-dismiss.tentative.html": [
-       "568a515a9d53f15f86886a92d6bed57793d52f16",
+       "a5401cd426b1380fd18e93511335cee21411260c",
        [
         null,
         {
@@ -471626,7 +471758,7 @@
        ]
       ],
       "popup-not-keyboard-focusable.tentative.html": [
-       "4deb76d0d76911dd726ee13c80f343e07f82470e",
+       "88736ab472b0d2d8ca533a1f0f0144ff943fd44f",
        [
         null,
         {
@@ -471635,35 +471767,35 @@
        ]
       ],
       "popup-removal-2.tentative.html": [
-       "02e74297eeca211a73be6d61ad1476d8caa9a757",
+       "71d420e57988e559cda8b8e7bf3a6b69d2617b59",
        [
         null,
         {}
        ]
       ],
       "popup-removal.tentative.html": [
-       "525448eed1c71ab5f7a710901ef3b92c234f813c",
+       "b5f8100d04f619ee1acda9f1c494b004a509f8e0",
        [
         null,
         {}
        ]
       ],
       "popup-shadow-dom.tentative.html": [
-       "8df874def480aa6c1ff0295d53d15c7bd439adf7",
+       "21e18bcae9980dcf03c9700ad33b5d84d3692d2c",
        [
         null,
         {}
        ]
       ],
       "popup-stacking.tentative.html": [
-       "2cf540c96d238065d9c89e59bb7292ddcd185eee",
+       "6af6a9cb7e6e1cb82b970854bdfe9519f93c56ca",
        [
         null,
         {}
        ]
       ],
       "popup-top-layer-interactions.tentative.html": [
-       "69cc436a3d1f8d3ce68106c835ba8765e9688596",
+       "c8f9ddf658f8f5168cac30398d9b10a5d1a16aa3",
        [
         null,
         {
@@ -471672,7 +471804,7 @@
        ]
       ],
       "popup-types.tentative.html": [
-       "e3d24acfd9955da7d902f158adda1590eb229ca7",
+       "baa022d6e900a5cb1e97de39bfc771e17ca6b914",
        [
         null,
         {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/intra-base-white-space-001.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/intra-base-white-space-001.html
new file mode 100644
index 0000000..86468376
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/intra-base-white-space-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Ruby Test: intra-base white space (complex)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-ruby-1/#white-space">
+  <link rel="match" href="reference/intra-base-white-space-001-ref.html">
+
+  <meta content="" name="flags">
+  <meta content="This test checks that a single intra-base white space must be used when doing unit box pairing as long as it does not begin a ruby base container box or it does not end a ruby base container box. In this test, a leading white space inside of a ruby base unit box (the 'c' one) and a trailing white space inside of a ruby base unit box (the 'd' one) are collapsible white spaces across adjacent ruby base boxes according to white space processing rules.">
+
+  <style>
+  ruby
+    {
+      background-color: lightblue;
+      font-size: 60px;
+    }
+  </style>
+
+  <ruby>
+
+    b<rb> </rb><rb> c</rb><rb>d </rb><rb> </rb><rb>e</rb>
+
+    <rt>a</rt><rt></rt><rt>a</rt><rt>a</rt><rt></rt><rt>a</rt>
+
+  </ruby>
+
+  <!--
+
+  |[ a ]|[  ]|[ a ]|  [ a ]  |[]|[ a ]|
+  |[ b ]|[ws]|[ c ]|[ d ][ws]|[]|[ e ]|
+
+  -->
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ruby/reference/intra-base-white-space-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ruby/reference/intra-base-white-space-001-ref.html
new file mode 100644
index 0000000..4615b53
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ruby/reference/intra-base-white-space-001-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference File</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  ruby
+    {
+      background-color: lightblue;
+      font-size: 60px;
+    }
+  </style>
+
+  <ruby>
+
+    <rb>b</rb><rt>a</rt><rb>&nbsp;</rb><rt></rt><rb>c</rb><rt>a</rt><rb>d&nbsp;</rb><rt>a</rt><rb>e</rb><rt>a</rt>
+
+  </ruby>
+
+  <!--
+
+  |[ a ]|[  ]|[ a ]|  [ a ]  |[ a ]|
+  |[ b ]|[ws]|[ c ]|[ d ][ws]|[ e ]|
+
+  -->
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-with-focus.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-with-focus.html
new file mode 100644
index 0000000..585cd17
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-with-focus.html
@@ -0,0 +1,12 @@
+<script>
+addEventListener("DOMContentLoaded", () => {
+  document.querySelector("dd[contenteditable]").focus();
+  document.querySelector("dd[contenteditable]").addEventListener("DOMNodeRemoved", () => {
+    document.querySelector("h6").textContent = "";
+  });
+  document.execCommand("selectAll");
+  document.execCommand("delete");
+})
+</script>
+<h6>
+<dd contenteditable>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-without-focus.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-without-focus.html
new file mode 100644
index 0000000..a45f2dad
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/delete-in-dd-editing-host-after-selectall-without-focus.html
@@ -0,0 +1,12 @@
+<script>
+addEventListener("DOMContentLoaded", () => {
+  document.querySelector("dd[contenteditable]").blur();
+  document.querySelector("dd[contenteditable]").addEventListener("DOMNodeRemoved", () => {
+    document.querySelector("h6").textContent = "";
+  });
+  document.execCommand("selectAll");
+  document.execCommand("delete");
+})
+</script>
+<h6>
+<dd contenteditable>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-with-focus.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-with-focus.html
new file mode 100644
index 0000000..266cc4f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-with-focus.html
@@ -0,0 +1,15 @@
+<script>
+addEventListener("load", () => {
+  document.querySelector("ol[contenteditable]").focus();
+  document.execCommand("selectAll");
+  const targetListItem = document.querySelector("li + li");
+  targetListItem.addEventListener("DOMSubtreeModified", () => {
+    document.execCommand("forwardDelete");
+    document.querySelector("script").appendChild(targetListItem);
+  });
+  targetListItem.setAttribute("scrolling", "auto");
+});
+</script>
+<ol contenteditable>
+<li>
+<li>a</li>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-without-focus.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-without-focus.html
new file mode 100644
index 0000000..de10e8b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/forwarddelete-in-list-editing-host-after-selectall-without-focus.html
@@ -0,0 +1,15 @@
+<script>
+addEventListener("load", () => {
+  document.querySelector("ol[contenteditable]").blur();
+  document.execCommand("selectAll");
+  const targetListItem = document.querySelector("li + li");
+  targetListItem.addEventListener("DOMSubtreeModified", () => {
+    document.execCommand("forwardDelete");
+    document.querySelector("script").appendChild(targetListItem);
+  });
+  targetListItem.setAttribute("scrolling", "auto");
+});
+</script>
+<ol contenteditable>
+<li>
+<li>a</li>
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/move-editing-host-to-subdocument-when-textarea-has-focus.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/move-editing-host-to-subdocument-when-textarea-has-focus.html
new file mode 100644
index 0000000..b7d2e2f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/move-editing-host-to-subdocument-when-textarea-has-focus.html
@@ -0,0 +1,15 @@
+<script>
+addEventListener("DOMContentLoaded", () => {
+  document.querySelector("iframe").contentDocument.body.appendChild(
+    document.querySelector("span")
+  );
+  document.documentElement.style.display = "none";
+})
+</script>
+<hgroup>
+<audio controls>
+</audio>
+<iframe></iframe>
+<span contenteditable></span>
+</hgroup>
+<textarea autofocus>
diff --git a/third_party/blink/web_tests/external/wpt/editing/other/selectall-without-focus.html b/third_party/blink/web_tests/external/wpt/editing/other/selectall-without-focus.html
new file mode 100644
index 0000000..0db01014
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/editing/other/selectall-without-focus.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<head>
+<meta charset=utf-8>
+<title>Select All without focus should select not select only in the editing host</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+"use strict";
+
+addEventListener("DOMContentLoaded", () => {
+  test(() => {
+    document.head.remove();
+    document.execCommand("selectAll");
+    const rangeText = getSelection().toString();
+    assert_true(
+      rangeText.includes("preceding text"),
+      "Selection should contain the preceding text of the editing host"
+    );
+    assert_true(
+      rangeText.includes("editable text"),
+      "Selection should contain the editable text in the editing host"
+    );
+    getSelection().removeAllRanges();
+  }, "execCommand('selectAll') should select all content in the document even if the document body ends with editable content");
+});
+</script>
+</head>
+<p>preceding text</p>
+<div contenteditable>editable text
diff --git a/third_party/blink/web_tests/external/wpt/focus/activeelement-after-calling-window-focus.sub.html b/third_party/blink/web_tests/external/wpt/focus/activeelement-after-calling-window-focus.sub.html
new file mode 100644
index 0000000..f854ffb3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/focus/activeelement-after-calling-window-focus.sub.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>activeElement after calling window.focus()</title>
+<meta name="timeout" content="long">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+function waitForEvent(target, event, checkFn) {
+  return new Promise(resolve => {
+    target.addEventListener(event, e => {
+      if (checkFn && !checkFn(e)) {
+        return;
+      }
+      resolve();
+    }, { once: true });
+  });
+}
+
+function focusInnerInput(w) {
+  w.postMessage("focusinnerinput", "*");
+}
+
+function focusInnerFrame(w) {
+  w.postMessage("focusinner", "*");
+}
+
+function focusMiddleFrame(w) {
+  w.postMessage("focusmiddle", "*");
+}
+
+function focusOuterFrame(w) {
+  w.postMessage("focusouter", "*");
+}
+
+// This will send message to outer frame and also inner frame to ask them
+// send the log they collect back, the logs of outer and inner will be
+// concatenated.
+async function getLog(w) {
+  let log = "";
+  step_timeout(function() {
+    w.postMessage("getlog", "*");
+  }, 0);
+  await waitForEvent(window, "message", (e) => {
+    log = e.data;
+    return true;
+  });
+  return log;
+}
+
+async function runTest(t, url) {
+  let w = window.open(url);
+  t.add_cleanup(() => { w.close(); });
+  await waitForEvent(window, "message", e => e.data === "ready");
+  // Calling input.focus() on inner iframe should move its document.activeElement to INPUT.
+  focusInnerInput(w);
+  assert_equals(await getLog(w), 'outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT,');
+  // Calling window.focus() on inner iframe should NOT reset its document.activeElement to BODY
+  // because it's focused element is not an iframe.
+  focusInnerFrame(w);
+  assert_equals(await getLog(w), 'outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT,INPUT,');
+  // Calling window.focus() on middle iframe should reset its document.activeElement to BODY.
+  focusMiddleFrame(w);
+  assert_equals(await getLog(w), 'outerlog:windowblur,middlelog:windowfocus,BODY,innerlog:windowfocus,INPUT,INPUT,windowblur,');
+  // Calling window.focus() on top-level frame should reset its document.activeElement to BODY.
+  focusOuterFrame(w);
+  assert_equals(await getLog(w), 'outerlog:windowblur,windowfocus,BODY,middlelog:windowfocus,BODY,windowblur,innerlog:windowfocus,INPUT,INPUT,windowblur,');
+}
+
+promise_test(async t => {
+  await runTest(t, "https://{{hosts[][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-outer-same.sub.html");
+}, "Tests for all frames are in same origin");
+
+promise_test(async t => {
+  await runTest(t, "https://{{hosts[alt][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-outer-same.sub.html");
+}, "Tests for middle frame and inner frame are in same origin and outer frame is in different origin");
+
+promise_test(async t => {
+  await runTest(t, "https://{{hosts[alt][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-outer-different.sub.html");
+}, "Tests for outer frame and middle frame are in same origin and inner frame is in different origin");
+
+promise_test(async t => {
+  await runTest(t, "https://{{hosts[][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-outer-different.sub.html");
+}, "Tests for outer frame and inner frame are in same origin and middle frame is in different origin");
+
+promise_test(async t => {
+  await runTest(t, "support/activeelement-after-calling-window-focus-outer-different.sub.html");
+}, "Tests for all frames are in different origin");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-inner.html b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-inner.html
new file mode 100644
index 0000000..1fa14d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-inner.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Focus test inner document</title>
+</head>
+<body>
+<h1>Inner</h1>
+<input>
+<script>
+let innerlog = "innerlog:";
+
+window.onmessage = function(e) {
+  if (e.data == "focusinnerinput") {
+    document.querySelector("input").focus();
+    innerlog += document.activeElement.tagName + ",";
+  } else if (e.data == "focusinner") {
+    window.focus();
+    innerlog += document.activeElement.tagName + ",";
+  } else if (e.data == "getlog") {
+    parent.postMessage(innerlog, "*");
+  }
+};
+
+window.onfocus = function() {
+  innerlog += "windowfocus,";
+};
+
+window.onblur = function() {
+  innerlog += "windowblur,";
+};
+
+window.onload = function() {
+  parent.postMessage("ready", "*");
+}
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-middle.sub.html b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-middle.sub.html
new file mode 100644
index 0000000..c5a0d60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-middle.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Focus test middle document</title>
+<h1>Middle</h1><br>
+<iframe src="https://{{hosts[][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-inner.html"></iframe>
+<script>
+let middlelog = "middlelog:";
+
+let iframe = document.querySelector("iframe");
+window.onmessage = function(e) {
+  if (e.data == "ready") {
+    parent.postMessage(e.data, "*");
+  } else if (e.data == "focusinnerinput" || e.data == "focusinner" || e.data == "getlog") {
+    iframe.contentWindow.postMessage(e.data, "*");
+  } else if (e.data == "focusmiddle") {
+    window.focus();
+    middlelog += document.activeElement.tagName + ",";
+  } else {
+    parent.postMessage(middlelog + e.data, "*");
+  }
+};
+
+window.onfocus = function() {
+  middlelog += "windowfocus,";
+};
+
+window.onblur = function() {
+  middlelog += "windowblur,";
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-different.sub.html b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-different.sub.html
new file mode 100644
index 0000000..0c2f8f79
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-different.sub.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Focus test outer document</title>
+<iframe src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-middle.sub.html"></iframe>
+<script>
+let outerlog = "outerlog:";
+
+let iframe = document.querySelector("iframe");
+window.onmessage = function(e) {
+   if (e.data == "ready") {
+    opener.postMessage(e.data, "*");
+  } else if (e.data == "focusinnerinput" || e.data == "focusinner" || e.data == "focusmiddle" || e.data == "getlog") {
+    iframe.contentWindow.postMessage(e.data, "*");
+  } else if (e.data == "focusouter") {
+    window.focus();
+    outerlog += document.activeElement.tagName + ",";
+  } else {
+    opener.postMessage(outerlog + e.data, "*");
+  }
+};
+
+window.onload = function() {
+  window.onfocus = function() {
+    outerlog += "windowfocus,";
+  };
+};
+
+window.onblur = function() {
+  outerlog += "windowblur,";
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-same.sub.html b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-same.sub.html
new file mode 100644
index 0000000..cabdb26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/focus/support/activeelement-after-calling-window-focus-outer-same.sub.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Focus test outer document</title>
+<iframe src="https://{{hosts[][www]}}:{{ports[https][0]}}/focus/support/activeelement-after-calling-window-focus-middle.sub.html"></iframe>
+<script>
+let outerlog = "outerlog:";
+
+let iframe = document.querySelector("iframe");
+window.onmessage = function(e) {
+   if (e.data == "ready") {
+    opener.postMessage(e.data, "*");
+  } else if (e.data == "focusinnerinput" || e.data == "focusinner" || e.data == "focusmiddle" || e.data == "getlog") {
+    iframe.contentWindow.postMessage(e.data, "*");
+  } else if (e.data == "focusouter") {
+    window.focus();
+    outerlog += document.activeElement.tagName + ",";
+  } else {
+    opener.postMessage(outerlog + e.data, "*");
+  }
+};
+
+window.onload = function() {
+  window.onfocus = function() {
+    outerlog += "windowfocus,";
+  };
+};
+
+window.onblur = function() {
+  outerlog += "windowblur,";
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resources/idlharness.js b/third_party/blink/web_tests/external/wpt/resources/idlharness.js
index b5eed06..b3fe8034 100644
--- a/third_party/blink/web_tests/external/wpt/resources/idlharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/idlharness.js
@@ -1529,12 +1529,12 @@
         // https://github.com/heycam/webidl/issues/698
         assert_true(isConstructor(this.get_interface_object()), "interface object must pass IsConstructor check");
 
+        var interface_object = this.get_interface_object();
+        assert_throws_js(globalOf(interface_object).TypeError, function() {
+            interface_object();
+        }, "interface object didn't throw TypeError when called as a function");
+
         if (!this.constructors().length) {
-            // "If I was not declared with a constructor operation, then throw a TypeError."
-            var interface_object = this.get_interface_object();
-            assert_throws_js(globalOf(interface_object).TypeError, function() {
-                interface_object();
-            }, "interface object didn't throw TypeError when called as a function");
             assert_throws_js(globalOf(interface_object).TypeError, function() {
                 new interface_object();
             }, "interface object didn't throw TypeError when called as a constructor");
diff --git a/third_party/blink/web_tests/fast/xsl/resources/doctype.html b/third_party/blink/web_tests/fast/xsl/resources/doctype.html
new file mode 100644
index 0000000..c10c906
--- /dev/null
+++ b/third_party/blink/web_tests/fast/xsl/resources/doctype.html
@@ -0,0 +1 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
diff --git a/third_party/blink/web_tests/fast/xsl/xsl-external-load-detached.html b/third_party/blink/web_tests/fast/xsl/xsl-external-load-detached.html
new file mode 100644
index 0000000..bab788c0
--- /dev/null
+++ b/third_party/blink/web_tests/fast/xsl/xsl-external-load-detached.html
@@ -0,0 +1,15 @@
+<body>
+PASS if no crash.
+<iframe src="resources/doctype.html" id="i"></iframe>
+<script>
+if (window.testRunner)
+  testRunner.dumpAsText();
+
+window.onload = () => {
+  let i_doc = i.contentDocument;
+  i.remove();
+  var x = new XSLTProcessor();
+  var xsl = new DOMParser().parseFromString('<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"></xsl:stylesheet>','application/xml');
+  x.importStylesheet(xsl);
+  x.transformToDocument(i_doc);
+}</script>
diff --git a/third_party/blink/web_tests/http/tests/geolocation-api/geolocation-default-feature-policy.https.sub.html b/third_party/blink/web_tests/http/tests/geolocation-api/geolocation-default-feature-policy.https.sub.html
index 1a7f6756..98deab2 100644
--- a/third_party/blink/web_tests/http/tests/geolocation-api/geolocation-default-feature-policy.https.sub.html
+++ b/third_party/blink/web_tests/http/tests/geolocation-api/geolocation-default-feature-policy.https.sub.html
@@ -5,7 +5,7 @@
 <script src=../resources/feature-policy-permissions-test.js></script>
 
 <script type="module">
-import {GeolocationMock} from '/wpt_internal/geolocation-api/resources/geolocation-mock.js';
+import {GeolocationMock} from '/resources/geolocation-mock.js';
 
 const mockLatitude = 51.478;
 const mockLongitude = -0.166;
diff --git a/third_party/blink/web_tests/http/tests/resources/geolocation-mock.js b/third_party/blink/web_tests/http/tests/resources/geolocation-mock.js
new file mode 100644
index 0000000..1e9a588
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/resources/geolocation-mock.js
@@ -0,0 +1,225 @@
+/*
+ * geolocation-mock contains a mock implementation of Geolocation and
+ * PermissionService.
+ */
+
+import {GeolocationReceiver} from '/gen/services/device/public/mojom/geolocation.mojom.m.js';
+import {Geoposition_ErrorCode} from '/gen/services/device/public/mojom/geoposition.mojom.m.js';
+import {GeolocationService, GeolocationServiceReceiver} from '/gen/third_party/blink/public/mojom/geolocation/geolocation_service.mojom.m.js';
+import {PermissionStatus} from '/gen/third_party/blink/public/mojom/permissions/permission_status.mojom.m.js';
+
+export class GeolocationMock {
+  constructor() {
+    this.geolocationServiceInterceptor_ =
+        new MojoInterfaceInterceptor(GeolocationService.$interfaceName);
+    this.geolocationServiceInterceptor_.oninterfacerequest =
+        e => this.connectGeolocationService_(e.handle);
+    this.geolocationServiceInterceptor_.start();
+
+    /**
+     * The next geoposition to return in response to a queryNextPosition()
+     * call.
+    */
+    this.geoposition_ = null;
+
+    /**
+     * While true, position requests will result in a timeout error.
+     */
+    this.shouldTimeout_ = false;
+
+    /**
+     * A pending request for permission awaiting a decision to be set via a
+     * setGeolocationPermission call.
+     *
+     * @type {?Function}
+     */
+    this.pendingPermissionRequest_ = null;
+
+    /**
+     * The status to respond to permission requests with. If set to ASK, then
+     * permission requests will block until setGeolocationPermission is called
+     * to allow or deny permission requests.
+     *
+     * @type {!PermissionStatus}
+     */
+    this.permissionStatus_ = PermissionStatus.ASK;
+    this.rejectGeolocationServiceConnections_ = false;
+
+    this.systemPermissionStatus_ = PermissionStatus.GRANTED;
+
+    /**
+     * Set by interceptQueryNextPosition() and used to resolve the promise
+     * returned by that call once the next incoming queryPosition() is received.
+     */
+    this.queryNextPositionIntercept_ = null;
+
+    this.geolocationReceiver_ = new GeolocationReceiver(this);
+    this.geolocationServiceReceiver_ = new GeolocationServiceReceiver(this);
+  }
+
+  connectGeolocationService_(handle) {
+    if (this.rejectGeolocationServiceConnections_) {
+      handle.close();
+      return;
+    }
+    this.geolocationServiceReceiver_.$.bindHandle(handle);
+  }
+
+  setHighAccuracy(highAccuracy) {
+    // FIXME: We need to add some tests regarding "high accuracy" mode.
+    // See https://bugs.webkit.org/show_bug.cgi?id=49438
+  }
+
+  /**
+   * Waits for the next queryPosition() call, and returns a function which can
+   * be used to respond to it. This allows tests to have fine-grained control
+   * over exactly when and how the mock responds to a specific request.
+   */
+  async interceptQueryNextPosition() {
+    if (this.queryNextPositionIntercept_) {
+      throw new Error(
+          'interceptQueryNextPosition called twice in a row, with no interim ' +
+          'queryPosition');
+    }
+    return new Promise(resolve => {
+      this.queryNextPositionIntercept_ = resolver => {
+        this.queryNextPositionIntercept_ = null;
+        resolve(geoposition => { resolver({geoposition}); });
+      };
+    });
+  }
+
+  /**
+   * A mock implementation of GeolocationService.queryNextPosition(). This
+   * returns the position set by a call to setGeolocationPosition() or
+   * setGeolocationPositionUnavailableError().
+   */
+  queryNextPosition() {
+    if (this.shouldTimeout_) {
+      // Return a promise that will never be resolved. Since no geoposition is
+      // returned, the request will eventually time out.
+      return new Promise((resolve, reject) => {});
+    }
+    if (this.queryNextPositionIntercept_) {
+      return new Promise(resolve => {
+        this.queryNextPositionIntercept_(resolve);
+      });
+    }
+
+    if (this.systemPermissionStatus_ != PermissionStatus.GRANTED) {
+      this.geoposition_ = {
+        valid: false,
+        timestamp: {internalValue: 0n},
+        errorMessage: "User has not allowed access to system location.",
+        errorCode: Geoposition_ErrorCode.PERMISSION_DENIED,
+      };
+    }
+
+    if (!this.geoposition_) {
+      this.setGeolocationPositionUnavailableError(
+          'Test error: position not set before call to queryNextPosition()');
+    }
+    let geoposition = this.geoposition_;
+    this.geoposition_ = null;
+    return Promise.resolve({geoposition});
+  }
+
+  makeGeoposition(latitude, longitude, accuracy, altitude = undefined,
+                  altitudeAccuracy = undefined, heading = undefined,
+                  speed = undefined) {
+    // The new Date().getTime() returns the number of milliseconds since the
+    // UNIX epoch (1970-01-01 00::00:00 UTC), while |internalValue| of the
+    // device.mojom.Geoposition represents the value of microseconds since the
+    // Windows FILETIME epoch (1601-01-01 00:00:00 UTC). So add the delta when
+    // sets the |internalValue|. See more info in //base/time/time.h.
+    const windowsEpoch = Date.UTC(1601,0,1,0,0,0,0);
+    const unixEpoch = Date.UTC(1970,0,1,0,0,0,0);
+    // |epochDeltaInMs| equals to base::Time::kTimeTToMicrosecondsOffset.
+    const epochDeltaInMs = unixEpoch - windowsEpoch;
+    const timestamp =
+        {internalValue: BigInt((new Date().getTime() + epochDeltaInMs) * 1000)};
+    const errorMessage = '';
+    const valid = true;
+    return {latitude, longitude, accuracy, altitude, altitudeAccuracy, heading,
+            speed, timestamp, errorMessage, valid};
+  }
+
+  /**
+   * Sets the position to return to the next queryNextPosition() call. If any
+   * queryNextPosition() requests are outstanding, they will all receive the
+   * position set by this call.
+   */
+  setGeolocationPosition(latitude, longitude, accuracy, altitude,
+                         altitudeAccuracy, heading, speed) {
+    this.geoposition_ = this.makeGeoposition(latitude, longitude, accuracy,
+        altitude, altitudeAccuracy, heading, speed);
+  }
+
+  /**
+   * Sets the error message to return to the next queryNextPosition() call. If
+   * any queryNextPosition() requests are outstanding, they will all receive
+   * the error set by this call.
+   */
+  setGeolocationPositionUnavailableError(message) {
+    this.geoposition_ = {
+      valid: false,
+      timestamp: {internalValue: 0n},
+      errorMessage: message,
+      errorCode: Geoposition_ErrorCode.POSITION_UNAVAILABLE,
+    };
+  }
+
+  /**
+   * Sets whether geolocation requests should cause timeout errors.
+   */
+  setGeolocationTimeoutError(shouldTimeout) {
+    this.shouldTimeout_ = shouldTimeout;
+  }
+
+  /**
+   * Reject any connection requests for the geolocation service. This will
+   * trigger a connection error in the client.
+   */
+  rejectGeolocationServiceConnections() {
+    this.rejectGeolocationServiceConnections_ = true;
+  }
+
+  /**
+   * A mock implementation of GeolocationService.createGeolocation().
+   * This accepts the request as long as the permission has been set to
+   * granted.
+   */
+  createGeolocation(receiver, user_gesture) {
+    switch (this.permissionStatus_) {
+     case PermissionStatus.ASK:
+      return new Promise((resolve, reject) => {
+        setTimeout(() => {
+          resolve(this.createGeolocation(receiver, user_gesture));
+        }, 50);
+      });
+      setTimeout(() => { this.createGeolocation(receiver, user_gesture)}, 50);
+      break;
+
+     case PermissionStatus.GRANTED:
+      this.geolocationReceiver_.$.bindHandle(receiver.handle);
+      break;
+
+     default:
+      receiver.handle.close();
+    }
+    return Promise.resolve(this.permissionStatus_);
+  }
+
+  /**
+   * Sets whether the next geolocation permission request should be allowed.
+   */
+  setGeolocationPermission(allowed) {
+    this.permissionStatus_ = allowed ? PermissionStatus.GRANTED
+                                     : PermissionStatus.DENIED;
+  }
+
+  setSystemGeolocationPermission(allowed) {
+    this.systemPermissionStatus_ = allowed ? PermissionStatus.GRANTED
+                                           : PermissionStatus.DENIED;
+  }
+}
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
index 3b7dc42d..cfc76e7 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Geolocation On A Secure Origin</title>
 <script type="module">
-import {GeolocationMock} from '/wpt_internal/geolocation-api/resources/geolocation-mock.js';
+import {GeolocationMock} from '/resources/geolocation-mock.js';
 
 const mockLatitude = 51.478;
 const mockLongitude = -0.166;
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/selectall-without-focus-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/selectall-without-focus-expected.txt
new file mode 100644
index 0000000..7f598c26
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/external/wpt/editing/other/selectall-without-focus-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL execCommand('selectAll') should select all content in the document even if the document body ends with editable content assert_true: Selection should contain the preceding text of the editing host expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/focus/activeelement-after-calling-window-focus.sub-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/focus/activeelement-after-calling-window-focus.sub-expected.txt
new file mode 100644
index 0000000..fb0ba66
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/external/wpt/focus/activeelement-after-calling-window-focus.sub-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+FAIL Tests for all frames are in same origin assert_equals: expected "outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT," but got "outerlog:middlelog:innerlog:INPUT,"
+FAIL Tests for middle frame and inner frame are in same origin and outer frame is in different origin assert_equals: expected "outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT," but got "outerlog:middlelog:innerlog:INPUT,"
+FAIL Tests for outer frame and middle frame are in same origin and inner frame is in different origin assert_equals: expected "outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT," but got "outerlog:middlelog:innerlog:INPUT,"
+FAIL Tests for outer frame and inner frame are in same origin and middle frame is in different origin assert_equals: expected "outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT," but got "outerlog:middlelog:innerlog:INPUT,"
+FAIL Tests for all frames are in different origin assert_equals: expected "outerlog:windowblur,middlelog:innerlog:windowfocus,INPUT," but got "outerlog:middlelog:innerlog:INPUT,"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/generic/fast/xsl/xsl-external-load-detached-expected.txt b/third_party/blink/web_tests/platform/generic/fast/xsl/xsl-external-load-detached-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/fast/xsl/xsl-external-load-detached-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/at-fallback-position-allowed-declarations.html b/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/at-fallback-position-allowed-declarations.html
index 938361e..edfc7538 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/at-fallback-position-allowed-declarations.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-anchor-position/at-fallback-position-allowed-declarations.html
@@ -11,10 +11,9 @@
     style.sheet.deleteRule(0);
 }
 
-function test_allowed_property(property) {
+function test_allowed_property(property, value = '1px') {
   test(t => {
     t.add_cleanup(cleanup);
-    const value = '1px';
     const serialization = `${property}: ${value}`;
     const rule = `@position-fallback --foo { @try { ${property}: ${value}; } }`;
     const index = style.sheet.insertRule(rule);
@@ -61,6 +60,14 @@
 test_allowed_property('max-block-size');
 test_allowed_property('max-inline-size');
 
+// Box alignment properties are allowed
+test_allowed_property('justify-content', 'normal');
+test_allowed_property('align-content', 'normal');
+test_allowed_property('justify-items', 'normal');
+test_allowed_property('align-items', 'normal');
+test_allowed_property('justify-self', 'normal');
+test_allowed_property('align-self', 'normal');
+
 // Custom properties are allowed
 test_allowed_property('--custom');
 
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html
new file mode 100644
index 0000000..02f28bd8
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="utils.js"></script>
+
+<body>
+  <script type="module">
+    // Ask the worker to do a fetch request that will be handled by the service
+    // worker via postMessage.
+    const checkIfServiceWorkerCanControlWebWorker = async () => {
+      const dedicated_worker = new Worker('serviceWorker-dedicated-worker.js');
+      return new Promise((resolve, reject) => {
+        dedicated_worker.addEventListener('message', e => {
+          resolve(e.data)
+        });
+        dedicated_worker.postMessage('fetch');
+      })
+    }
+
+    const [key] = parseKeylist();
+    const url = new URL(location.href);
+    if (url.searchParams.get('useServiceWorkerInFencedFrame')) {
+      await navigator.serviceWorker.register('serviceWorker-dedicated-worker-sw.js');
+      await navigator.serviceWorker.ready;
+    }
+
+    const result = await checkIfServiceWorkerCanControlWebWorker();
+    writeValueToServer(key, result);
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html.headers b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html.headers
new file mode 100644
index 0000000..6247f6d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-inner.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js
new file mode 100644
index 0000000..027995a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js
@@ -0,0 +1,18 @@
+self.addEventListener('fetch', async (e) => {
+  if (e.request.url.includes('fenced_frame_dedicated_worker_test')) {
+    e.respondWith(new Response('OK'));
+    return;
+  }
+
+  e.respondWith(fetch(e.request).catch(() => {
+    return new Response('not found');
+  }));
+})
+
+self.addEventListener('install', () => {
+  return self.skipWaiting();
+});
+
+self.addEventListener('activate', () => {
+  return self.clients.claim();
+});
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js.headers b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js.headers
new file mode 100644
index 0000000..d0b9633
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker-sw.js.headers
@@ -0,0 +1 @@
+Service-Worker-Allowed: /
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker.js b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker.js
new file mode 100644
index 0000000..8a9fa5e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/resources/serviceWorker-dedicated-worker.js
@@ -0,0 +1,8 @@
+self.addEventListener('message', async (e) => {
+  if (e.data === 'fetch') {
+    // Send a request to non-existing URL but handled by SW.
+    const res = await fetch('./fenced_frame_dedicated_worker_test');
+    const data = res.ok ? await res.text() : res.statusText;
+    self.postMessage(data);
+  }
+});
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html
new file mode 100644
index 0000000..92533e38
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>Service Worker: Check if dedicated workers are controlled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<script src="/common/utils.js"></script>
+
+<body>
+  <script>
+    const frameUrl = './resources/serviceWorker-dedicated-worker-inner.html';
+    const unregisterAllSW = async () => {
+      const regs = await navigator.serviceWorker.getRegistrations();
+      return Promise.all(regs.map(reg => reg.unregister()));
+    };
+
+    promise_test(async t => {
+      t.add_cleanup(unregisterAllSW);
+      const key = token();
+
+      // Inside the fenced frame, the service worker is registered and fetch
+      // request is triggered from the dedicated worker to the url that is
+      // handled in the service worker.
+      const url = `${frameUrl}?useServiceWorkerInFencedFrame=true`;
+      attachFencedFrame(generateURL(url, [key]));
+      const result = await nextValueFromServer(key);
+      assert_equals(result, "OK");
+    }, "Fenced frame's service workers can control fenced frame's dedicated workers");
+
+    promise_test(async t => {
+      t.add_cleanup(unregisterAllSW);
+      const key = token();
+
+      // Set a service worker in the fenced frame. Inside the fenced frame, a
+      // dedicated worker is created and triggers a fetch request. But we don't
+      // use the fetch request result in this test. This test will check if the
+      // dedicated worker in the parent frame is controlled by the SW in FF.
+      const url = `${frameUrl}?useServiceWorkerInFencedFrame=true`;
+      attachFencedFrame(generateURL(url, [key]));
+      await nextValueFromServer(key);
+
+      const checkIfWorkerIsControlled = async () => {
+        const dedicated_worker = new Worker('resources/serviceWorker-dedicated-worker.js');
+        return new Promise((resolve, reject) => {
+          dedicated_worker.addEventListener('message', e => {
+            resolve(e.data)
+          });
+          dedicated_worker.postMessage('fetch');
+        });
+      }
+
+      const result = await checkIfWorkerIsControlled()
+      assert_equals(result, "Not Found");
+    }, "Fenced frame's service workers can not control the dedicated workers in the parent frame");
+
+    promise_test(async t => {
+      t.add_cleanup(unregisterAllSW);
+      const key = token();
+
+      // Register a service worker in the parent frame.
+      await navigator.serviceWorker.register('resources/serviceWorker-dedicated-worker-sw.js', { scope: '/' });
+      await navigator.serviceWorker.ready;
+
+      // Inside the fenced frame, fetch request to unexisting URL is triggered
+      // from the dedicated worker.
+      attachFencedFrame(generateURL(frameUrl, [key]));
+
+      const result = await nextValueFromServer(key);
+      assert_equals(result, "Not Found");
+    }, "Service workers in the parent frame of fenced frames can not control dedicated workers in fenced frames");
+  </script>
+</body>
diff --git a/third_party/puffin/BUILD.gn b/third_party/puffin/BUILD.gn
new file mode 100644
index 0000000..2c3d87d
--- /dev/null
+++ b/third_party/puffin/BUILD.gn
@@ -0,0 +1,122 @@
+# Copyright 2022 The Chromium OS 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("//third_party/protobuf/proto_library.gni")
+group("all") {
+  deps = [
+    ":libpuffdiff",
+    ":libpuffin-proto",
+    ":libpuffpatch",
+    ":puffin",
+  ]
+}
+
+config("target_defaults") {
+  cflags = [ "-Wextra" ]
+  cflags_cc = [
+    "-Wnon-virtual-dtor",
+    "-Wno-unused-parameter",
+  ]
+  include_dirs = [
+    "//third_party/puffin/src/include",
+    "//third_party",
+    "//components",
+  ]
+  defines = [ "_FILE_OFFSET_BITS=64" ]
+}
+
+proto_library("libpuffin-proto") {
+  sources = [ "src/puffin.proto" ]
+  proto_out_dir = "puffin/src"
+}
+
+static_library("libpuffpatch") {
+  configs += [ ":target_defaults" ]
+  complete_static_lib = true
+  deps = [
+    ":libpuffin-proto",
+    "//base",
+    "//components/zucchini:zucchini_lib",
+    "//third_party/brotli:dec",
+  ]
+  sources = [
+    "src/bit_reader.cc",
+    "src/bit_writer.cc",
+    "src/brotli_util.cc",
+    "src/huffer.cc",
+    "src/huffman_table.cc",
+    "src/memory_stream.cc",
+    "src/puff_reader.cc",
+    "src/puff_writer.cc",
+    "src/puffer.cc",
+    "src/puffin_stream.cc",
+    "src/puffpatch.cc",
+  ]
+}
+
+static_library("libpuffdiff") {
+  configs += [ ":target_defaults" ]
+  deps = [
+    ":libpuffin-proto",
+    "//base",
+    "//components/zucchini:zucchini_lib",
+    "//third_party/brotli:enc",
+  ]
+  sources = [
+    "src/file_stream.cc",
+    "src/puffdiff.cc",
+    "src/utils.cc",
+  ]
+}
+
+executable("puffin") {
+  configs += [ ":target_defaults" ]
+  deps = [
+    ":libpuffdiff",
+    ":libpuffpatch",
+    "//base",
+  ]
+  sources = [ "src/chromium_main.cc" ]
+}
+
+config("test_defaults") {
+  cflags = [
+    "-Wextra",
+    "-Wno-sign-compare",
+  ]
+  cflags_cc = [
+    "-Wnon-virtual-dtor",
+    "-Wno-unused-parameter",
+  ]
+  include_dirs = [
+    "../protobuf/src",
+    "src/include",
+    "//third_party",
+    "//components",
+  ]
+  defines = [ "_FILE_OFFSET_BITS=64" ]
+}
+
+executable("puffin_unittest") {
+  testonly = true
+  configs += [ ":test_defaults" ]
+  sources = [
+    "src/bit_io_unittest.cc",
+    "src/brotli_util_unittest.cc",
+    "src/integration_test.cc",
+    "src/patching_unittest.cc",
+    "src/puff_io_unittest.cc",
+    "src/puffin_unittest.cc",
+    "src/stream_unittest.cc",
+    "src/testrunner.cc",
+    "src/unittest_common.cc",
+    "src/utils_unittest.cc",
+  ]
+  deps = [
+    ":libpuffdiff",
+    ":libpuffpatch",
+    "//base",
+    "//testing/gtest:gtest",
+  ]
+}
diff --git a/third_party/puffin/DEPS b/third_party/puffin/DEPS
index e0513edf..c1f90a5 100644
--- a/third_party/puffin/DEPS
+++ b/third_party/puffin/DEPS
@@ -1,11 +1,7 @@
 include_rules = [
-    "+base",
-    "+brillo",
-    "+brotli",
-    "+bsdiff",
-    "+gflags",
-    "+glog",
-    "+gtest",
-    "+puffin",
-    "+zucchini",
-  ]
\ No newline at end of file
+  "+base",
+  "+brotli",
+  "+gtest",
+  "+puffin",
+  "+zucchini",
+]
diff --git a/third_party/puffin/OWNERS b/third_party/puffin/OWNERS
index cc9f4a2..2ad72f0 100644
--- a/third_party/puffin/OWNERS
+++ b/third_party/puffin/OWNERS
@@ -1,11 +1,2 @@
-# Android
-senj@google.com
-xunchang@google.com
-zhangkelvin@google.com
-
-# Chrome OS
-kimjae@google.com
-
 # Omaha
-sorin@chromium.org
-waffles@chromium.org
\ No newline at end of file
+file://components/update_client/OWNERS
\ No newline at end of file
diff --git a/third_party/puffin/README.chromium b/third_party/puffin/README.chromium
index 9c9cd89..6832d48 100644
--- a/third_party/puffin/README.chromium
+++ b/third_party/puffin/README.chromium
@@ -19,7 +19,14 @@
 by Omaha Server.
 
 Local Modifications:
-- Updated OWNERS to reflect the chromium/src owners and inherit the original AOSP owners as well.
+- Updated OWNERS to reflect our team as the owners.
 - Removed BUILD.gn taken from AOSP as it doesn't build in chromium.
 - removed PRESUBMIT.cfg and PREUPLOAD.cfg
 - Adding a DEPS file so we can pass presubmit checks.
+- removed BSDiff as we only require the zucchini version of puffdiff/puffpatch
+- rewrote the commandline usage for the puffin binary as we only need to support
+    and test puffdiff and puffpatch.
+- Replaced POSIX file IO with chromium/src's base::File/base::FilePath methods
+    so it will build and run cross-platform.
+- Removed dependence of libpuffpatch on libpuffdiff as the puffin patching
+    service we plant to implement only requires libpuffpatch.
diff --git a/third_party/puffin/README.md b/third_party/puffin/README.md
index 0523e89..080abfd 100644
--- a/third_party/puffin/README.md
+++ b/third_party/puffin/README.md
@@ -224,6 +224,10 @@
 It can also be used as a library (currently used by update_engine) that provides
 different APIs.
 
+## Compute Patch
+To compute the diff between our current state and the original changes:
+`git diff 4180a65119ef2c333c4d33c9e39869da89a8faea -- .`
+
 ## References
 
 [RFC 1951]: https://www.ietf.org/rfc/rfc1951.txt
diff --git a/third_party/puffin/src/bit_reader.h b/third_party/puffin/src/bit_reader.h
index aa4a97f..7371b6e 100644
--- a/third_party/puffin/src/bit_reader.h
+++ b/third_party/puffin/src/bit_reader.h
@@ -81,11 +81,7 @@
   // |in_buf|  IN  The input buffer
   // |in_size| IN  The size of the input buffer
   BufferBitReader(const uint8_t* in_buf, size_t in_size)
-      : in_buf_(in_buf),
-        in_size_(in_size),
-        index_(0),
-        in_cache_(0),
-        in_cache_bits_(0) {}
+      : in_buf_(in_buf), in_size_(in_size) {}
 
   ~BufferBitReader() override = default;
 
@@ -103,11 +99,11 @@
   uint64_t BitsRemaining() const override;
 
  private:
-  const uint8_t* in_buf_;  // The input buffer.
-  uint64_t in_size_;       // The number of bytes in |in_buf_|.
-  uint64_t index_;         // The index to the next byte to be read.
-  uint32_t in_cache_;      // The temporary buffer to put input data into.
-  size_t in_cache_bits_;   // The number of bits available in |in_cache_|.
+  const uint8_t* in_buf_;    // The input buffer.
+  uint64_t in_size_;         // The number of bytes in |in_buf_|.
+  uint64_t index_{0};        // The index to the next byte to be read.
+  uint32_t in_cache_{0};     // The temporary buffer to put input data into.
+  size_t in_cache_bits_{0};  // The number of bits available in |in_cache_|.
 
   DISALLOW_COPY_AND_ASSIGN(BufferBitReader);
 };
diff --git a/third_party/puffin/src/bit_writer.h b/third_party/puffin/src/bit_writer.h
index 9e9bdb92..e6cea98 100644
--- a/third_party/puffin/src/bit_writer.h
+++ b/third_party/puffin/src/bit_writer.h
@@ -67,11 +67,7 @@
   // |out_buf|  IN  The output buffer
   // |out_size| IN  The size of the output buffer
   BufferBitWriter(uint8_t* out_buf, size_t out_size)
-      : out_buf_(out_buf),
-        out_size_(out_size),
-        index_(0),
-        out_holder_(0),
-        out_holder_bits_(0) {}
+      : out_buf_(out_buf), out_size_(out_size) {}
 
   ~BufferBitWriter() override = default;
 
@@ -91,13 +87,13 @@
   uint64_t out_size_;
 
   // The index to the next byte to write into.
-  uint64_t index_;
+  uint64_t index_{0};
 
   // A temporary buffer to keep the bits going out.
-  uint32_t out_holder_;
+  uint32_t out_holder_{0};
 
   // The number of bits in |out_holder_|.
-  uint8_t out_holder_bits_;
+  uint8_t out_holder_bits_{0};
 
   DISALLOW_COPY_AND_ASSIGN(BufferBitWriter);
 };
diff --git a/third_party/puffin/src/brotli_util.cc b/third_party/puffin/src/brotli_util.cc
index b5c84886..64acec94 100644
--- a/third_party/puffin/src/brotli_util.cc
+++ b/third_party/puffin/src/brotli_util.cc
@@ -81,7 +81,7 @@
   while (available_in != 0 || !BrotliDecoderIsFinished(decoder.get())) {
     const uint8_t* next_in = input + input_size - available_in;
     // Set up the output buffer
-    uint8_t buffer[kBufferSize];
+    uint8_t buffer[kBufferSize] = {0};
     uint8_t* next_out = buffer;
     size_t available_out = kBufferSize;
 
diff --git a/third_party/puffin/src/chromium_main.cc b/third_party/puffin/src/chromium_main.cc
new file mode 100644
index 0000000..ae0613f
--- /dev/null
+++ b/third_party/puffin/src/chromium_main.cc
@@ -0,0 +1,345 @@
+// Copyright 2022 The Chromium OS 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/sys_string_conversions.h"
+
+#include "puffin/file_stream.h"
+#include "puffin/memory_stream.h"
+#include "puffin/src/include/puffin/common.h"
+#include "puffin/src/include/puffin/huffer.h"
+#include "puffin/src/include/puffin/puffdiff.h"
+#include "puffin/src/include/puffin/puffer.h"
+#include "puffin/src/include/puffin/puffpatch.h"
+#include "puffin/src/include/puffin/utils.h"
+#include "puffin/src/logging.h"
+#include "puffin/src/puffin_stream.h"
+
+using puffin::BitExtent;
+using puffin::Buffer;
+using puffin::ByteExtent;
+using puffin::FileStream;
+using puffin::Huffer;
+using puffin::MemoryStream;
+using puffin::Puffer;
+using puffin::PuffinStream;
+using puffin::UniqueStreamPtr;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+namespace {
+
+void PrintHelp() {
+  LOG(WARNING) << "Main Usage:\n"
+               << "puffdiff usage:\n"
+               << "  puffin -puffdiff <source_file_path> "
+                  "<destination_file_path> <output_patch_file_path>\n"
+               << "puffpatch usage:\n"
+               << " puffin -puffpatch <source_file_path> <output_file_path> "
+                  "<input_patch_file_path>";
+}
+
+const uint64_t kDefaultPuffCacheSize = 50 * 1024 * 1024;  // 50 MB
+
+// An enum representing the type of compressed files.
+enum class FileType { kDeflate, kZlib, kGzip, kZip, kRaw, kUnknown };
+
+// Returns a file type based on the input string `file_type` (normally the final
+// extension of the file).
+FileType StringToFileType(const string& file_type) {
+  if (file_type == "raw") {
+    return FileType::kRaw;
+  }
+  if (file_type == "deflate") {
+    return FileType::kDeflate;
+  } else if (file_type == "zlib") {
+    return FileType::kZlib;
+  } else if (file_type == "gzip" || file_type == "gz" || file_type == "tgz") {
+    return FileType::kGzip;
+  } else if (file_type == "zip" || file_type == "apk" || file_type == "jar" ||
+             file_type == "crx" || file_type == "crx2" || file_type == "crx3") {
+    return FileType::kZip;
+  }
+  return FileType::kUnknown;
+}
+
+// Finds the location of deflates in |stream|. If |file_type_to_override| is
+// non-empty, it infers the file type based on that, otherwise, it infers the
+// file type based on the final extension of |file_name|. It returns false if
+// file type cannot be inferred from any of the input arguments. |deflates|
+// is filled with byte-aligned location of deflates.
+bool LocateDeflatesBasedOnFileType(const UniqueStreamPtr& stream,
+                                   const string& file_name,
+                                   vector<BitExtent>* deflates) {
+  auto last_dot = file_name.find_last_of(".");
+  if (last_dot == string::npos) {
+    // Could not find a dot so we assume there is no extension.
+    return false;
+  }
+  auto extension = file_name.substr(last_dot + 1);
+  FileType file_type = StringToFileType(extension);
+
+  if (file_type == FileType::kRaw) {
+    // Do not need to populate |deflates|.
+    return true;
+  }
+
+  uint64_t stream_size = 0;
+  if (!stream->GetSize(&stream_size)) {
+    LOG(ERROR) << "Unable to get streamsize for file: " << file_name;
+    return false;
+  }
+  Buffer data(stream_size);
+  if (!stream->Read(data.data(), data.size())) {
+    LOG(ERROR) << "Unable to read stream for file: " << file_name;
+    return false;
+  }
+  switch (file_type) {
+    case FileType::kDeflate:
+      if (!puffin::LocateDeflatesInDeflateStream(data.data(), data.size(), 0,
+                                                 deflates, nullptr)) {
+        LOG(ERROR) << "Unable to find deflates in deflate stream for file: "
+                   << file_name;
+        return false;
+      }
+      break;
+    case FileType::kZlib:
+      if (!puffin::LocateDeflatesInZlib(data, deflates)) {
+        LOG(ERROR) << "Unable to find zlib deflates for file: " << file_name;
+        return false;
+      }
+      break;
+    case FileType::kGzip:
+      if (!puffin::LocateDeflatesInGzip(data, deflates)) {
+        LOG(ERROR) << "Unable to find gzip deflates for file: " << file_name;
+        return false;
+      }
+      break;
+    case FileType::kZip:
+      if (!puffin::LocateDeflatesInZipArchive(data, deflates)) {
+        LOG(ERROR) << "Unable to find zip deflates for file: " << file_name;
+        return false;
+      }
+      break;
+    default:
+      LOG(ERROR) << "Unknown file type: (" << extension << ").";
+      return false;
+  }
+  // Return the stream to its zero offset in case we used it.
+  if (!stream->Seek(0)) {
+    LOG(ERROR) << "Unable to return stream to its zero offset.";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+bool ExecutePuffDiff(const string& src_file_path,
+                     const string& dst_file_path,
+                     const string& patch_file_path) {
+  auto src_deflates_byte = vector<ByteExtent>();
+  auto dst_deflates_byte = vector<ByteExtent>();
+  auto src_deflates_bit = vector<BitExtent>();
+  auto dst_deflates_bit = vector<BitExtent>();
+  auto src_puffs = vector<ByteExtent>();
+  auto dst_puffs = vector<ByteExtent>();
+  puffin::UniqueStreamPtr src_stream =
+      FileStream::Open(src_file_path, true, false);
+  if (!src_stream) {
+    LOG(ERROR) << "Second argument of puffdiff must be a valid source filepath";
+    PrintHelp();
+    return false;
+  }
+  puffin::UniqueStreamPtr dst_stream =
+      FileStream::Open(dst_file_path, true, false);
+  if (!dst_stream) {
+    LOG(ERROR) << "Third argument must be a valid destination filepath";
+    PrintHelp();
+    return false;
+  }
+
+  if (!LocateDeflatesBasedOnFileType(src_stream, src_file_path,
+                                     &src_deflates_bit)) {
+    LOG(ERROR) << "Failed to locate deflates base on source filetype";
+    PrintHelp();
+    return false;
+  }
+  if (!LocateDeflatesBasedOnFileType(dst_stream, dst_file_path,
+                                     &dst_deflates_bit)) {
+    LOG(ERROR) << "Failed to locate deflates base on destination filetype";
+    PrintHelp();
+    return false;
+  }
+
+  if (src_deflates_bit.empty() && src_deflates_byte.empty()) {
+    LOG(WARNING) << "Warning: "
+                 << "You should pass source deflates, is this intentional?";
+  }
+  if (dst_deflates_bit.empty() && dst_deflates_byte.empty()) {
+    LOG(WARNING) << "Warning: "
+                 << "You should pass target deflates, is this intentional?";
+  }
+  if (src_deflates_bit.empty()) {
+    if (!FindDeflateSubBlocks(src_stream, src_deflates_byte,
+                              &src_deflates_bit)) {
+      LOG(ERROR) << "Unable to find deflate subblocks for source.";
+      return false;
+    }
+  }
+
+  if (dst_deflates_bit.empty()) {
+    if (!FindDeflateSubBlocks(dst_stream, dst_deflates_byte,
+                              &dst_deflates_bit)) {
+      LOG(ERROR) << "Unable to find deflate subblocks for destination";
+      return false;
+    }
+  }
+
+  Buffer puffdiff_delta;
+  if (!puffin::PuffDiff(std::move(src_stream), std::move(dst_stream),
+                        src_deflates_bit, dst_deflates_bit,
+                        {puffin::CompressorType::kBrotli},
+                        // TODO(crbug.com/1321247): we are currently just ALWAYS
+                        // doing zucchini with brotli, we might come back and
+                        // support bsdiff and/or bzip2.
+                        puffin::PatchAlgorithm::kZucchini, "/tmp/patch.tmp",
+                        &puffdiff_delta)) {
+    LOG(ERROR) << "Unable to generate PuffDiff";
+    return false;
+  }
+  LOG(INFO) << "patch_size: " << puffdiff_delta.size();
+  puffin::UniqueStreamPtr patch_stream =
+      FileStream::Open(patch_file_path, false, true);
+  if (!patch_stream) {
+    LOG(ERROR) << "Unable to open patch Stream";
+    return false;
+  }
+  if (!patch_stream->Write(puffdiff_delta.data(), puffdiff_delta.size())) {
+    LOG(ERROR) << "Unable to write to patch stream";
+    return false;
+  }
+  return true;
+}
+
+bool ExecutePuffPatch(const string& src_file_path,
+                      const string& dst_file_path,
+                      const string& patch_file_path) {
+  auto src_deflates_byte = vector<ByteExtent>();
+  auto dst_deflates_byte = vector<ByteExtent>();
+  auto src_deflates_bit = vector<BitExtent>();
+  auto dst_deflates_bit = vector<BitExtent>();
+  auto src_puffs = vector<ByteExtent>();
+  auto dst_puffs = vector<ByteExtent>();
+  puffin::UniqueStreamPtr src_stream =
+      FileStream::Open(src_file_path, true, false);
+  if (!src_stream) {
+    LOG(ERROR) << "Second argument must be a valid source filepath";
+    PrintHelp();
+    return false;
+  }
+  puffin::UniqueStreamPtr patch_stream =
+      FileStream::Open(patch_file_path, true, false);
+  if (!patch_stream) {
+    LOG(ERROR) << "Unable to open patch stream";
+    return false;
+  }
+  uint64_t patch_size = 0;
+  if (!patch_stream->GetSize(&patch_size)) {
+    LOG(ERROR) << "Unable obtain patch stream size";
+    return false;
+  }
+
+  Buffer puffdiff_delta(patch_size);
+  if (!patch_stream->Read(puffdiff_delta.data(), puffdiff_delta.size())) {
+    LOG(ERROR) << "Unable to read patch stream";
+    return false;
+  }
+  puffin::UniqueStreamPtr dst_stream =
+      FileStream::Open(dst_file_path, false, true);
+  if (!dst_stream) {
+    LOG(ERROR) << "Unable to open destination stream";
+    return false;
+  }
+  // Apply the patch. Use 50MB cache, it should be enough for most of the
+  // operations.
+  if (!puffin::PuffPatch(std::move(src_stream), std::move(dst_stream),
+                         puffdiff_delta.data(), puffdiff_delta.size(),
+                         kDefaultPuffCacheSize)) {
+    LOG(ERROR) << "Unable to patch file, an unknown error occurred.";
+    return false;
+  }
+  LOG(INFO) << "File Patched successfully!";
+  LOG(INFO) << "Output file: " << dst_file_path;
+  return true;
+}
+
+bool Main(int argc, char** argv) {
+  base::CommandLine::Init(argc, argv);
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_ALL;
+  settings.log_file_path = FILE_PATH_LITERAL("puffin.log");
+  std::ignore = logging::InitLogging(settings);
+  logging::SetMinLogLevel(logging::LOG_VERBOSE);
+  bool cmd_puffdiff = command_line.HasSwitch("puffdiff");
+  bool cmd_puffpatch = command_line.HasSwitch("puffpatch");
+
+  std::vector<base::FilePath> values;
+  for (const auto& arg : command_line.GetArgs()) {
+    values.emplace_back(arg);
+  }
+
+  if (cmd_puffdiff && !cmd_puffpatch) {
+    if (values.size() != 3) {
+      PrintHelp();
+      return false;
+    }
+
+    std::string src_file_path(values[0].AsUTF8Unsafe());
+    std::string dst_file_path(values[1].AsUTF8Unsafe());
+    std::string patch_file_path(values[2].AsUTF8Unsafe());
+
+    return ExecutePuffDiff(src_file_path, dst_file_path, patch_file_path);
+  } else if (cmd_puffpatch && !cmd_puffdiff) {
+    if (values.size() != 3) {
+      PrintHelp();
+      return false;
+    }
+
+    std::string src_file_path(values[0].AsUTF8Unsafe());
+    std::string dst_file_path(values[1].AsUTF8Unsafe());
+    std::string patch_file_path(values[2].AsUTF8Unsafe());
+
+    return ExecutePuffPatch(src_file_path, dst_file_path, patch_file_path);
+  }
+  // Only one operation must be selected. If zero or both are selected, fail.
+  LOG(ERROR) << "First argument must be one of:\n"
+                "  -puffdiff or -puffpatch.";
+  PrintHelp();
+  return false;
+}
+
+int main(int argc, char** argv) {
+  if (!Main(argc, argv)) {
+    return 1;
+  }
+  return 0;
+}
diff --git a/third_party/puffin/src/extent_stream.cc b/third_party/puffin/src/extent_stream.cc
deleted file mode 100644
index 3622125f..0000000
--- a/third_party/puffin/src/extent_stream.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2017 The Chromium OS 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 "puffin/src/extent_stream.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "puffin/src/logging.h"
-
-using std::vector;
-
-namespace puffin {
-
-UniqueStreamPtr ExtentStream::CreateForWrite(
-    UniqueStreamPtr stream, const vector<ByteExtent>& extents) {
-  return UniqueStreamPtr(new ExtentStream(std::move(stream), extents, true));
-}
-
-UniqueStreamPtr ExtentStream::CreateForRead(UniqueStreamPtr stream,
-                                            const vector<ByteExtent>& extents) {
-  return UniqueStreamPtr(new ExtentStream(std::move(stream), extents, false));
-}
-
-ExtentStream::ExtentStream(UniqueStreamPtr stream,
-                           const vector<ByteExtent>& extents,
-                           bool is_for_write)
-    : stream_(std::move(stream)),
-      extents_(extents),
-      cur_extent_offset_(0),
-      is_for_write_(is_for_write),
-      offset_(0) {
-  extents_upper_bounds_.reserve(extents_.size() + 1);
-  extents_upper_bounds_.emplace_back(0);
-  uint64_t total_size = 0;
-  uint64_t extent_end = 0;
-  for (const auto& extent : extents_) {
-    total_size += extent.length;
-    extents_upper_bounds_.emplace_back(total_size);
-    extent_end = extent.offset + extent.length;
-  }
-  size_ = total_size;
-
-  // Adding one extent at the end to avoid doing extra checks in:
-  // - Seek: when seeking to the end of extents
-  // - DoReadOrWrite: when changing the current extent.
-  extents_.emplace_back(extent_end, 0);
-  cur_extent_ = extents_.begin();
-}
-
-bool ExtentStream::GetSize(uint64_t* size) const {
-  *size = size_;
-  return true;
-}
-
-bool ExtentStream::GetOffset(uint64_t* offset) const {
-  *offset = offset_;
-  return true;
-}
-
-bool ExtentStream::Seek(uint64_t offset) {
-  TEST_AND_RETURN_FALSE(offset <= size_);
-
-  // The first item is zero and upper_bound never returns it because it always
-  // return the item which is greater than the given value.
-  auto extent_idx = std::upper_bound(extents_upper_bounds_.begin(),
-                                     extents_upper_bounds_.end(), offset) -
-                    extents_upper_bounds_.begin() - 1;
-  cur_extent_ = std::next(extents_.begin(), extent_idx);
-  offset_ = offset;
-  cur_extent_offset_ = offset_ - extents_upper_bounds_[extent_idx];
-  TEST_AND_RETURN_FALSE(
-      stream_->Seek(cur_extent_->offset + cur_extent_offset_));
-  return true;
-}
-
-bool ExtentStream::Close() {
-  return stream_->Close();
-}
-
-bool ExtentStream::Read(void* buffer, size_t length) {
-  TEST_AND_RETURN_FALSE(!is_for_write_);
-  TEST_AND_RETURN_FALSE(DoReadOrWrite(buffer, nullptr, length));
-  return true;
-}
-
-bool ExtentStream::Write(const void* buffer, size_t length) {
-  TEST_AND_RETURN_FALSE(is_for_write_);
-  TEST_AND_RETURN_FALSE(DoReadOrWrite(nullptr, buffer, length));
-  return true;
-}
-
-bool ExtentStream::DoReadOrWrite(void* read_buffer,
-                                 const void* write_buffer,
-                                 size_t length) {
-  uint64_t bytes_passed = 0;
-  while (bytes_passed < length) {
-    if (cur_extent_ == extents_.end()) {
-      return false;
-    }
-    uint64_t bytes_to_pass = std::min(length - bytes_passed,
-                                      cur_extent_->length - cur_extent_offset_);
-    if (read_buffer != nullptr) {
-      TEST_AND_RETURN_FALSE(
-          stream_->Read(reinterpret_cast<uint8_t*>(read_buffer) + bytes_passed,
-                        bytes_to_pass));
-    } else if (write_buffer != nullptr) {
-      TEST_AND_RETURN_FALSE(stream_->Write(
-          reinterpret_cast<const uint8_t*>(write_buffer) + bytes_passed,
-          bytes_to_pass));
-    } else {
-      LOG(ERROR) << "Either read or write buffer should be given!";
-      return false;
-    }
-
-    bytes_passed += bytes_to_pass;
-    cur_extent_offset_ += bytes_to_pass;
-    offset_ += bytes_to_pass;
-    if (cur_extent_offset_ == cur_extent_->length) {
-      // We have to advance the cur_extent_;
-      cur_extent_++;
-      cur_extent_offset_ = 0;
-      if (cur_extent_ != extents_.end()) {
-        TEST_AND_RETURN_FALSE(stream_->Seek(cur_extent_->offset));
-      }
-    }
-  }
-  return true;
-}
-
-}  // namespace puffin
diff --git a/third_party/puffin/src/extent_stream.h b/third_party/puffin/src/extent_stream.h
deleted file mode 100644
index 455f800..0000000
--- a/third_party/puffin/src/extent_stream.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2017 The Chromium OS 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 SRC_EXTENT_STREAM_H_
-#define SRC_EXTENT_STREAM_H_
-
-#include <memory>
-#include <vector>
-
-#include "puffin/src/include/puffin/common.h"
-#include "puffin/src/include/puffin/stream.h"
-
-namespace puffin {
-
-// A stream object that allows reading and writing into disk extents. This is
-// only used in main.cc for puffin binary to allow puffpatch on a actual rootfs
-// and kernel images.
-class ExtentStream : public StreamInterface {
- public:
-  // Creates a stream only for writing.
-  static UniqueStreamPtr CreateForWrite(UniqueStreamPtr stream,
-                                        const std::vector<ByteExtent>& extents);
-  // Creates a stream only for reading.
-  static UniqueStreamPtr CreateForRead(UniqueStreamPtr stream,
-                                       const std::vector<ByteExtent>& extents);
-  ~ExtentStream() override = default;
-
-  bool GetSize(uint64_t* size) const override;
-  bool GetOffset(uint64_t* offset) const override;
-  bool Seek(uint64_t offset) override;
-  bool Read(void* buffer, size_t length) override;
-  bool Write(const void* buffer, size_t length) override;
-  bool Close() override;
-
- private:
-  ExtentStream(UniqueStreamPtr stream,
-               const std::vector<ByteExtent>& extents,
-               bool is_for_write);
-
-  // Since both read and write operations are very similar in this class, this
-  // function acts as a common operation that does both write and read based on
-  // the nullability of |read_buffer| or |write_buffer|.
-  bool DoReadOrWrite(void* read_buffer,
-                     const void* write_buffer,
-                     size_t length);
-
-  // The underlying stream to read from and write into.
-  UniqueStreamPtr stream_;
-
-  std::vector<ByteExtent> extents_;
-
-  // The current |ByteExtent| that is being read from or write into.
-  std::vector<ByteExtent>::iterator cur_extent_;
-
-  // The current offset in the current |ByteExtent| |cur_extent_|.
-  uint64_t cur_extent_offset_;
-
-  // |True| if the stream is write only. |False| if the stream is read only.
-  bool is_for_write_;
-
-  // The size of the stream. It is actually the cumulative size of all the bytes
-  // in |extents_|.
-  uint64_t size_;
-
-  // The current offset.
-  uint64_t offset_;
-
-  // Used for proper and faster seeking.
-  std::vector<uint64_t> extents_upper_bounds_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtentStream);
-};
-
-}  // namespace puffin
-
-#endif  // SRC_EXTENT_STREAM_H_
diff --git a/third_party/puffin/src/file_stream.cc b/third_party/puffin/src/file_stream.cc
index de03723..b7a2ab5 100644
--- a/third_party/puffin/src/file_stream.cc
+++ b/third_party/puffin/src/file_stream.cc
@@ -5,11 +5,14 @@
 #include "puffin/file_stream.h"
 
 #include <fcntl.h>
-#include <unistd.h>
 
 #include <algorithm>
+#include <cstdint>
 #include <utility>
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/numerics/safe_conversions.h"
 #include "puffin/src/include/puffin/common.h"
 #include "puffin/src/logging.h"
 
@@ -19,51 +22,52 @@
 
 UniqueStreamPtr FileStream::Open(const string& path, bool read, bool write) {
   TEST_AND_RETURN_VALUE(read || write, nullptr);
-  int flags = O_CLOEXEC;
+
+  uint32_t flags = 0;
+  base::FilePath file_path = base::FilePath::FromUTF8Unsafe(path.c_str());
   if (read && write) {
-    flags |= O_RDWR | O_CREAT;
+    flags |= base::File::Flags::FLAG_READ | base::File::Flags::FLAG_WRITE |
+             base::File::Flags::FLAG_OPEN_ALWAYS;
   } else if (read) {
-    flags |= O_RDONLY;
+    flags |= base::File::Flags::FLAG_READ | base::File::Flags::FLAG_OPEN;
+    TEST_AND_RETURN_VALUE(PathExists(file_path), nullptr);
   } else {
-    flags |= O_WRONLY | O_CREAT;
+    flags |=
+        base::File::Flags::FLAG_WRITE | base::File::Flags::FLAG_OPEN_ALWAYS;
   }
-
-  mode_t mode = 0644;  // -rw-r--r--
-  int fd = open(path.c_str(), flags, mode);
-  TEST_AND_RETURN_VALUE(fd >= 0, nullptr);
-  return UniqueStreamPtr(new FileStream(fd));
+  return UniqueStreamPtr(new FileStream(file_path, flags));
 }
 
-bool FileStream::GetSize(uint64_t* size) const {
-  auto cur_off = lseek(fd_, 0, SEEK_CUR);
-  TEST_AND_RETURN_FALSE(cur_off >= 0);
-  auto fsize = lseek(fd_, 0, SEEK_END);
-  TEST_AND_RETURN_FALSE(fsize >= 0);
-  cur_off = lseek(fd_, cur_off, SEEK_SET);
-  TEST_AND_RETURN_FALSE(cur_off >= 0);
-  *size = fsize;
+bool FileStream::GetSize(uint64_t* size) {
+  TEST_AND_RETURN_FALSE(file_.IsValid());
+  int64_t result = file_.GetLength();
+  TEST_AND_RETURN_FALSE(result >= 0);
+  *size = base::as_unsigned(result);
   return true;
 }
 
-bool FileStream::GetOffset(uint64_t* offset) const {
-  auto off = lseek(fd_, 0, SEEK_CUR);
+bool FileStream::GetOffset(uint64_t* offset) {
+  int64_t off = file_.Seek(base::File::Whence::FROM_CURRENT, 0);
   TEST_AND_RETURN_FALSE(off >= 0);
-  *offset = off;
+  *offset = base::as_unsigned(off);
   return true;
 }
 
-bool FileStream::Seek(uint64_t offset) {
-  auto off = lseek(fd_, offset, SEEK_SET);
-  TEST_AND_RETURN_FALSE(off == static_cast<off_t>(offset));
+bool FileStream::Seek(uint64_t u_offset) {
+  TEST_AND_RETURN_FALSE(base::IsValueInRangeForNumericType<int64_t>(u_offset));
+  int64_t offset = base::as_signed(u_offset);
+  int64_t off =
+      base::as_signed(file_.Seek(base::File::Whence::FROM_BEGIN, offset));
+  TEST_AND_RETURN_FALSE(off == offset);
   return true;
 }
 
 bool FileStream::Read(void* buffer, size_t length) {
-  auto c_bytes = static_cast<uint8_t*>(buffer);
+  auto c_bytes = static_cast<char*>(buffer);
   size_t total_bytes_read = 0;
   while (total_bytes_read < length) {
-    auto bytes_read =
-        read(fd_, c_bytes + total_bytes_read, length - total_bytes_read);
+    auto bytes_read = file_.ReadAtCurrentPos(c_bytes + total_bytes_read,
+                                             length - total_bytes_read);
     // if bytes_read is zero then EOF is reached and we should not be here.
     TEST_AND_RETURN_FALSE(bytes_read > 0);
     total_bytes_read += bytes_read;
@@ -72,11 +76,11 @@
 }
 
 bool FileStream::Write(const void* buffer, size_t length) {
-  auto c_bytes = static_cast<const uint8_t*>(buffer);
+  auto c_bytes = static_cast<const char*>(buffer);
   size_t total_bytes_wrote = 0;
   while (total_bytes_wrote < length) {
-    auto bytes_wrote =
-        write(fd_, c_bytes + total_bytes_wrote, length - total_bytes_wrote);
+    auto bytes_wrote = file_.WriteAtCurrentPos(c_bytes + total_bytes_wrote,
+                                               length - total_bytes_wrote);
     TEST_AND_RETURN_FALSE(bytes_wrote >= 0);
     total_bytes_wrote += bytes_wrote;
   }
@@ -84,7 +88,11 @@
 }
 
 bool FileStream::Close() {
-  return close(fd_) == 0;
+  if (!file_.IsValid()) {
+    return false;
+  }
+  file_.Close();
+  return true;
 }
 
 }  // namespace puffin
diff --git a/third_party/puffin/src/fuzzer_huff.cc b/third_party/puffin/src/fuzzer_huff.cc
index 4002aa0..0ea1e46f 100644
--- a/third_party/puffin/src/fuzzer_huff.cc
+++ b/third_party/puffin/src/fuzzer_huff.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/logging.h"
-#include "brillo/test_helpers.h"
 
 #include "puffin/src/bit_writer.h"
 #include "puffin/src/include/puffin/common.h"
diff --git a/third_party/puffin/src/fuzzer_puff.cc b/third_party/puffin/src/fuzzer_puff.cc
index c4d26f69..2b8ab42c7 100644
--- a/third_party/puffin/src/fuzzer_puff.cc
+++ b/third_party/puffin/src/fuzzer_puff.cc
@@ -5,7 +5,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "brillo/test_helpers.h"
 
 #include "puffin/src/bit_reader.h"
 #include "puffin/src/include/puffin/common.h"
diff --git a/third_party/puffin/src/fuzzer_puffpatch.cc b/third_party/puffin/src/fuzzer_puffpatch.cc
index 1c0b749f..65ca221 100644
--- a/third_party/puffin/src/fuzzer_puffpatch.cc
+++ b/third_party/puffin/src/fuzzer_puffpatch.cc
@@ -5,7 +5,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "brillo/test_helpers.h"
 
 #include "puffin/memory_stream.h"
 #include "puffin/src/include/puffin/common.h"
diff --git a/third_party/puffin/src/huffer.cc b/third_party/puffin/src/huffer.cc
index 6119205..6c3af82 100644
--- a/third_party/puffin/src/huffer.cc
+++ b/third_party/puffin/src/huffer.cc
@@ -23,7 +23,7 @@
 
 Huffer::Huffer() : dyn_ht_(new HuffmanTable()), fix_ht_(new HuffmanTable()) {}
 
-Huffer::~Huffer() {}
+Huffer::~Huffer() = default;
 
 bool Huffer::HuffDeflate(PuffReaderInterface* pr,
                          BitWriterInterface* bw) const {
diff --git a/third_party/puffin/src/huffman_table.cc b/third_party/puffin/src/huffman_table.cc
index 3a12543..7858e66 100644
--- a/third_party/puffin/src/huffman_table.cc
+++ b/third_party/puffin/src/huffman_table.cc
@@ -48,7 +48,7 @@
 // 286 = 256 (coding a byte) +
 //         1 (coding the end of block symbole) +
 //        29 (coding the lengths)
-HuffmanTable::HuffmanTable() : codeindexpairs_(288), initialized_(false) {}
+HuffmanTable::HuffmanTable() : codeindexpairs_(288) {}
 
 bool HuffmanTable::InitHuffmanCodes(const Buffer& lens, size_t* max_bits) {
   // Temporary buffers used in |InitHuffmanCodes|.
diff --git a/third_party/puffin/src/huffman_table.h b/third_party/puffin/src/huffman_table.h
index e47f8ccf..4e5128b 100644
--- a/third_party/puffin/src/huffman_table.h
+++ b/third_party/puffin/src/huffman_table.h
@@ -286,7 +286,7 @@
   std::vector<uint16_t> code_rcodes_;
   size_t code_max_bits_;
 
-  bool initialized_;
+  bool initialized_{false};
 
   DISALLOW_COPY_AND_ASSIGN(HuffmanTable);
 };
diff --git a/third_party/puffin/src/include/puffin/common.h b/third_party/puffin/src/include/puffin/common.h
index 61e9eb2..f76c538 100644
--- a/third_party/puffin/src/include/puffin/common.h
+++ b/third_party/puffin/src/include/puffin/common.h
@@ -25,6 +25,12 @@
 
 namespace puffin {
 
+enum class CompressorType : uint8_t {
+  kNoCompression = 0,  // Unsupported by chromium/src's puffin implementation.
+  kBZ2 = 1,            // Unsupported by chromium/src's puffin implementation.
+  kBrotli = 2,
+};
+
 using Buffer = std::vector<uint8_t>;
 
 // This class is similar to the protobuf generated for |ProtoByteExtent|. We
diff --git a/third_party/puffin/src/include/puffin/file_stream.h b/third_party/puffin/src/include/puffin/file_stream.h
index 626d7c6..466983b 100644
--- a/third_party/puffin/src/include/puffin/file_stream.h
+++ b/third_party/puffin/src/include/puffin/file_stream.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <utility>
 
+#include "base/files/file.h"
+#include "base/files/file_path.h"
 #include "puffin/common.h"
 #include "puffin/stream.h"
 
@@ -16,13 +18,16 @@
 // A very simple class for reading and writing data into a file descriptor.
 class FileStream : public StreamInterface {
  public:
-  explicit FileStream(int fd) : fd_(fd) { Seek(0); }
+  FileStream(const base::FilePath& path, uint32_t flags) {
+    file_.Initialize(path, flags);
+    Seek(0);
+  }
   ~FileStream() override = default;
 
   static UniqueStreamPtr Open(const std::string& path, bool read, bool write);
 
-  bool GetSize(uint64_t* size) const override;
-  bool GetOffset(uint64_t* offset) const override;
+  bool GetSize(uint64_t* size) override;
+  bool GetOffset(uint64_t* offset) override;
   bool Seek(uint64_t offset) override;
   bool Read(void* buffer, size_t length) override;
   bool Write(const void* buffer, size_t length) override;
@@ -32,8 +37,7 @@
   FileStream() = default;
 
  private:
-  // The file descriptor.
-  int fd_;
+  base::File file_;
 
   DISALLOW_COPY_AND_ASSIGN(FileStream);
 };
diff --git a/third_party/puffin/src/include/puffin/memory_stream.h b/third_party/puffin/src/include/puffin/memory_stream.h
index a338e7f9..fa71d4f0 100644
--- a/third_party/puffin/src/include/puffin/memory_stream.h
+++ b/third_party/puffin/src/include/puffin/memory_stream.h
@@ -5,9 +5,6 @@
 #ifndef SRC_MEMORY_STREAM_H_
 #define SRC_MEMORY_STREAM_H_
 
-#include <string>
-#include <utility>
-
 #include "puffin/common.h"
 #include "puffin/stream.h"
 
@@ -26,8 +23,8 @@
   // the |memory|.
   static UniqueStreamPtr CreateForWrite(Buffer* memory);
 
-  bool GetSize(uint64_t* size) const override;
-  bool GetOffset(uint64_t* offset) const override;
+  bool GetSize(uint64_t* size) override;
+  bool GetOffset(uint64_t* offset) override;
   bool Seek(uint64_t offset) override;
   bool Read(void* buffer, size_t length) override;
   bool Write(const void* buffer, size_t length) override;
@@ -44,10 +41,10 @@
   Buffer* write_memory_;
 
   // The current offset.
-  uint64_t offset_;
+  uint64_t offset_{0};
 
   // True if the stream is open.
-  bool open_;
+  bool open_{true};
 
   DISALLOW_COPY_AND_ASSIGN(MemoryStream);
 };
diff --git a/third_party/puffin/src/include/puffin/puffdiff.h b/third_party/puffin/src/include/puffin/puffdiff.h
index ad8a106..f36e80fed 100644
--- a/third_party/puffin/src/include/puffin/puffdiff.h
+++ b/third_party/puffin/src/include/puffin/puffdiff.h
@@ -8,15 +8,13 @@
 #include <string>
 #include <vector>
 
-#include "bsdiff/constants.h"
-
 #include "puffin/common.h"
 #include "puffin/stream.h"
 
 namespace puffin {
 
 enum class PatchAlgorithm {
-  kBsdiff = 0,
+  kBsdiff = 0,  // Unsupported by chromium/src's Puffin implementation.
   kZucchini = 1,
 };
 
@@ -26,8 +24,7 @@
 // |dst|          IN   Destination deflate stream.
 // |src_deflates| IN   Deflate locations in |src|.
 // |dst_deflates| IN   Deflate locations in |dst|.
-// |compressors|  IN   Compressors to use in the underlying bsdiff, e.g.
-// bz2,
+// |compressors|  IN   Compressors to use in the underlying bsdiff, e.g. bz2,
 //                     brotli.
 // |patchAlgorithm|    IN   The patchAlgorithm used to create patches between
 //                     uncompressed bytes, e.g. bsdiff, zucchini.
@@ -39,7 +36,7 @@
               UniqueStreamPtr dst,
               const std::vector<BitExtent>& src_deflates,
               const std::vector<BitExtent>& dst_deflates,
-              const std::vector<bsdiff::CompressorType>& compressors,
+              const std::vector<puffin::CompressorType>& compressors,
               PatchAlgorithm patchAlgorithm,
               const std::string& tmp_filepath,
               Buffer* patch);
@@ -49,7 +46,7 @@
               UniqueStreamPtr dst,
               const std::vector<BitExtent>& src_deflates,
               const std::vector<BitExtent>& dst_deflates,
-              const std::vector<bsdiff::CompressorType>& compressors,
+              const std::vector<puffin::CompressorType>& compressors,
               const std::string& tmp_filepath,
               Buffer* patch);
 
@@ -59,7 +56,7 @@
               const Buffer& dst,
               const std::vector<BitExtent>& src_deflates,
               const std::vector<BitExtent>& dst_deflates,
-              const std::vector<bsdiff::CompressorType>& compressors,
+              const std::vector<puffin::CompressorType>& compressors,
               const std::string& tmp_filepath,
               Buffer* patch);
 
diff --git a/third_party/puffin/src/include/puffin/stream.h b/third_party/puffin/src/include/puffin/stream.h
index f480b59..c305c4d 100644
--- a/third_party/puffin/src/include/puffin/stream.h
+++ b/third_party/puffin/src/include/puffin/stream.h
@@ -18,11 +18,11 @@
   virtual ~StreamInterface() = default;
 
   // Returns the size of the stream.
-  virtual bool GetSize(uint64_t* size) const = 0;
+  virtual bool GetSize(uint64_t* size) = 0;
 
   // Returns the current offset in the stream where next read or write will
   // happen.
-  virtual bool GetOffset(uint64_t* offset) const = 0;
+  virtual bool GetOffset(uint64_t* offset) = 0;
 
   // Sets the offset in the stream for the next read or write. On error
   // returns |false|.
diff --git a/third_party/puffin/src/integration_test.cc b/third_party/puffin/src/integration_test.cc
index ab49445..f0eb9cf9 100644
--- a/third_party/puffin/src/integration_test.cc
+++ b/third_party/puffin/src/integration_test.cc
@@ -63,11 +63,11 @@
   ASSERT_TRUE(LocateDeflatesInZipArchive(kTestZipB, &dst_deflates));
 
   std::string tmp_file;
-  ASSERT_TRUE(MakeTempFile(&tmp_file, nullptr));
+  ASSERT_TRUE(MakeTempFile(&tmp_file));
   Buffer patch;
   ASSERT_TRUE(PuffDiff(MemoryStream::CreateForRead(kTestZipA),
                        MemoryStream::CreateForRead(kTestZipB), src_deflates,
-                       dst_deflates, {bsdiff::CompressorType::kBrotli},
+                       dst_deflates, {puffin::CompressorType::kBrotli},
                        getPatchType(), tmp_file, &patch));
 
   Buffer patched;
@@ -80,9 +80,8 @@
   ASSERT_EQ(kTestZipB, patched);
 }
 
-INSTANTIATE_TEST_CASE_P(TestWithPatchType,
-                        PuffinIntegrationTest,
-                        testing::Values(PatchAlgorithm::kBsdiff,
-                                        PatchAlgorithm::kZucchini));
+INSTANTIATE_TEST_SUITE_P(TestWithPatchType,
+                         PuffinIntegrationTest,
+                         testing::Values(PatchAlgorithm::kZucchini));
 
 }  // namespace puffin
\ No newline at end of file
diff --git a/third_party/puffin/src/logging.h b/third_party/puffin/src/logging.h
index 8b801532..1dcea647 100644
--- a/third_party/puffin/src/logging.h
+++ b/third_party/puffin/src/logging.h
@@ -5,14 +5,8 @@
 #ifndef SRC_LOGGING_H_
 #define SRC_LOGGING_H_
 
-#if defined(BASE_VER) && BASE_VER >= 822064
-#include "base/check.h"  // CHECK-related macros are defined in base/check.h on Chrome OS.
+#include "base/check.h"
 #include "base/logging.h"
-#elif USE_BRILLO
-#include "base/logging.h"
-#else
-#include "glog/logging.h"
-#endif
 
 #define TEST_AND_RETURN_FALSE(_x)   \
   do {                              \
diff --git a/third_party/puffin/src/main.cc b/third_party/puffin/src/main.cc
deleted file mode 100644
index 3dbb8ca6..0000000
--- a/third_party/puffin/src/main.cc
+++ /dev/null
@@ -1,413 +0,0 @@
-// Copyright 2017 The Chromium OS 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 <algorithm>
-#include <fstream>
-#include <iostream>
-#include <sstream>
-
-#ifdef USE_BRILLO
-#include "brillo/flag_helper.h"
-#else
-#include "gflags/gflags.h"
-#endif
-
-#include "puffin/file_stream.h"
-#include "puffin/memory_stream.h"
-#include "puffin/src/extent_stream.h"
-#include "puffin/src/include/puffin/common.h"
-#include "puffin/src/include/puffin/huffer.h"
-#include "puffin/src/include/puffin/puffdiff.h"
-#include "puffin/src/include/puffin/puffer.h"
-#include "puffin/src/include/puffin/puffpatch.h"
-#include "puffin/src/include/puffin/utils.h"
-#include "puffin/src/logging.h"
-#include "puffin/src/puffin_stream.h"
-
-using puffin::BitExtent;
-using puffin::Buffer;
-using puffin::ByteExtent;
-using puffin::ExtentStream;
-using puffin::FileStream;
-using puffin::Huffer;
-using puffin::MemoryStream;
-using puffin::Puffer;
-using puffin::PuffinStream;
-using puffin::UniqueStreamPtr;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-namespace {
-
-constexpr char kExtentDelimeter = ',';
-constexpr char kOffsetLengthDelimeter = ':';
-
-template <typename T>
-vector<T> StringToExtents(const string& str) {
-  vector<T> extents;
-  if (!str.empty()) {
-    stringstream ss(str);
-    string extent_str;
-    while (getline(ss, extent_str, kExtentDelimeter)) {
-      stringstream extent_ss(extent_str);
-      string offset_str, length_str;
-      getline(extent_ss, offset_str, kOffsetLengthDelimeter);
-      getline(extent_ss, length_str, kOffsetLengthDelimeter);
-      extents.emplace_back(stoull(offset_str), stoull(length_str));
-    }
-  }
-  return extents;
-}
-
-const uint64_t kDefaultPuffCacheSize = 50 * 1024 * 1024;  // 50 MB
-
-// An enum representing the type of compressed files.
-enum class FileType { kDeflate, kZlib, kGzip, kZip, kRaw, kUnknown };
-
-// Returns a file type based on the input string |file_type| (normally the final
-// extension of the file).
-FileType StringToFileType(const string& file_type) {
-  if (file_type == "raw") {
-    return FileType::kRaw;
-  }
-  if (file_type == "deflate") {
-    return FileType::kDeflate;
-  } else if (file_type == "zlib") {
-    return FileType::kZlib;
-  } else if (file_type == "gzip" || file_type == "gz" || file_type == "tgz") {
-    return FileType::kGzip;
-  } else if (file_type == "zip" || file_type == "apk" || file_type == "jar") {
-    return FileType::kZip;
-  }
-  return FileType::kUnknown;
-}
-
-// Finds the location of deflates in |stream|. If |file_type_to_override| is
-// non-empty, it infers the file type based on that, otherwise, it infers the
-// file type based on the final extension of |file_name|. It returns false if
-// file type cannot be inferred from any of the input arguments. |deflates|
-// is filled with byte-aligned location of deflates.
-bool LocateDeflatesBasedOnFileType(const UniqueStreamPtr& stream,
-                                   const string& file_name,
-                                   const string& file_type_to_override,
-                                   vector<BitExtent>* deflates) {
-  auto file_type = FileType::kUnknown;
-
-  auto last_dot = file_name.find_last_of(".");
-  if (last_dot == string::npos) {
-    // Could not find a dot so we assume there is no extension.
-    return false;
-  }
-  auto extension = file_name.substr(last_dot + 1);
-  file_type = StringToFileType(extension);
-
-  if (!file_type_to_override.empty()) {
-    auto override_file_type = StringToFileType(file_type_to_override);
-    if (override_file_type == FileType::kUnknown) {
-      LOG(ERROR) << "Overriden file type " << file_type_to_override
-                 << " does not exist.";
-      return false;
-    }
-    if (file_type != FileType::kUnknown && file_type != override_file_type) {
-      LOG(WARNING) << "Based on the file name, the file type is " << extension
-                   << ", But the overriden file type is "
-                   << file_type_to_override << ". Is this intentional?";
-    }
-    file_type = override_file_type;
-  }
-
-  if (file_type == FileType::kRaw) {
-    // Do not need to populate |deflates|.
-    return true;
-  }
-
-  uint64_t stream_size;
-  TEST_AND_RETURN_FALSE(stream->GetSize(&stream_size));
-  Buffer data(stream_size);
-  TEST_AND_RETURN_FALSE(stream->Read(data.data(), data.size()));
-  switch (file_type) {
-    case FileType::kDeflate:
-      TEST_AND_RETURN_FALSE(puffin::LocateDeflatesInDeflateStream(
-          data.data(), data.size(), 0, deflates, nullptr));
-      break;
-    case FileType::kZlib:
-      TEST_AND_RETURN_FALSE(puffin::LocateDeflatesInZlib(data, deflates));
-      break;
-    case FileType::kGzip:
-      TEST_AND_RETURN_FALSE(puffin::LocateDeflatesInGzip(data, deflates));
-      break;
-    case FileType::kZip:
-      TEST_AND_RETURN_FALSE(puffin::LocateDeflatesInZipArchive(data, deflates));
-      break;
-    default:
-      LOG(ERROR) << "Unknown file type: (" << file_type_to_override << ") nor ("
-                 << extension << ").";
-      return false;
-  }
-  // Return the stream to its zero offset in case we used it.
-  TEST_AND_RETURN_FALSE(stream->Seek(0));
-
-  return true;
-}
-
-}  // namespace
-
-#define SETUP_FLAGS                                                          \
-  DEFINE_string(src_file, "", "Source file");                                \
-  DEFINE_string(dst_file, "", "Target file");                                \
-  DEFINE_string(patch_file, "", "patch file");                               \
-  DEFINE_string(                                                             \
-      src_deflates_byte, "",                                                 \
-      "Source deflate byte locations in the format offset:length,...");      \
-  DEFINE_string(                                                             \
-      dst_deflates_byte, "",                                                 \
-      "Target deflate byte locations in the format offset:length,...");      \
-  DEFINE_string(                                                             \
-      src_deflates_bit, "",                                                  \
-      "Source deflate bit locations in the format offset:length,...");       \
-  DEFINE_string(                                                             \
-      dst_deflates_bit, "",                                                  \
-      "Target deflatebit locations in the format offset:length,...");        \
-  DEFINE_string(src_puffs, "",                                               \
-                "Source puff locations in the format offset:length,...");    \
-  DEFINE_string(dst_puffs, "",                                               \
-                "Target puff locations in the format offset:length,...");    \
-  DEFINE_string(src_extents, "",                                             \
-                "Source extents in the format of offset:length,...");        \
-  DEFINE_string(dst_extents, "",                                             \
-                "Target extents in the format of offset:length,...");        \
-  DEFINE_string(operation, "",                                               \
-                "Type of the operation: puff, huff, puffdiff, puffpatch, "   \
-                "puffhuff");                                                 \
-  DEFINE_string(src_file_type, "",                                           \
-                "Type of the input source file: deflate, gzip, "             \
-                "zlib or zip");                                              \
-  DEFINE_string(dst_file_type, "",                                           \
-                "Same as src_file_type but for the target file");            \
-  DEFINE_bool(verbose, false,                                                \
-              "Logs all the given parameters including internally "          \
-              "generated ones");                                             \
-  DEFINE_uint64(cache_size, kDefaultPuffCacheSize,                           \
-                "Maximum size to cache the puff stream. Used in puffpatch"); \
-  DEFINE_int32(patch_algorithm, 0,                                           \
-               "Type of raw diff algorithm to use. The current supported "   \
-               "ones are 0: bsdiff, 1: zucchini.");
-#ifndef USE_BRILLO
-SETUP_FLAGS;
-#endif
-
-// Main entry point to the application.
-bool Main(int argc, char** argv) {
-#ifdef USE_BRILLO
-  SETUP_FLAGS;
-  brillo::FlagHelper::Init(argc, argv, "Puffin tool");
-#else
-  // google::InitGoogleLogging(argv[0]);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-#endif
-
-  TEST_AND_RETURN_FALSE(!FLAGS_operation.empty());
-  TEST_AND_RETURN_FALSE(!FLAGS_src_file.empty());
-  TEST_AND_RETURN_FALSE(!FLAGS_dst_file.empty());
-
-  auto src_deflates_byte = StringToExtents<ByteExtent>(FLAGS_src_deflates_byte);
-  auto dst_deflates_byte = StringToExtents<ByteExtent>(FLAGS_dst_deflates_byte);
-  auto src_deflates_bit = StringToExtents<BitExtent>(FLAGS_src_deflates_bit);
-  auto dst_deflates_bit = StringToExtents<BitExtent>(FLAGS_dst_deflates_bit);
-  auto src_puffs = StringToExtents<ByteExtent>(FLAGS_src_puffs);
-  auto dst_puffs = StringToExtents<ByteExtent>(FLAGS_dst_puffs);
-  auto src_extents = StringToExtents<ByteExtent>(FLAGS_src_extents);
-  auto dst_extents = StringToExtents<ByteExtent>(FLAGS_dst_extents);
-
-  auto src_stream = FileStream::Open(FLAGS_src_file, true, false);
-  TEST_AND_RETURN_FALSE(src_stream);
-  if (!src_extents.empty()) {
-    src_stream =
-        ExtentStream::CreateForRead(std::move(src_stream), src_extents);
-    TEST_AND_RETURN_FALSE(src_stream);
-  }
-
-  if (FLAGS_operation == "puff" || FLAGS_operation == "puffhuff") {
-    TEST_AND_RETURN_FALSE(LocateDeflatesBasedOnFileType(
-        src_stream, FLAGS_src_file, FLAGS_src_file_type, &src_deflates_bit));
-
-    if (src_deflates_bit.empty() && src_deflates_byte.empty()) {
-      LOG(WARNING) << "You should pass source deflates, is this intentional?";
-    }
-    if (src_deflates_bit.empty()) {
-      TEST_AND_RETURN_FALSE(FindDeflateSubBlocks(src_stream, src_deflates_byte,
-                                                 &src_deflates_bit));
-    }
-    TEST_AND_RETURN_FALSE(dst_puffs.empty());
-    uint64_t dst_puff_size;
-    TEST_AND_RETURN_FALSE(FindPuffLocations(src_stream, src_deflates_bit,
-                                            &dst_puffs, &dst_puff_size));
-
-    auto dst_stream = FileStream::Open(FLAGS_dst_file, false, true);
-    TEST_AND_RETURN_FALSE(dst_stream);
-    auto puffer = std::make_shared<Puffer>();
-    auto reader =
-        PuffinStream::CreateForPuff(std::move(src_stream), puffer,
-                                    dst_puff_size, src_deflates_bit, dst_puffs);
-
-    Buffer puff_buffer;
-    auto writer = FLAGS_operation == "puffhuff"
-                      ? MemoryStream::CreateForWrite(&puff_buffer)
-                      : std::move(dst_stream);
-
-    Buffer buffer(1024 * 1024);
-    uint64_t bytes_wrote = 0;
-    while (bytes_wrote < dst_puff_size) {
-      auto write_size = std::min(static_cast<uint64_t>(buffer.size()),
-                                 dst_puff_size - bytes_wrote);
-      TEST_AND_RETURN_FALSE(reader->Read(buffer.data(), write_size));
-      TEST_AND_RETURN_FALSE(writer->Write(buffer.data(), write_size));
-      bytes_wrote += write_size;
-    }
-
-    // puffhuff operation puffs a stream and huffs it back to the target stream
-    // to make sure we can get to the original stream.
-    if (FLAGS_operation == "puffhuff") {
-      src_puffs = dst_puffs;
-      dst_deflates_byte = src_deflates_byte;
-      dst_deflates_bit = src_deflates_bit;
-
-      auto read_puff_stream = MemoryStream::CreateForRead(puff_buffer);
-      auto huffer = std::make_shared<Huffer>();
-      auto huff_writer = PuffinStream::CreateForHuff(
-          std::move(dst_stream), huffer, dst_puff_size, dst_deflates_bit,
-          src_puffs);
-
-      uint64_t bytes_read = 0;
-      while (bytes_read < dst_puff_size) {
-        auto read_size = std::min(static_cast<uint64_t>(buffer.size()),
-                                  dst_puff_size - bytes_read);
-        TEST_AND_RETURN_FALSE(read_puff_stream->Read(buffer.data(), read_size));
-        TEST_AND_RETURN_FALSE(huff_writer->Write(buffer.data(), read_size));
-        bytes_read += read_size;
-      }
-    }
-  } else if (FLAGS_operation == "huff") {
-    if (dst_deflates_bit.empty() && src_puffs.empty()) {
-      LOG(WARNING) << "You should pass source puffs and destination deflates"
-                   << ", is this intentional?";
-    }
-    TEST_AND_RETURN_FALSE(src_puffs.size() == dst_deflates_bit.size());
-    uint64_t src_stream_size;
-    TEST_AND_RETURN_FALSE(src_stream->GetSize(&src_stream_size));
-    auto dst_file = FileStream::Open(FLAGS_dst_file, false, true);
-    TEST_AND_RETURN_FALSE(dst_file);
-
-    auto huffer = std::make_shared<Huffer>();
-    auto dst_stream = PuffinStream::CreateForHuff(std::move(dst_file), huffer,
-                                                  src_stream_size,
-                                                  dst_deflates_bit, src_puffs);
-
-    Buffer buffer(1024 * 1024);
-    uint64_t bytes_read = 0;
-    while (bytes_read < src_stream_size) {
-      auto read_size = std::min(static_cast<uint64_t>(buffer.size()),
-                                src_stream_size - bytes_read);
-      TEST_AND_RETURN_FALSE(src_stream->Read(buffer.data(), read_size));
-      TEST_AND_RETURN_FALSE(dst_stream->Write(buffer.data(), read_size));
-      bytes_read += read_size;
-    }
-  } else if (FLAGS_operation == "puffdiff") {
-    auto dst_stream = FileStream::Open(FLAGS_dst_file, true, false);
-    TEST_AND_RETURN_FALSE(dst_stream);
-
-    TEST_AND_RETURN_FALSE(LocateDeflatesBasedOnFileType(
-        src_stream, FLAGS_src_file, FLAGS_src_file_type, &src_deflates_bit));
-    TEST_AND_RETURN_FALSE(LocateDeflatesBasedOnFileType(
-        dst_stream, FLAGS_dst_file, FLAGS_dst_file_type, &dst_deflates_bit));
-
-    if (src_deflates_bit.empty() && src_deflates_byte.empty()) {
-      LOG(WARNING) << "You should pass source deflates, is this intentional?";
-    }
-    if (dst_deflates_bit.empty() && dst_deflates_byte.empty()) {
-      LOG(WARNING) << "You should pass target deflates, is this intentional?";
-    }
-    if (!dst_extents.empty()) {
-      dst_stream =
-          ExtentStream::CreateForWrite(std::move(dst_stream), dst_extents);
-      TEST_AND_RETURN_FALSE(dst_stream);
-    }
-
-    if (src_deflates_bit.empty()) {
-      TEST_AND_RETURN_FALSE(FindDeflateSubBlocks(src_stream, src_deflates_byte,
-                                                 &src_deflates_bit));
-    }
-
-    if (dst_deflates_bit.empty()) {
-      TEST_AND_RETURN_FALSE(FindDeflateSubBlocks(dst_stream, dst_deflates_byte,
-                                                 &dst_deflates_bit));
-    }
-
-    if (FLAGS_patch_algorithm != 0 && FLAGS_patch_algorithm != 1) {
-      LOG(ERROR)
-          << "The supported patch algorithms are 0: bsdiff, 1: zucchini.";
-      return false;
-    }
-    // TODO(xunchang) add flags to select the bsdiff compressors.
-    Buffer puffdiff_delta;
-    TEST_AND_RETURN_FALSE(puffin::PuffDiff(
-        std::move(src_stream), std::move(dst_stream), src_deflates_bit,
-        dst_deflates_bit,
-        {bsdiff::CompressorType::kBZ2, bsdiff::CompressorType::kBrotli},
-        static_cast<puffin::PatchAlgorithm>(FLAGS_patch_algorithm),
-        "/tmp/patch.tmp", &puffdiff_delta));
-    if (FLAGS_verbose) {
-      LOG(INFO) << "patch_size: " << puffdiff_delta.size();
-    }
-    auto patch_stream = FileStream::Open(FLAGS_patch_file, false, true);
-    TEST_AND_RETURN_FALSE(patch_stream);
-    TEST_AND_RETURN_FALSE(
-        patch_stream->Write(puffdiff_delta.data(), puffdiff_delta.size()));
-  } else if (FLAGS_operation == "puffpatch") {
-    auto patch_stream = FileStream::Open(FLAGS_patch_file, true, false);
-    TEST_AND_RETURN_FALSE(patch_stream);
-    uint64_t patch_size;
-    TEST_AND_RETURN_FALSE(patch_stream->GetSize(&patch_size));
-
-    Buffer puffdiff_delta(patch_size);
-    TEST_AND_RETURN_FALSE(
-        patch_stream->Read(puffdiff_delta.data(), puffdiff_delta.size()));
-    auto dst_stream = FileStream::Open(FLAGS_dst_file, false, true);
-    TEST_AND_RETURN_FALSE(dst_stream);
-    if (!dst_extents.empty()) {
-      dst_stream =
-          ExtentStream::CreateForWrite(std::move(dst_stream), dst_extents);
-      TEST_AND_RETURN_FALSE(dst_stream);
-    }
-    // Apply the patch. Use 50MB cache, it should be enough for most of the
-    // operations.
-    TEST_AND_RETURN_FALSE(puffin::PuffPatch(
-        std::move(src_stream), std::move(dst_stream), puffdiff_delta.data(),
-        puffdiff_delta.size(), FLAGS_cache_size));
-  }
-
-  if (FLAGS_verbose) {
-    LOG(INFO) << "src_deflates_byte: "
-              << puffin::ExtentsToString(src_deflates_byte);
-    LOG(INFO) << "dst_deflates_byte: "
-              << puffin::ExtentsToString(dst_deflates_byte);
-    LOG(INFO) << "src_deflates_bit: "
-              << puffin::ExtentsToString(src_deflates_bit);
-    LOG(INFO) << "dst_deflates_bit: "
-              << puffin::ExtentsToString(dst_deflates_bit);
-    LOG(INFO) << "src_puffs: " << puffin::ExtentsToString(src_puffs);
-    LOG(INFO) << "dst_puffs: " << puffin::ExtentsToString(dst_puffs);
-    LOG(INFO) << "src_extents: " << puffin::ExtentsToString(src_extents);
-    LOG(INFO) << "dst_extents: " << puffin::ExtentsToString(dst_extents);
-  }
-  return true;
-}
-
-int main(int argc, char** argv) {
-  if (!Main(argc, argv)) {
-    return 1;
-  }
-  return 0;
-}
diff --git a/third_party/puffin/src/memory_stream.cc b/third_party/puffin/src/memory_stream.cc
index 8a2afdd..599f1af 100644
--- a/third_party/puffin/src/memory_stream.cc
+++ b/third_party/puffin/src/memory_stream.cc
@@ -5,11 +5,12 @@
 #include "puffin/memory_stream.h"
 
 #include <fcntl.h>
-#include <unistd.h>
-
 #include <algorithm>
 #include <utility>
 
+#include "base/files/file.h"
+#include "base/numerics/safe_conversions.h"
+
 #include "puffin/src/include/puffin/common.h"
 #include "puffin/src/logging.h"
 
@@ -24,18 +25,15 @@
 }
 
 MemoryStream::MemoryStream(const Buffer* read_memory, Buffer* write_memory)
-    : read_memory_(read_memory),
-      write_memory_(write_memory),
-      offset_(0),
-      open_(true) {}
+    : read_memory_(read_memory), write_memory_(write_memory) {}
 
-bool MemoryStream::GetSize(uint64_t* size) const {
+bool MemoryStream::GetSize(uint64_t* size) {
   *size =
       read_memory_ != nullptr ? read_memory_->size() : write_memory_->size();
   return true;
 }
 
-bool MemoryStream::GetOffset(uint64_t* offset) const {
+bool MemoryStream::GetOffset(uint64_t* offset) {
   *offset = offset_;
   return true;
 }
@@ -52,6 +50,7 @@
 bool MemoryStream::Read(void* buffer, size_t length) {
   TEST_AND_RETURN_FALSE(open_);
   TEST_AND_RETURN_FALSE(read_memory_ != nullptr);
+  TEST_AND_RETURN_FALSE(base::IsValueInRangeForNumericType<int64_t>(length));
   TEST_AND_RETURN_FALSE(offset_ + length <= read_memory_->size());
   memcpy(buffer, read_memory_->data() + offset_, length);
   offset_ += length;
@@ -62,6 +61,7 @@
   // TODO(ahassani): Add a maximum size limit to prevent malicious attacks.
   TEST_AND_RETURN_FALSE(open_);
   TEST_AND_RETURN_FALSE(write_memory_ != nullptr);
+  TEST_AND_RETURN_FALSE(base::IsValueInRangeForNumericType<int64_t>(length));
   if (offset_ + length > write_memory_->size()) {
     write_memory_->resize(offset_ + length);
   }
diff --git a/third_party/puffin/src/patching_unittest.cc b/third_party/puffin/src/patching_unittest.cc
index 72a3099..3a73ac2 100644
--- a/third_party/puffin/src/patching_unittest.cc
+++ b/third_party/puffin/src/patching_unittest.cc
@@ -46,85 +46,51 @@
 #endif
 
 const Buffer kPatch1To2 = {
-    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x51, 0x08, 0x01, 0x12, 0x27,
+    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x53, 0x08, 0x01, 0x12, 0x27,
     0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
     0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
     0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
     0x38, 0x18, 0x1F, 0x1A, 0x24, 0x0A, 0x02, 0x10, 0x32, 0x0A, 0x04, 0x08,
     0x48, 0x10, 0x50, 0x0A, 0x05, 0x08, 0x98, 0x01, 0x10, 0x12, 0x12, 0x02,
     0x10, 0x58, 0x12, 0x04, 0x08, 0x70, 0x10, 0x58, 0x12, 0x05, 0x08, 0xC8,
-    0x01, 0x10, 0x38, 0x18, 0x21, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
-    0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xD1,
-    0x20, 0xBB, 0x7E, 0x00, 0x00, 0x03, 0x60, 0x40, 0x78, 0x0E, 0x08, 0x00,
-    0x40, 0x00, 0x20, 0x00, 0x31, 0x06, 0x4C, 0x40, 0x92, 0x8F, 0x46, 0xA7,
-    0xA8, 0xE0, 0xF3, 0xD6, 0x21, 0x12, 0xF4, 0xBC, 0x43, 0x32, 0x1F, 0x17,
-    0x72, 0x45, 0x38, 0x50, 0x90, 0xD1, 0x20, 0xBB, 0x7E, 0x42, 0x5A, 0x68,
-    0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xF1, 0x20, 0x5F, 0x0D, 0x00,
-    0x00, 0x02, 0x41, 0x15, 0x42, 0x08, 0x20, 0x00, 0x40, 0x00, 0x00, 0x02,
-    0x40, 0x00, 0x20, 0x00, 0x22, 0x3D, 0x23, 0x10, 0x86, 0x03, 0x96, 0x54,
-    0x11, 0x16, 0x5F, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0xF1, 0x20, 0x5F,
-    0x0D, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x07,
-    0xD4, 0xCB, 0x6E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x00,
-    0x21, 0x18, 0x46, 0x82, 0xEE, 0x48, 0xA7, 0x0A, 0x12, 0x00, 0xFA, 0x99,
-    0x6D, 0xC0};
+    0x01, 0x10, 0x38, 0x18, 0x21, 0x20, 0x01, 0x17, 0x68, 0x00, 0x00, 0xC4,
+    0xCA, 0xB3, 0xBD, 0x3C, 0x18, 0x8B, 0x67, 0x42, 0x10, 0xD0, 0x14, 0xDF,
+    0x4F, 0xFB, 0x7B, 0x4B, 0x56, 0x93, 0x72, 0x85, 0xEB, 0xF5, 0x42, 0x2E,
+    0x0E, 0x78, 0x60, 0x13, 0x9D, 0xEB, 0x6B, 0x97, 0x48, 0x96, 0x68, 0x8E,
+    0x79, 0x8C, 0x65, 0x19, 0x8E, 0x84, 0x4C, 0xF6, 0xB6, 0x25, 0x00, 0x66,
+    0x9F, 0xCA, 0xDD, 0x56, 0xF3, 0x86, 0xD9, 0xD7, 0x37, 0x36, 0x0C, 0xD8,
+    0x8F, 0xC1, 0x04, 0x4B, 0x5C, 0x08, 0x52, 0xFA, 0x1F, 0x80, 0x43, 0x10,
+    0xE3, 0x42, 0xFE, 0x27, 0x70, 0x81, 0x78, 0x19};
 
 const Buffer kPatch2To1 = {
-    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x51, 0x08, 0x01, 0x12, 0x24,
+    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x53, 0x08, 0x01, 0x12, 0x24,
     0x0A, 0x02, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x48, 0x10, 0x50, 0x0A, 0x05,
     0x08, 0x98, 0x01, 0x10, 0x12, 0x12, 0x02, 0x10, 0x58, 0x12, 0x04, 0x08,
     0x70, 0x10, 0x58, 0x12, 0x05, 0x08, 0xC8, 0x01, 0x10, 0x38, 0x18, 0x21,
     0x1A, 0x27, 0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50,
     0x10, 0x0A, 0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10,
     0x10, 0x58, 0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8,
-    0x01, 0x10, 0x38, 0x18, 0x1F, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
-    0x01, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x3D,
-    0xBD, 0x08, 0x91, 0x00, 0x00, 0x01, 0xE0, 0x40, 0x5C, 0x0A, 0x40, 0x00,
-    0x40, 0x00, 0x20, 0x00, 0x31, 0x0C, 0x08, 0x23, 0xD2, 0x34, 0xD1, 0xB1,
-    0x73, 0x60, 0x44, 0x54, 0xE4, 0xFC, 0x5D, 0xC9, 0x14, 0xE1, 0x42, 0x40,
-    0xF6, 0xF4, 0x22, 0x44, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
-    0x53, 0x59, 0x41, 0x62, 0x2E, 0xF0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40,
-    0x20, 0x20, 0x00, 0x21, 0x00, 0x82, 0x83, 0x17, 0x72, 0x45, 0x38, 0x50,
-    0x90, 0x41, 0x62, 0x2E, 0xF0, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59,
-    0x26, 0x53, 0x59, 0xE0, 0x20, 0x04, 0x57, 0x00, 0x00, 0x04, 0x76, 0x50,
-    0xE0, 0x00, 0x20, 0x00, 0x10, 0x00, 0x04, 0x00, 0x02, 0x00, 0x20, 0x00,
-    0x40, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x21, 0xA1, 0xA3, 0x10, 0x83, 0x26,
-    0x21, 0x5E, 0xB2, 0x69, 0xAC, 0x70, 0x60, 0x53, 0xC5, 0xDC, 0x91, 0x4E,
-    0x14, 0x24, 0x38, 0x08, 0x01, 0x15, 0xC0};
-
-const Buffer kPatch1ToEmpty = {
-    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x08, 0x01, 0x12, 0x27,
-    0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
-    0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
-    0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
-    0x38, 0x18, 0x1F, 0x1A, 0x00, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
-    0x01, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00,
-    0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50,
-    0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45,
-    0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00};
+    0x01, 0x10, 0x38, 0x18, 0x1F, 0x20, 0x01, 0x17, 0x66, 0x00, 0x00, 0xC4,
+    0xE7, 0xBD, 0xF5, 0x37, 0xBF, 0x41, 0xB6, 0x12, 0xCF, 0xE2, 0xA2, 0xF3,
+    0x78, 0xDE, 0xFD, 0x3C, 0xB2, 0x99, 0xC4, 0x09, 0xE7, 0x79, 0x50, 0x93,
+    0xF3, 0xA8, 0xC0, 0x12, 0xCD, 0xF5, 0xE2, 0xE6, 0xAF, 0x59, 0xA8, 0x79,
+    0x0E, 0x73, 0x39, 0x28, 0xD2, 0x56, 0xCB, 0x73, 0x9A, 0x08, 0x00, 0xEF,
+    0xDE, 0xAC, 0xFE, 0x8C, 0xF6, 0xE9, 0x83, 0xFB, 0x3E, 0xF8, 0x51, 0x20,
+    0xA3, 0x39, 0x5E, 0x9A, 0x0C, 0xA3, 0xC1, 0xB4, 0x2B, 0x5F, 0xEE, 0xBF,
+    0x2C, 0x07, 0x92, 0x2F, 0x4C, 0x50};
 
 const Buffer kPatch1ToNoDeflate = {
-    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x2F, 0x08, 0x01, 0x12, 0x27,
+    0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x31, 0x08, 0x01, 0x12, 0x27,
     0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
     0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
     0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
-    0x38, 0x18, 0x1F, 0x1A, 0x02, 0x18, 0x04, 0x42, 0x53, 0x44, 0x46, 0x32,
-    0x01, 0x01, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53,
-    0x59, 0xBA, 0x8D, 0x7F, 0x2D, 0x00, 0x00, 0x00, 0x40, 0x00, 0x44, 0x08,
-    0x20, 0x00, 0x30, 0xCC, 0x09, 0x32, 0x54, 0x65, 0x38, 0xBB, 0x92, 0x29,
-    0xC2, 0x84, 0x85, 0xD4, 0x6B, 0xF9, 0x68, 0x42, 0x5A, 0x68, 0x39, 0x17,
-    0x72, 0x45, 0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68,
-    0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xE7, 0xAA, 0xF1, 0xFC, 0x00,
-    0x00, 0x00, 0x70, 0x00, 0x00, 0x08, 0x01, 0x00, 0x20, 0x04, 0x20, 0x00,
-    0x21, 0x9A, 0x68, 0x33, 0x4D, 0x13, 0x3C, 0x5D, 0xC9, 0x14, 0xE1, 0x42,
-    0x43, 0x9E, 0xAB, 0xC7, 0xF0};
+    0x38, 0x18, 0x1F, 0x1A, 0x02, 0x18, 0x04, 0x20, 0x01, 0x17, 0x55, 0x00,
+    0x00, 0x04, 0x22, 0x77, 0xF7, 0x5B, 0x96, 0xA7, 0x2D, 0x0F, 0x34, 0xD0,
+    0x8A, 0xA3, 0xB6, 0x9F, 0x97, 0xA4, 0x10, 0x41, 0x1C, 0x60, 0x64, 0x79,
+    0xC0, 0xDD, 0x89, 0xF7, 0xEB, 0xCD, 0x38, 0x73, 0xAE, 0x81, 0x87, 0x6C,
+    0x17, 0x14, 0x45, 0x80, 0xDB, 0x52, 0x15, 0xC0, 0xF7, 0xF6, 0x74, 0x4C,
+    0xF2, 0xFE, 0xAE, 0xBB, 0xF9, 0x54, 0x02, 0x79, 0x94, 0x39, 0x7E, 0xD6,
+    0x85, 0x88, 0x00};
 
 }  // namespace
 
@@ -135,13 +101,15 @@
                   const Buffer patch) {
   Buffer patch_out;
   string patch_path;
-  ASSERT_TRUE(MakeTempFile(&patch_path, nullptr));
+  ASSERT_TRUE(MakeTempFile(&patch_path));
   ScopedPathUnlinker scoped_unlinker(patch_path);
   ASSERT_TRUE(PuffDiff(src_buf, dst_buf, src_deflates, dst_deflates,
-                       {bsdiff::CompressorType::kBZ2}, patch_path, &patch_out));
+                       {puffin::CompressorType::kBrotli}, patch_path,
+                       &patch_out));
 
 #if PRINT_SAMPLE
-  PrintArray("kPatchXXXXX", patch_out);
+  PrintArray("kPatchIn", patch);
+  PrintArray("kPatchOut", patch_out);
 #endif
 
   EXPECT_EQ(patch_out, patch);
@@ -166,18 +134,12 @@
                kPatch2To1);
 }
 
-TEST(PatchingTest, Patching1ToEmptyTest) {
-  TestPatching(kDeflatesSample1, {}, kSubblockDeflateExtentsSample1, {},
-               kPatch1ToEmpty);
-}
-
 TEST(PatchingTest, Patching1ToNoDeflateTest) {
   TestPatching(kDeflatesSample1, {11, 22, 33, 44},
                kSubblockDeflateExtentsSample1, {}, kPatch1ToNoDeflate);
 }
 
 // TODO(ahassani): add tests for:
-//   TestPatchingEmptyTo2
 //   TestPatchingNoDeflateTo2
 
 // TODO(ahassani): Change tests data if you decided to compress the header of
diff --git a/third_party/puffin/src/puff_reader.h b/third_party/puffin/src/puff_reader.h
index 40e6bfb..e6f16be 100644
--- a/third_party/puffin/src/puff_reader.h
+++ b/third_party/puffin/src/puff_reader.h
@@ -39,10 +39,7 @@
   //                 be valid during the lifetime of the object.
   // |puff_size| IN  The size of the puffed stream.
   BufferPuffReader(const uint8_t* puff_buf, size_t puff_size)
-      : puff_buf_in_(puff_buf),
-        puff_size_(puff_size),
-        index_(0),
-        state_(State::kReadingBlockMetadata) {}
+      : puff_buf_in_(puff_buf), puff_size_(puff_size) {}
 
   ~BufferPuffReader() override = default;
 
@@ -57,13 +54,13 @@
   size_t puff_size_;
 
   // Index to the offset of the next data in the puff buffer.
-  size_t index_;
+  size_t index_{0};
 
   // State when reading from the puffed buffer.
   enum class State {
     kReadingLenDist = 0,
     kReadingBlockMetadata,
-  } state_;
+  } state_{State::kReadingBlockMetadata};
 
   DISALLOW_COPY_AND_ASSIGN(BufferPuffReader);
 };
diff --git a/third_party/puffin/src/puff_writer.h b/third_party/puffin/src/puff_writer.h
index 8556583..8b7f7bd10 100644
--- a/third_party/puffin/src/puff_writer.h
+++ b/third_party/puffin/src/puff_writer.h
@@ -44,12 +44,7 @@
   //                 be valid during the lifetime of the object.
   // |puff_size| IN  The size of the puffed stream.
   BufferPuffWriter(uint8_t* puff_buf, size_t puff_size)
-      : puff_buf_out_(puff_buf),
-        puff_size_(puff_size),
-        index_(0),
-        len_index_(0),
-        cur_literals_length_(0),
-        state_(State::kWritingNonLiteral) {}
+      : puff_buf_out_(puff_buf), puff_size_(puff_size) {}
 
   ~BufferPuffWriter() override = default;
 
@@ -68,21 +63,21 @@
   size_t puff_size_;
 
   // The offset to the next data in the buffer.
-  size_t index_;
+  size_t index_{0};
 
   // Marks where the length of data should be written after the |index_| has
   // moved forward.
-  size_t len_index_;
+  size_t len_index_{0};
 
   // The number of literals currently been written (or cached).
-  size_t cur_literals_length_;
+  size_t cur_literals_length_{0};
 
   // States when writing into the puffed buffer.
   enum class State {
     kWritingNonLiteral = 0,
     kWritingSmallLiteral,
     kWritingLargeLiteral,
-  } state_;
+  } state_{State::kWritingNonLiteral};
 
   DISALLOW_COPY_AND_ASSIGN(BufferPuffWriter);
 };
diff --git a/third_party/puffin/src/puffdiff.cc b/third_party/puffin/src/puffdiff.cc
index 0f6a57d13..381b26e 100644
--- a/third_party/puffin/src/puffdiff.cc
+++ b/third_party/puffin/src/puffdiff.cc
@@ -4,15 +4,11 @@
 
 #include "puffin/src/include/puffin/puffdiff.h"
 
-#include <endian.h>
 #include <inttypes.h>
-#include <unistd.h>
-
 #include <string>
 #include <vector>
 
-#include "bsdiff/bsdiff.h"
-#include "bsdiff/patch_writer_factory.h"
+#include "base/big_endian.h"
 #include "zucchini/buffer_view.h"
 #include "zucchini/patch_writer.h"
 #include "zucchini/zucchini.h"
@@ -34,7 +30,6 @@
 namespace puffin {
 
 namespace {
-const int kBrotliCompressionQuality = 11;
 
 template <typename T>
 void CopyVectorToRpf(
@@ -86,7 +81,9 @@
   offset += kMagicLength;
 
   // Read header size from big-endian mode.
-  uint32_t be_header_size = htobe32(header_size);
+  uint32_t be_header_size = 0;
+  base::ReadBigEndian(reinterpret_cast<const uint8_t*>(&header_size),
+                      &be_header_size);
   memcpy(patch->data() + offset, &be_header_size, sizeof(be_header_size));
   offset += 4;
 
@@ -108,7 +105,7 @@
               UniqueStreamPtr dst,
               const vector<BitExtent>& src_deflates,
               const vector<BitExtent>& dst_deflates,
-              const vector<bsdiff::CompressorType>& compressors,
+              const vector<puffin::CompressorType>& compressors,
               PatchAlgorithm patchAlgorithm,
               const string& tmp_filepath,
               Buffer* patch) {
@@ -136,29 +133,7 @@
                                             &src_puff_buffer, &src_puffs));
   TEST_AND_RETURN_FALSE(puff_deflate_stream(std::move(dst), dst_deflates,
                                             &dst_puff_buffer, &dst_puffs));
-
-  if (patchAlgorithm == PatchAlgorithm::kBsdiff) {
-    auto bsdiff_patch_writer = bsdiff::CreateBSDF2PatchWriter(
-        tmp_filepath, compressors, kBrotliCompressionQuality);
-
-    TEST_AND_RETURN_FALSE(
-        0 == bsdiff::bsdiff(src_puff_buffer.data(), src_puff_buffer.size(),
-                            dst_puff_buffer.data(), dst_puff_buffer.size(),
-                            bsdiff_patch_writer.get(), nullptr));
-
-    auto bsdiff_patch = FileStream::Open(tmp_filepath, true, false);
-    TEST_AND_RETURN_FALSE(bsdiff_patch);
-    uint64_t patch_size;
-    TEST_AND_RETURN_FALSE(bsdiff_patch->GetSize(&patch_size));
-    Buffer bsdiff_patch_buf(patch_size);
-    TEST_AND_RETURN_FALSE(
-        bsdiff_patch->Read(bsdiff_patch_buf.data(), bsdiff_patch_buf.size()));
-    TEST_AND_RETURN_FALSE(bsdiff_patch->Close());
-
-    TEST_AND_RETURN_FALSE(CreatePatch(
-        bsdiff_patch_buf, src_deflates, dst_deflates, src_puffs, dst_puffs,
-        src_puff_buffer.size(), dst_puff_buffer.size(), patchAlgorithm, patch));
-  } else if (patchAlgorithm == PatchAlgorithm::kZucchini) {
+  if (patchAlgorithm == PatchAlgorithm::kZucchini) {
     zucchini::ConstBufferView src_bytes(src_puff_buffer.data(),
                                         src_puff_buffer.size());
     zucchini::ConstBufferView dst_bytes(dst_puff_buffer.data(),
@@ -194,23 +169,23 @@
               UniqueStreamPtr dst,
               const std::vector<BitExtent>& src_deflates,
               const std::vector<BitExtent>& dst_deflates,
-              const std::vector<bsdiff::CompressorType>& compressors,
+              const std::vector<puffin::CompressorType>& compressors,
               const std::string& tmp_filepath,
               Buffer* patch) {
   return PuffDiff(std::move(src), std::move(dst), src_deflates, dst_deflates,
-                  compressors, PatchAlgorithm::kBsdiff, tmp_filepath, patch);
+                  compressors, PatchAlgorithm::kZucchini, tmp_filepath, patch);
 }
 
 bool PuffDiff(const Buffer& src,
               const Buffer& dst,
               const vector<BitExtent>& src_deflates,
               const vector<BitExtent>& dst_deflates,
-              const vector<bsdiff::CompressorType>& compressors,
+              const vector<puffin::CompressorType>& compressors,
               const string& tmp_filepath,
               Buffer* patch) {
   return PuffDiff(MemoryStream::CreateForRead(src),
                   MemoryStream::CreateForRead(dst), src_deflates, dst_deflates,
-                  compressors, PatchAlgorithm::kBsdiff, tmp_filepath, patch);
+                  compressors, PatchAlgorithm::kZucchini, tmp_filepath, patch);
 }
 
 bool PuffDiff(const Buffer& src,
@@ -219,10 +194,8 @@
               const vector<BitExtent>& dst_deflates,
               const string& tmp_filepath,
               Buffer* patch) {
-  return PuffDiff(
-      src, dst, src_deflates, dst_deflates,
-      {bsdiff::CompressorType::kBZ2, bsdiff::CompressorType::kBrotli},
-      tmp_filepath, patch);
+  return PuffDiff(src, dst, src_deflates, dst_deflates,
+                  {puffin::CompressorType::kBrotli}, tmp_filepath, patch);
 }
 
 }  // namespace puffin
diff --git a/third_party/puffin/src/puffer.cc b/third_party/puffin/src/puffer.cc
index f3a54f8..6da93ac 100644
--- a/third_party/puffin/src/puffer.cc
+++ b/third_party/puffin/src/puffer.cc
@@ -30,7 +30,7 @@
 
 Puffer::Puffer() : Puffer(false) {}
 
-Puffer::~Puffer() {}
+Puffer::~Puffer() = default;
 
 bool Puffer::PuffDeflate(BitReaderInterface* br,
                          PuffWriterInterface* pw,
@@ -149,10 +149,10 @@
       TEST_AND_RETURN_FALSE(br->CacheBits(max_bits));
       auto bits = br->ReadBits(max_bits);
       uint16_t lit_len_alphabet;
-      size_t nbits;
+      size_t dropNbits = 0;
       TEST_AND_RETURN_FALSE(
-          cur_ht->LitLenAlphabet(bits, &lit_len_alphabet, &nbits));
-      br->DropBits(nbits);
+          cur_ht->LitLenAlphabet(bits, &lit_len_alphabet, &dropNbits));
+      br->DropBits(dropNbits);
       if (lit_len_alphabet < 256) {
         pd.type = PuffData::Type::kLiteral;
         pd.byte = lit_len_alphabet;
@@ -193,11 +193,11 @@
                        << " recognize happened. Nothing to worry about."
                        << " See crbug.com/915559";
         }
-        auto bits = br->ReadBits(bits_to_cache);
+        auto read_bits = br->ReadBits(bits_to_cache);
+        size_t nbits = 0;
         uint16_t distance_alphabet;
-        size_t nbits;
         TEST_AND_RETURN_FALSE(
-            cur_ht->DistanceAlphabet(bits, &distance_alphabet, &nbits));
+            cur_ht->DistanceAlphabet(read_bits, &distance_alphabet, &nbits));
         br->DropBits(nbits);
 
         // Reading distance.
diff --git a/third_party/puffin/src/puffin_stream.cc b/third_party/puffin/src/puffin_stream.cc
index 123f862..d5961c9 100644
--- a/third_party/puffin/src/puffin_stream.cc
+++ b/third_party/puffin/src/puffin_stream.cc
@@ -99,15 +99,8 @@
       puff_stream_size_(puff_size),
       deflates_(deflates),
       puffs_(puffs),
-      puff_pos_(0),
-      skip_bytes_(0),
-      deflate_bit_pos_(0),
-      last_byte_(0),
-      extra_byte_(0),
       is_for_puff_(puffer_ ? true : false),
-      closed_(false),
-      max_cache_size_(max_cache_size),
-      cur_cache_size_(0) {
+      max_cache_size_(max_cache_size) {
   // Building upper bounds for faster seek.
   upper_bounds_.reserve(puffs.size());
   for (const auto& puff : puffs) {
@@ -133,7 +126,7 @@
   for (const auto& puff : puffs) {
     max_puff_length = std::max(max_puff_length, puff.length);
   }
-  puff_buffer_.reset(new Buffer(max_puff_length + 1));
+  puff_buffer_ = std::make_shared<Buffer>(max_puff_length + 1);
   if (max_cache_size_ < max_puff_length) {
     max_cache_size_ = 0;  // It means we are not caching puffs.
   }
@@ -142,15 +135,15 @@
   for (const auto& deflate : deflates) {
     max_deflate_length = std::max(max_deflate_length, deflate.length * 8);
   }
-  deflate_buffer_.reset(new Buffer(max_deflate_length + 2));
+  deflate_buffer_ = std::make_unique<Buffer>(max_deflate_length + 2);
 }
 
-bool PuffinStream::GetSize(uint64_t* size) const {
+bool PuffinStream::GetSize(uint64_t* size) {
   *size = puff_stream_size_;
   return true;
 }
 
-bool PuffinStream::GetOffset(uint64_t* offset) const {
+bool PuffinStream::GetOffset(uint64_t* offset) {
   *offset = puff_pos_ + skip_bytes_;
   return true;
 }
@@ -466,7 +459,7 @@
     }
     // If we have not populated the cache yet, create one.
     if (!cache.second) {
-      cache.second.reset(new Buffer(puff_size));
+      cache.second = std::make_shared<Buffer>(puff_size);
     }
     cache.second->resize(puff_size);
 
diff --git a/third_party/puffin/src/puffin_stream.h b/third_party/puffin/src/puffin_stream.h
index 4baf067..f55431b 100644
--- a/third_party/puffin/src/puffin_stream.h
+++ b/third_party/puffin/src/puffin_stream.h
@@ -63,10 +63,10 @@
                                        const std::vector<BitExtent>& deflates,
                                        const std::vector<ByteExtent>& puffs);
 
-  bool GetSize(uint64_t* size) const override;
+  bool GetSize(uint64_t* size) override;
 
   // Returns the current offset in the imaginary puff stream.
-  bool GetOffset(uint64_t* offset) const override;
+  bool GetOffset(uint64_t* offset) override;
 
   // Sets the current offset in the imaginary puff stream.
   bool Seek(uint64_t offset) override;
@@ -126,30 +126,30 @@
 
   // The current offset in the imaginary puff stream is |puff_pos_| +
   // |skip_bytes_|
-  uint64_t puff_pos_;
-  uint64_t skip_bytes_;
+  uint64_t puff_pos_{0};
+  uint64_t skip_bytes_{0};
 
   // The current bit offset in |stream_|.
-  uint64_t deflate_bit_pos_;
+  uint64_t deflate_bit_pos_{0};
 
   // This value caches the first or last byte of a deflate stream. This is
   // needed when two deflate stream end on the same byte (with greater than zero
   // bit offset difference) or a deflate starts from middle of the byte. We need
   // to cache the value in here before we have the rest of the puff buffer to
   // make the deflate.
-  uint8_t last_byte_;
+  uint8_t last_byte_{0};
 
   // We have to figure out if we need to cache an extra puff byte for the last
   // byte of the deflate. This is only needed if the last bit of the current
   // deflate is not in the same byte as the first bit of the next deflate. The
   // value is either 0 or 1. If 1.
-  size_t extra_byte_;
+  size_t extra_byte_{0};
 
   // True if the stream is only for puffing. False if for huffing.
   bool is_for_puff_;
 
   // True if the |Close()| is called.
-  bool closed_;
+  bool closed_{false};
 
   std::unique_ptr<Buffer> deflate_buffer_;
   std::shared_ptr<Buffer> puff_buffer_;
@@ -160,7 +160,7 @@
   // this class.
   size_t max_cache_size_;
   // The current amount of memory (in bytes) used for caching puff buffers.
-  uint64_t cur_cache_size_;
+  uint64_t cur_cache_size_{0};
 
   DISALLOW_COPY_AND_ASSIGN(PuffinStream);
 };
diff --git a/third_party/puffin/src/puffpatch.cc b/third_party/puffin/src/puffpatch.cc
index d023a20a..ea3ae72d 100644
--- a/third_party/puffin/src/puffpatch.cc
+++ b/third_party/puffin/src/puffpatch.cc
@@ -4,16 +4,13 @@
 
 #include "puffin/src/include/puffin/puffpatch.h"
 
-#include <endian.h>
 #include <inttypes.h>
-#include <unistd.h>
 
 #include <algorithm>
 #include <string>
 #include <vector>
 
-#include "bsdiff/bspatch.h"
-#include "bsdiff/file_interface.h"
+#include "base/big_endian.h"
 #include "zucchini/patch_reader.h"
 #include "zucchini/zucchini.h"
 
@@ -49,53 +46,6 @@
   }
 }
 
-class BsdiffStream : public bsdiff::FileInterface {
- public:
-  ~BsdiffStream() override = default;
-
-  static unique_ptr<bsdiff::FileInterface> Create(UniqueStreamPtr stream) {
-    TEST_AND_RETURN_VALUE(stream, nullptr);
-    return unique_ptr<bsdiff::FileInterface>(
-        new BsdiffStream(std::move(stream)));
-  }
-
-  bool Read(void* buf, size_t count, size_t* bytes_read) override {
-    *bytes_read = 0;
-    if (stream_->Read(buf, count)) {
-      *bytes_read = count;
-      return true;
-    }
-    return false;
-  }
-
-  bool Write(const void* buf, size_t count, size_t* bytes_written) override {
-    *bytes_written = 0;
-    if (stream_->Write(buf, count)) {
-      *bytes_written = count;
-      return true;
-    }
-    return false;
-  }
-
-  bool Seek(off_t pos) override { return stream_->Seek(pos); }
-
-  bool Close() override { return stream_->Close(); }
-
-  bool GetSize(uint64_t* size) override {
-    uint64_t my_size;
-    TEST_AND_RETURN_FALSE(stream_->GetSize(&my_size));
-    *size = my_size;
-    return true;
-  }
-
- private:
-  explicit BsdiffStream(UniqueStreamPtr stream) : stream_(std::move(stream)) {}
-
-  UniqueStreamPtr stream_;
-
-  DISALLOW_COPY_AND_ASSIGN(BsdiffStream);
-};
-
 bool DecodePatch(const uint8_t* patch,
                  size_t patch_length,
                  size_t* bsdiff_patch_offset,
@@ -108,7 +58,7 @@
                  uint64_t* dst_puff_size,
                  metadata::PatchHeader_PatchType* patch_type) {
   size_t offset = 0;
-  uint32_t header_size;
+  uint32_t header_size = 0;
   TEST_AND_RETURN_FALSE(patch_length >= (kMagicLength + sizeof(header_size)));
 
   string patch_magic(reinterpret_cast<const char*>(patch), kMagicLength);
@@ -120,7 +70,7 @@
 
   // Read the header size from big-endian mode.
   memcpy(&header_size, patch + offset, sizeof(header_size));
-  header_size = be32toh(header_size);
+  base::WriteBigEndian(reinterpret_cast<char*>(&header_size), header_size);
   offset += sizeof(header_size);
   TEST_AND_RETURN_FALSE(header_size <= (patch_length - offset));
 
@@ -216,19 +166,7 @@
   auto dst_stream = PuffinStream::CreateForHuff(
       std::move(dst), huffer, dst_puff_size, dst_deflates, dst_puffs);
   TEST_AND_RETURN_FALSE(dst_stream);
-
-  if (patch_type == metadata::PatchHeader_PatchType_BSDIFF) {
-    // For reading from source.
-    auto reader = BsdiffStream::Create(std::move(src_stream));
-    TEST_AND_RETURN_FALSE(reader);
-    // For writing into destination.
-    auto writer = BsdiffStream::Create(std::move(dst_stream));
-    TEST_AND_RETURN_FALSE(writer);
-
-    // Running bspatch itself.
-    TEST_AND_RETURN_FALSE(
-        0 == bspatch(reader, writer, &patch[patch_offset], raw_patch_size));
-  } else if (patch_type == metadata::PatchHeader_PatchType_ZUCCHINI) {
+  if (patch_type == metadata::PatchHeader_PatchType_ZUCCHINI) {
     TEST_AND_RETURN_FALSE(ApplyZucchiniPatch(
         std::move(src_stream), src_puff_size, patch + patch_offset,
         raw_patch_size, std::move(dst_stream)));
diff --git a/third_party/puffin/src/stream_unittest.cc b/third_party/puffin/src/stream_unittest.cc
index 9f609d1..1e6c1ea 100644
--- a/third_party/puffin/src/stream_unittest.cc
+++ b/third_party/puffin/src/stream_unittest.cc
@@ -4,11 +4,11 @@
 
 #include <numeric>
 
+#include "base/rand_util.h"
 #include "gtest/gtest.h"
 
 #include "puffin/file_stream.h"
 #include "puffin/memory_stream.h"
-#include "puffin/src/extent_stream.h"
 #include "puffin/src/include/puffin/huffer.h"
 #include "puffin/src/include/puffin/puffer.h"
 #include "puffin/src/puffin_stream.h"
@@ -42,6 +42,8 @@
     ASSERT_FALSE(stream->Read(tmp.data(), 2));
     ASSERT_FALSE(stream->Read(tmp.data(), 3));
     ASSERT_FALSE(stream->Read(tmp.data(), 100));
+    ASSERT_FALSE(stream->Read(tmp.data(), -1));
+    ASSERT_FALSE(stream->Read(tmp.data(), -10));
 
     ASSERT_TRUE(stream->Seek(size - 1));
     ASSERT_TRUE(stream->Read(tmp.data(), 0));
@@ -71,16 +73,15 @@
     // Read random lengths from random offsets.
     tmp.resize(buf.size());
     srand(time(nullptr));
-    uint32_t rand_seed;
     for (size_t idx = 0; idx < 10000; idx++) {
       // zero to full size available.
-      size_t size = rand_r(&rand_seed) % (buf.size() + 1);
-      uint64_t max_start = buf.size() - size;
-      uint64_t start = rand_r(&rand_seed) % (max_start + 1);
+      uint64_t rand_size = base::RandGenerator(buf.size() + 1);
+      uint64_t max_start = buf.size() - rand_size;
+      uint64_t start = base::RandGenerator(max_start + 1);
       ASSERT_TRUE(stream->Seek(start));
-      ASSERT_TRUE(stream->Read(tmp.data(), size));
-      for (size_t idx = 0; idx < size; idx++) {
-        ASSERT_EQ(tmp[idx], buf[start + idx]);
+      ASSERT_TRUE(stream->Read(tmp.data(), rand_size));
+      for (size_t idy = 0; idy < rand_size; idy++) {
+        ASSERT_EQ(tmp[idy], buf[start + idy]);
       }
     }
   }
@@ -96,17 +97,23 @@
     ASSERT_TRUE(stream->Write(buf.data(), 2));
     ASSERT_TRUE(stream->Write(buf.data(), 3));
     ASSERT_TRUE(stream->Write(buf.data(), 10));
+    ASSERT_FALSE(stream->Write(buf.data(), -1));
+    ASSERT_FALSE(stream->Write(buf.data(), -10));
 
     ASSERT_TRUE(stream->GetSize(&size));
     ASSERT_TRUE(stream->Seek(size - 1));
     ASSERT_TRUE(stream->Write(buf.data(), 0));
     ASSERT_TRUE(stream->Write(buf.data(), 1));
+    ASSERT_FALSE(stream->Write(buf.data(), -1));
+    ASSERT_FALSE(stream->Write(buf.data(), -10));
 
     ASSERT_TRUE(stream->GetSize(&size));
     ASSERT_TRUE(stream->Seek(size - 1));
     ASSERT_TRUE(stream->Write(buf.data(), 2));
     ASSERT_TRUE(stream->Write(buf.data(), 3));
     ASSERT_TRUE(stream->Write(buf.data(), 10));
+    ASSERT_FALSE(stream->Write(buf.data(), -1));
+    ASSERT_FALSE(stream->Write(buf.data(), -10));
   }
 
   void TestWrite(StreamInterface* write_stream, StreamInterface* read_stream) {
@@ -123,12 +130,16 @@
     ASSERT_TRUE(read_stream->Read(buf2.data(), buf2.size()));
     ASSERT_EQ(buf1, buf2);
 
+    // Make sure the write fails when expected.
+    ASSERT_FALSE(write_stream->Write(buf1.data(), -1));
+    ASSERT_FALSE(write_stream->Write(buf1.data(), -10));
+
     std::fill(buf2.begin(), buf2.end(), 0);
 
     // Write entire buffer one byte at a time. (all zeros).
     ASSERT_TRUE(write_stream->Seek(0));
-    for (size_t idx = 0; idx < buf2.size(); idx++) {
-      ASSERT_TRUE(write_stream->Write(&buf2[idx], 1));
+    for (const auto& byte : buf2) {
+      ASSERT_TRUE(write_stream->Write(&byte, 1));
     }
 
     ASSERT_TRUE(read_stream->Seek(0));
@@ -151,6 +162,9 @@
     ASSERT_EQ(offset, 0);
     // Test end of stream offset.
     ASSERT_EQ(stream->Seek(size + 1), seek_end_is_fine);
+    // Test invalid negative seek offsets.
+    ASSERT_FALSE(stream->Seek(-1));
+    ASSERT_FALSE(stream->Seek(-10));
   }
 
   void TestClose(StreamInterface* stream) { ASSERT_TRUE(stream->Close()); }
@@ -175,10 +189,10 @@
 
 TEST_F(StreamTest, FileStreamTest) {
   string filepath;
-  ASSERT_TRUE(MakeTempFile(&filepath, nullptr));
+  ASSERT_TRUE(MakeTempFile(&filepath));
+
   ScopedPathUnlinker scoped_unlinker(filepath);
   ASSERT_FALSE(FileStream::Open(filepath, false, false));
-
   auto stream = FileStream::Open(filepath, true, true);
   ASSERT_TRUE(stream.get() != nullptr);
   // Doesn't matter if it is not initialized. I will be overridden.
@@ -186,12 +200,21 @@
   std::iota(buf.begin(), buf.end(), 0);
 
   ASSERT_TRUE(stream->Write(buf.data(), buf.size()));
-
   TestRead(stream.get(), buf);
   TestWrite(stream.get(), stream.get());
   TestWriteBoundary(stream.get());
   TestSeek(stream.get(), true);
   TestClose(stream.get());
+
+  // Make sure you can open and close a read only stream.
+  auto read_only_stream = FileStream::Open(filepath, true, false);
+  ASSERT_TRUE(read_only_stream != nullptr);
+  ASSERT_TRUE(read_only_stream->Close());
+
+  // Make sure you can open and close write only stream.
+  auto write_only_stream = FileStream::Open(filepath, false, true);
+  ASSERT_TRUE(write_only_stream != nullptr);
+  ASSERT_TRUE(write_only_stream->Close());
 }
 
 TEST_F(StreamTest, PuffinStreamTest) {
@@ -220,8 +243,8 @@
       kSubblockDeflateExtentsSample1, kPuffExtentsSample1);
 
   ASSERT_TRUE(write_stream->Seek(0));
-  for (size_t idx = 0; idx < kPuffsSample1.size(); idx++) {
-    ASSERT_TRUE(write_stream->Write(&kPuffsSample1[idx], 1));
+  for (const auto& byte : kPuffsSample1) {
+    ASSERT_TRUE(write_stream->Write(&byte, 1));
   }
   // Make sure the write works
   ASSERT_EQ(buf, kDeflatesSample1);
@@ -246,34 +269,4 @@
   TestClose(write_stream.get());
 }
 
-TEST_F(StreamTest, ExtentStreamTest) {
-  Buffer buf(100);
-  std::iota(buf.begin(), buf.end(), 0);
-
-  vector<ByteExtent> extents = {{10, 10}, {25, 0}, {30, 10}};
-  Buffer data = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
-                 30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
-
-  auto read_stream =
-      ExtentStream::CreateForRead(MemoryStream::CreateForRead(buf), extents);
-  TestSeek(read_stream.get(), false);
-  TestRead(read_stream.get(), data);
-  TestClose(read_stream.get());
-
-  auto buf2 = buf;
-  std::fill(data.begin(), data.end(), 3);
-  for (const auto& extent : extents) {
-    std::fill(buf.begin() + extent.offset,
-              buf.begin() + (extent.offset + extent.length), 3);
-  }
-  auto write_stream = ExtentStream::CreateForWrite(
-      MemoryStream::CreateForWrite(&buf2), extents);
-  ASSERT_TRUE(write_stream->Seek(0));
-  ASSERT_TRUE(write_stream->Write(data.data(), data.size()));
-  EXPECT_EQ(buf2, buf);
-
-  TestSeek(write_stream.get(), false);
-  TestClose(write_stream.get());
-}
-
 }  // namespace puffin
diff --git a/third_party/puffin/src/testrunner.cc b/third_party/puffin/src/testrunner.cc
index 1fba7439..e89b70b 100644
--- a/third_party/puffin/src/testrunner.cc
+++ b/third_party/puffin/src/testrunner.cc
@@ -2,19 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if USE_BRILLO
-#include "brillo/test_helpers.h"
-#else
 #include "gtest/gtest.h"
-#endif  // USE_BRILLO
 
 // The entry point of the unit tests.
 int main(int argc, char** argv) {
-#if USE_BRILLO
-  base::CommandLine::Init(argc, argv);
-  SetUpTests(&argc, argv, true);
-#else
   testing::InitGoogleTest(&argc, argv);
-#endif
   return RUN_ALL_TESTS();
 }
diff --git a/third_party/puffin/src/unittest_common.cc b/third_party/puffin/src/unittest_common.cc
index ad3a85f4..c0f35e20 100644
--- a/third_party/puffin/src/unittest_common.cc
+++ b/third_party/puffin/src/unittest_common.cc
@@ -4,27 +4,18 @@
 
 #include "puffin/src/unittest_common.h"
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+
 using std::string;
 using std::vector;
 
 namespace puffin {
 
-bool MakeTempFile(string* filename, int* fd) {
-#ifdef __ANDROID__
-  char tmp_template[] = "/data/local/tmp/puffin-XXXXXX";
-#else
-  char tmp_template[] = "/tmp/puffin-XXXXXX";
-#endif  // __ANDROID__
-  int mkstemp_fd = mkstemp(tmp_template);
-  TEST_AND_RETURN_FALSE(mkstemp_fd >= 0);
-  if (filename) {
-    *filename = tmp_template;
-  }
-  if (fd) {
-    *fd = mkstemp_fd;
-  } else {
-    close(mkstemp_fd);
-  }
+bool MakeTempFile(string* filename) {
+  base::FilePath tmp_file_path;
+  TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&tmp_file_path));
+  *filename = tmp_file_path.AsUTF8Unsafe();
   return true;
 }
 
diff --git a/third_party/puffin/src/unittest_common.h b/third_party/puffin/src/unittest_common.h
index eac61e6..3b49250c 100644
--- a/third_party/puffin/src/unittest_common.h
+++ b/third_party/puffin/src/unittest_common.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "puffin/src/include/puffin/common.h"
 #include "puffin/src/logging.h"
 
@@ -18,8 +20,9 @@
  public:
   explicit ScopedPathUnlinker(const std::string& path) : path_(path) {}
   ~ScopedPathUnlinker() {
-    if (unlink(path_.c_str()) < 0) {
-      LOG(ERROR) << "Failed to unlink: " << path_;
+    base::FilePath path = base::FilePath::FromUTF8Unsafe(path_);
+    if (!base::DeleteFile(path)) {
+      LOG(ERROR) << "Failed to delete: " << path_;
     }
   }
 
@@ -32,7 +35,7 @@
 // Makes a temporary file as /tmp/puffin-XXXXXX. Both |filename| and |fd| are
 // optional, but if given, they will be populated with the new temporary file's
 // values.
-bool MakeTempFile(std::string* filename, int* fd);
+bool MakeTempFile(std::string* filename);
 
 extern const Buffer kDeflatesSample1;
 extern const Buffer kPuffsSample1;
diff --git a/third_party/puffin/src/utils_unittest.cc b/third_party/puffin/src/utils_unittest.cc
index 9deb765..ca631f8 100644
--- a/third_party/puffin/src/utils_unittest.cc
+++ b/third_party/puffin/src/utils_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <unistd.h>
-
 #include <vector>
 
 #include "gtest/gtest.h"
@@ -51,54 +49,6 @@
     0x2e, 0x00, 0xb4, 0xa0, 0xf2, 0x36, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00,
     0x00, 0x00};
 
-// echo "0123456789" > test1.txt && echo "9876543210" > test2.txt &&
-// gzip -kf test1.txt test2.txt && cat test1.txt.gz test2.txt.gz |
-// hexdump -v -e '12/1 "0x%02x, " "\n"'
-const uint8_t kGzipEntryWithMultipleMembers[] = {
-    0x1f, 0x8b, 0x08, 0x08, 0x77, 0xd5, 0x84, 0x5a, 0x00, 0x03, 0x74, 0x65,
-    0x73, 0x74, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x33, 0x30, 0x34, 0x32,
-    0x36, 0x31, 0x35, 0x33, 0xb7, 0xb0, 0xe4, 0x02, 0x00, 0xd1, 0xe5, 0x76,
-    0x40, 0x0b, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08, 0x08, 0x77, 0xd5, 0x84,
-    0x5a, 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x32, 0x2e, 0x74, 0x78, 0x74,
-    0x00, 0xb3, 0xb4, 0x30, 0x37, 0x33, 0x35, 0x31, 0x36, 0x32, 0x34, 0xe0,
-    0x02, 0x00, 0x20, 0x9c, 0x5f, 0x89, 0x0b, 0x00, 0x00, 0x00};
-
-// echo "0123456789" > test1.txt && gzip -kf test1.txt && cat test1.txt.gz |
-// hexdump -v -e '12/1 "0x%02x, " "\n"'
-// And manually insert extra field with two byte length (10) followed by:
-// echo "extrafield" | hexdump -v -e '12/1 "0x%02x, " "\n"'
-// Then change the forth byte of array to -x0c to enable the extra field.
-const uint8_t kGzipEntryWithExtraField[] = {
-    0x1f, 0x8b, 0x08, 0x0c, 0xcf, 0x0e, 0x86, 0x5a, 0x00, 0x03,
-    // Extra field begin
-    0x0A, 0x00, 0x65, 0x78, 0x74, 0x72, 0x61, 0x66, 0x69, 0x65, 0x6c, 0x64,
-    // Extra field end
-    0x74, 0x65, 0x73, 0x74, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x33, 0x30,
-    0x34, 0x32, 0x36, 0x31, 0x35, 0x33, 0xb7, 0xb0, 0xe4, 0x02, 0x00, 0xd1,
-    0xe5, 0x76, 0x40, 0x0b, 0x00, 0x00, 0x00};
-
-// echo "0123456789" | zlib-flate -compress |
-// hexdump -v -e '12/1 "0x%02x, " "\n"'
-const uint8_t kZlibEntry[] = {0x78, 0x9c, 0x33, 0x30, 0x34, 0x32, 0x36,
-                              0x31, 0x35, 0x33, 0xb7, 0xb0, 0xe4, 0x02,
-                              0x00, 0x0d, 0x17, 0x02, 0x18};
-
-void FindDeflatesInZlibBlocks(const Buffer& src,
-                              const vector<ByteExtent>& zlibs,
-                              const vector<BitExtent>& deflates) {
-  string tmp_file;
-  ASSERT_TRUE(MakeTempFile(&tmp_file, nullptr));
-  ScopedPathUnlinker unlinker(tmp_file);
-  auto src_stream = FileStream::Open(tmp_file, false, true);
-  ASSERT_TRUE(src_stream);
-  ASSERT_TRUE(src_stream->Write(src.data(), src.size()));
-  ASSERT_TRUE(src_stream->Close());
-
-  vector<BitExtent> deflates_out;
-  ASSERT_TRUE(LocateDeflatesInZlibBlocks(tmp_file, zlibs, &deflates_out));
-  ASSERT_EQ(deflates, deflates_out);
-}
-
 void CheckFindPuffLocation(const Buffer& compressed,
                            const vector<BitExtent>& deflates,
                            const vector<ByteExtent>& expected_puffs,
@@ -123,37 +73,6 @@
                         kPuffExtentsSample2, kPuffsSample2.size());
 }
 
-TEST(UtilsTest, LocateDeflatesInZlib) {
-  Buffer zlib_data(kZlibEntry, std::end(kZlibEntry));
-  vector<BitExtent> deflates;
-  vector<BitExtent> expected_deflates = {{16, 98}};
-  EXPECT_TRUE(LocateDeflatesInZlib(zlib_data, &deflates));
-  EXPECT_EQ(deflates, expected_deflates);
-}
-
-TEST(UtilsTest, LocateDeflatesInEmptyZlib) {
-  Buffer empty;
-  vector<ByteExtent> empty_zlibs;
-  vector<BitExtent> empty_deflates;
-  FindDeflatesInZlibBlocks(empty, empty_zlibs, empty_deflates);
-}
-
-TEST(UtilsTest, LocateDeflatesInZlibWithInvalidFields) {
-  Buffer zlib_data(kZlibEntry, std::end(kZlibEntry));
-  auto cmf = zlib_data[0];
-  auto flag = zlib_data[1];
-
-  vector<BitExtent> deflates;
-  zlib_data[0] = cmf & 0xF0;
-  EXPECT_FALSE(LocateDeflatesInZlib(zlib_data, &deflates));
-  zlib_data[0] = cmf | (8 << 4);
-  EXPECT_FALSE(LocateDeflatesInZlib(zlib_data, &deflates));
-  zlib_data[0] = cmf;  // Correct it.
-
-  zlib_data[1] = flag & 0xF0;
-  EXPECT_FALSE(LocateDeflatesInZlib(zlib_data, &deflates));
-}
-
 TEST(UtilsTest, LocateDeflatesInZipArchiveSmoke) {
   Buffer zip_entries(kZipEntries, std::end(kZipEntries));
   vector<BitExtent> deflates;
@@ -186,42 +105,6 @@
   EXPECT_TRUE(deflates_incomplete.empty());
 }
 
-TEST(UtilsTest, LocateDeflatesInGzip) {
-  Buffer gzip_data(kGzipEntryWithMultipleMembers,
-                   std::end(kGzipEntryWithMultipleMembers));
-  vector<BitExtent> deflates;
-  vector<BitExtent> expected_deflates = {{160, 98}, {488, 98}};
-  EXPECT_TRUE(LocateDeflatesInGzip(gzip_data, &deflates));
-  EXPECT_EQ(deflates, expected_deflates);
-}
-
-TEST(UtilsTest, LocateDeflatesInGzipFail) {
-  Buffer gzip_data(kGzipEntryWithMultipleMembers,
-                   std::end(kGzipEntryWithMultipleMembers));
-  gzip_data[0] ^= 1;
-  vector<BitExtent> deflates;
-  EXPECT_FALSE(LocateDeflatesInGzip(gzip_data, &deflates));
-}
-
-TEST(UtilsTest, LocateDeflatesInGzipWithPadding) {
-  Buffer gzip_data(kGzipEntryWithMultipleMembers,
-                   std::end(kGzipEntryWithMultipleMembers));
-  gzip_data.resize(gzip_data.size() + 100);
-  vector<BitExtent> deflates;
-  vector<BitExtent> expected_deflates = {{160, 98}, {488, 98}};
-  EXPECT_TRUE(LocateDeflatesInGzip(gzip_data, &deflates));
-  EXPECT_EQ(deflates, expected_deflates);
-}
-
-TEST(UtilsTest, LocateDeflatesInGzipWithExtraField) {
-  Buffer gzip_data(kGzipEntryWithExtraField,
-                   std::end(kGzipEntryWithExtraField));
-  vector<BitExtent> deflates;
-  vector<BitExtent> expected_deflates = {{256, 98}};
-  EXPECT_TRUE(LocateDeflatesInGzip(gzip_data, &deflates));
-  EXPECT_EQ(deflates, expected_deflates);
-}
-
 TEST(UtilsTest, RemoveEqualBitExtents) {
   Buffer data1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   Buffer data2 = {1, 2, 3, 4, 5, 5, 6, 7, 8, 9};
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0c61ad9f..86dbfe2 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -54685,6 +54685,7 @@
   <int value="-2073402331"
       label="BrokerFileOperationsOnDiskCacheInNetworkService:disabled"/>
   <int value="-2072471036" label="OobeHidDetectionRevamp:disabled"/>
+  <int value="-2072181147" label="WebContentsCaptureHiDPI:enabled"/>
   <int value="-2071515296" label="allow-sync-xhr-in-page-dismissal"/>
   <int value="-2071202821" label="CopyLinkToText:enabled"/>
   <int value="-2068490665" label="PasswordChange:enabled"/>
@@ -59356,6 +59357,7 @@
   <int value="981818901" label="AppBanners:enabled"/>
   <int value="982032277" label="NTPOfflineBadge:disabled"/>
   <int value="982511393" label="NTPArticleSuggestions:disabled"/>
+  <int value="982932009" label="WebContentsCaptureHiDPI:disabled"/>
   <int value="983084316" label="SyncUSSNigori:disabled"/>
   <int value="983311394" label="tab-management-experiment-type"/>
   <int value="985127848"
@@ -63428,6 +63430,11 @@
   <int value="6" label="H264_hw"/>
 </enum>
 
+<enum name="MediaRecorderVEAUsed">
+  <int value="0" label="Not used"/>
+  <int value="1" label="Used"/>
+</enum>
+
 <enum name="MediaRendererType">
   <int value="0" label="kDefault"/>
   <int value="1" label="kMojo"/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 838c9d5..e8fd5027 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3188,6 +3188,13 @@
   <summary>The errors HW video encode encounters in MediaRecorder.</summary>
 </histogram>
 
+<histogram name="Media.MediaRecorder.VEAUsed" enum="MediaRecorderVEAUsed"
+    expires_after="M95">
+  <owner>mcasas@chromium.org</owner>
+  <owner>wtlee@chromium.org</owner>
+  <summary>Whether HW video encode is used in MediaRecorder.</summary>
+</histogram>
+
 <histogram name="Media.MediaStreamManager.DesktopVideoDeviceUpdate"
     enum="MediaStreamRequestResult2" expires_after="2022-12-01">
   <owner>eladalon@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index ed0e3c7..f004e2f 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -105,7 +105,7 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="PageLoad.Bytes" units="units"
+<histogram base="true" name="PageLoad.Bytes" units="KB"
     expires_after="2023-01-05">
   <owner>jkarlin@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 1dbcef3..3f4cfce 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "5d2e302a0724081bd9acfe06d4256776d5a659b4",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/d55a1685ae00d37b13590430d7d916dc291da2cc/trace_processor_shell.exe"
+            "hash": "5917c2f13de8a1616fce4f6641e653825fa95852",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/d836f02e9ab596cc817bff3efcae6287f9ee0403/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "ea611c8243ca07c3a54d7ba1b0371ac7957e6533",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d55a1685ae00d37b13590430d7d916dc291da2cc/trace_processor_shell"
+            "hash": "f8def2233b28bf40d61363174b172594e2dd375e",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d836f02e9ab596cc817bff3efcae6287f9ee0403/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "42ca3c37a2dfdb2c1ce5790a590b88ad7692ff0c",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d5024aeb5e2193961a66949b94c466784d6126b8/trace_processor_shell"
+            "hash": "7eb4e73a87f9132b1cabb5601579867f4d72bb41",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d836f02e9ab596cc817bff3efcae6287f9ee0403/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
index 93d6a10..bd5ab6d6 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/ModalDialogManager.java
@@ -372,8 +372,8 @@
         if (mDismissingCurrentDialog) return;
         mDismissingCurrentDialog = true;
         model.get(ModalDialogProperties.CONTROLLER).onDismiss(model, dismissalCause);
-        for (ModalDialogManagerObserver o : mObserverList) o.onDialogDismissed(model);
         mCurrentPresenter.setDialogModel(null, null);
+        for (ModalDialogManagerObserver o : mObserverList) o.onDialogDismissed(model);
         mCurrentPresenter = null;
         mDismissingCurrentDialog = false;
         dispatchOnLastDialogDismissedIfEmpty();
diff --git a/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java b/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
index dcc5e54..a141494f 100644
--- a/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
+++ b/ui/android/junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java
@@ -19,9 +19,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -41,7 +43,7 @@
 public class ModalDialogManagerTest {
     private static final int MAX_DIALOGS = 4;
 
-    @Mock
+    @Spy
     private ModalDialogManager.Presenter mAppModalPresenter;
     @Mock
     private ModalDialogManager.Presenter mTabModalPresenter;
@@ -91,6 +93,12 @@
         verify(mObserver, times(1)).onDialogAdded(mDialogModels.get(1));
 
         mModalDialogManager.dismissDialog(mDialogModels.get(1), DialogDismissalCause.UNKNOWN);
+
+        // Dialog view should be removed first before #onDialogDismissed; otherwise,
+        // Presenter#getCurrentModel inside #onDialogDismissed will not return null.
+        InOrder inOrder = Mockito.inOrder(mAppModalPresenter, mObserver);
+        inOrder.verify(mAppModalPresenter).removeDialogView(mDialogModels.get(1));
+        inOrder.verify(mObserver, times(1)).onDialogDismissed(mDialogModels.get(1));
         // Calling the same function again, as well as dismissDialogsOfType() should not trigger
         // notifying of empty (because onLastDialogDismissed() was already called once, and a new
         // dialog wasn't added).
diff --git a/ui/aura/screen_ozone.cc b/ui/aura/screen_ozone.cc
index d133110..a78a6a4 100644
--- a/ui/aura/screen_ozone.cc
+++ b/ui/aura/screen_ozone.cc
@@ -13,10 +13,13 @@
 
 namespace aura {
 
-ScreenOzone::ScreenOzone() = default;
+ScreenOzone::ScreenOzone() {
+  DCHECK(!display::Screen::HasScreen());
+  display::Screen::SetScreenInstance(this);
+}
 
 ScreenOzone::~ScreenOzone() {
-  display::Screen::SetScreenInstance(old_screen_);
+  display::Screen::SetScreenInstance(nullptr);
 }
 
 void ScreenOzone::Initialize() {
@@ -34,6 +37,11 @@
   }
 }
 
+// static
+bool ScreenOzone::IsOzoneInitialized() {
+  return ui::OzonePlatform::IsInitialized();
+}
+
 gfx::Point ScreenOzone::GetCursorScreenPoint() {
   return platform_screen_->GetCursorScreenPoint();
 }
@@ -149,4 +157,17 @@
 
 void ScreenOzone::OnBeforePlatformScreenInit() {}
 
+ScopedScreenOzone::ScopedScreenOzone(const base::Location& location)
+    : ScopedNativeScreen(/*call_maybe_init=*/false, location) {
+  MaybeInit();
+}
+
+ScopedScreenOzone::~ScopedScreenOzone() = default;
+
+display::Screen* ScopedScreenOzone::CreateScreen() {
+  auto* screen = new ScreenOzone();
+  screen->Initialize();
+  return screen;
+}
+
 }  // namespace aura
diff --git a/ui/aura/screen_ozone.h b/ui/aura/screen_ozone.h
index 980c083b..2970a0e 100644
--- a/ui/aura/screen_ozone.h
+++ b/ui/aura/screen_ozone.h
@@ -60,6 +60,8 @@
   virtual gfx::NativeWindow GetNativeWindowFromAcceleratedWidget(
       gfx::AcceleratedWidget widget) const;
 
+  static bool IsOzoneInitialized();
+
  protected:
   ui::PlatformScreen* platform_screen() { return platform_screen_.get(); }
 
@@ -73,10 +75,22 @@
 
   virtual void OnBeforePlatformScreenInit();
 
-  display::Screen* const old_screen_ = display::Screen::SetScreenInstance(this);
   std::unique_ptr<ui::PlatformScreen> platform_screen_;
 };
 
+// ScopedScreenOzone creates a ScreenOzone instead of NativeScreen
+// (created by `CreateNativeScreen()`) if the screen hasn't been set.
+class AURA_EXPORT ScopedScreenOzone : public display::ScopedNativeScreen {
+ public:
+  explicit ScopedScreenOzone(const base::Location& location = FROM_HERE);
+  ScopedScreenOzone(const ScopedScreenOzone&) = delete;
+  ScopedScreenOzone operator=(const ScopedScreenOzone&) = delete;
+  ~ScopedScreenOzone() override;
+
+ private:
+  display::Screen* CreateScreen() override;
+};
+
 }  // namespace aura
 
 #endif  // UI_AURA_SCREEN_OZONE_H_
diff --git a/ui/base/ime/linux/input_method_auralinux.cc b/ui/base/ime/linux/input_method_auralinux.cc
index 406096c8..dc624ee 100644
--- a/ui/base/ime/linux/input_method_auralinux.cc
+++ b/ui/base/ime/linux/input_method_auralinux.cc
@@ -348,11 +348,10 @@
   text_input_type_ = GetTextInputType();
 
   // We only focus in |context_| when the focus is in a textfield.
-  if (old_text_input_type != TEXT_INPUT_TYPE_NONE &&
-      text_input_type_ == TEXT_INPUT_TYPE_NONE) {
+  if (old_text_input_type != TEXT_INPUT_TYPE_NONE) {
     context_->Blur();
-  } else if (old_text_input_type == TEXT_INPUT_TYPE_NONE &&
-             text_input_type_ != TEXT_INPUT_TYPE_NONE) {
+  }
+  if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
     context_->Focus();
   }
 
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 9d77c8c..dc1d296bd 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -355,9 +355,9 @@
       std::replace(locale_name.begin(), locale_name.end(), '_', '-');
 
       // Map the Chinese locale names over to zh-CN and zh-TW.
-      if (base::LowerCaseEqualsASCII(locale_name, "zh-hans")) {
+      if (base::EqualsCaseInsensitiveASCII(locale_name, "zh-hans")) {
         locale_name = "zh-CN";
-      } else if (base::LowerCaseEqualsASCII(locale_name, "zh-hant")) {
+      } else if (base::EqualsCaseInsensitiveASCII(locale_name, "zh-hant")) {
         locale_name = "zh-TW";
       }
       locales->push_back(locale_name);
@@ -415,35 +415,35 @@
     std::string tmp_locale(lang);
     // Map es-RR other than es-ES to es-419 (Chrome's Latin American
     // Spanish locale).
-    if (base::LowerCaseEqualsASCII(lang, "es") &&
-        !base::LowerCaseEqualsASCII(region, "es")) {
+    if (base::EqualsCaseInsensitiveASCII(lang, "es") &&
+        !base::EqualsCaseInsensitiveASCII(region, "es")) {
 #if BUILDFLAG(IS_IOS)
       // iOS uses a different name for es-419 (es-MX).
       tmp_locale.append("-MX");
 #else
       tmp_locale.append("-419");
 #endif
-    } else if (base::LowerCaseEqualsASCII(lang, "pt") &&
-               !base::LowerCaseEqualsASCII(region, "br")) {
+    } else if (base::EqualsCaseInsensitiveASCII(lang, "pt") &&
+               !base::EqualsCaseInsensitiveASCII(region, "br")) {
       // Map pt-RR other than pt-BR to pt-PT. Note that "pt" by itself maps to
       // pt-BR (logic below), and we need to explicitly check for pt-BR here as
       // it is unavailable on iOS.
       tmp_locale.append("-PT");
-    } else if (base::LowerCaseEqualsASCII(lang, "zh")) {
+    } else if (base::EqualsCaseInsensitiveASCII(lang, "zh")) {
       // Map zh-HK and zh-MO to zh-TW. Otherwise, zh-FOO is mapped to zh-CN.
-      if (base::LowerCaseEqualsASCII(region, "hk") ||
-          base::LowerCaseEqualsASCII(region, "mo")) {  // Macao
+      if (base::EqualsCaseInsensitiveASCII(region, "hk") ||
+          base::EqualsCaseInsensitiveASCII(region, "mo")) {  // Macao
         tmp_locale.append("-TW");
       } else {
         tmp_locale.append("-CN");
       }
-    } else if (base::LowerCaseEqualsASCII(lang, "en")) {
+    } else if (base::EqualsCaseInsensitiveASCII(lang, "en")) {
       // Map Liberian and Filipino English to US English, and everything
       // else to British English.
       // TODO(jungshik): en-CA may have to change sides once
       // we have OS locale separate from app locale (Chrome's UI language).
-      if (base::LowerCaseEqualsASCII(region, "lr") ||
-          base::LowerCaseEqualsASCII(region, "ph")) {
+      if (base::EqualsCaseInsensitiveASCII(region, "lr") ||
+          base::EqualsCaseInsensitiveASCII(region, "ph")) {
         tmp_locale.append("-US");
       } else {
         tmp_locale.append("-GB");
@@ -465,7 +465,7 @@
       {"pt", "pt-BR"}, {"tl", "fil"}, {"zh", "zh-CN"},
   };
   for (const auto& alias : kAliasMap) {
-    if (base::LowerCaseEqualsASCII(lang, alias.source)) {
+    if (base::EqualsCaseInsensitiveASCII(lang, alias.source)) {
       std::string tmp_locale(alias.dest);
       if (HasStringsForLocale(tmp_locale, perform_io)) {
         resolved_locale->swap(tmp_locale);
@@ -964,13 +964,13 @@
 
   // Chinese locales (other than the ones that have strings on disk) should not
   // be shown.
-  if (base::LowerCaseEqualsASCII(language, "zh")) {
+  if (base::EqualsCaseInsensitiveASCII(language, "zh")) {
     return false;
   }
 
   // Norwegian (no) should not be shown as it does not specify a written form.
   // Users can select Norwegian Bokmål (nb) or Norwegian Nynorsk (nn) instead.
-  if (base::LowerCaseEqualsASCII(language, "no")) {
+  if (base::EqualsCaseInsensitiveASCII(language, "no")) {
     return false;
   }
 
diff --git a/ui/base/test/cocoa_helper.h b/ui/base/test/cocoa_helper.h
index 4ec09b1..c9030fe 100644
--- a/ui/base/test/cocoa_helper.h
+++ b/ui/base/test/cocoa_helper.h
@@ -13,6 +13,7 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/strings/sys_string_conversions.h"
 #include "testing/platform_test.h"
+#include "ui/display/screen.h"
 
 // CocoaTestHelperWindow behaves differently from a regular NSWindow in the
 // following ways:
@@ -74,6 +75,8 @@
   CocoaTestHelperWindow* test_window();
 
  private:
+  display::ScopedNativeScreen screen_;
+
   // Return a set of currently open windows. Avoiding NSArray so
   // contents aren't retained, the pointer values can only be used for
   // comparison purposes.  Using std::set to make progress-checking
diff --git a/ui/display/display.cc b/ui/display/display.cc
index 3693f89..3c3c659 100644
--- a/ui/display/display.cc
+++ b/ui/display/display.cc
@@ -34,7 +34,7 @@
 // -1.0, we read the forced device scale factor again.
 float g_forced_device_scale_factor = -1.0;
 
-// An alloance error epsilon cauesd by fractional scale factor to produce
+// An allowance error epsilon caused by fractional scale factor to produce
 // expected DP display size.
 constexpr float kDisplaySizeAllowanceEpsilon = 0.01f;
 
@@ -252,6 +252,16 @@
 void Display::SetScaleAndBounds(float device_scale_factor,
                                 const gfx::Rect& bounds_in_pixel) {
   gfx::Insets insets = bounds_.InsetsFrom(work_area_);
+  SetScale(device_scale_factor);
+
+  gfx::RectF f(bounds_in_pixel);
+  f.Scale(1.f / device_scale_factor_);
+  bounds_ = gfx::ToEnclosedRectIgnoringError(f, kDisplaySizeAllowanceEpsilon);
+  size_in_pixels_ = bounds_in_pixel.size();
+  UpdateWorkAreaFromInsets(insets);
+}
+
+void Display::SetScale(float device_scale_factor) {
   if (!HasForceDeviceScaleFactor()) {
 #if BUILDFLAG(IS_APPLE)
     // Unless an explicit scale factor was provided for testing, ensure the
@@ -261,12 +271,6 @@
     device_scale_factor_ = device_scale_factor;
   }
   device_scale_factor_ = std::max(0.5f, device_scale_factor_);
-
-  gfx::RectF f(bounds_in_pixel);
-  f.Scale(1.f / device_scale_factor_);
-  bounds_ = gfx::ToEnclosedRectIgnoringError(f, kDisplaySizeAllowanceEpsilon);
-  size_in_pixels_ = bounds_in_pixel.size();
-  UpdateWorkAreaFromInsets(insets);
 }
 
 void Display::SetSize(const gfx::Size& size_in_pixel) {
diff --git a/ui/display/display.h b/ui/display/display.h
index 5a9b7ec..3d0c27f2 100644
--- a/ui/display/display.h
+++ b/ui/display/display.h
@@ -172,11 +172,16 @@
   gfx::Insets GetWorkAreaInsets() const;
 
   // Sets the device scale factor and display bounds in pixel. This
-  // updates the work are using the same insets between old bounds and
+  // updates the work area using the same insets between old bounds and
   // work area.
   void SetScaleAndBounds(float device_scale_factor,
                          const gfx::Rect& bounds_in_pixel);
 
+  // Sets the device scale factor while respecting forced scale factor and other
+  // constraints. Use this over set_device_scale_factor() unless you need to
+  // forcefully overwrite the scale.
+  void SetScale(float device_scale_factor);
+
   // Sets the display's size. This updates the work area using the same insets
   // between old bounds and work area.
   void SetSize(const gfx::Size& size_in_pixel);
diff --git a/ui/display/display_list.h b/ui/display/display_list.h
index 2eb14bc..4c90bea3 100644
--- a/ui/display/display_list.h
+++ b/ui/display/display_list.h
@@ -71,6 +71,9 @@
   bool IsValid() const;
 
   base::ObserverList<DisplayObserver>* observers() { return &observers_; }
+  const base::ObserverList<DisplayObserver>* observers() const {
+    return &observers_;
+  }
 
  private:
   // A non-const version of FindDisplayById.
diff --git a/ui/display/screen.cc b/ui/display/screen.cc
index 2225ae6..b972388 100644
--- a/ui/display/screen.cc
+++ b/ui/display/screen.cc
@@ -31,8 +31,7 @@
 
 // static
 Screen* Screen::GetScreen() {
-#if BUILDFLAG(IS_APPLE)
-  // TODO(scottmg): https://crbug.com/558054
+#if BUILDFLAG(IS_IOS)
   if (!g_screen)
     g_screen = CreateNativeScreen();
 #endif
@@ -40,10 +39,23 @@
 }
 
 // static
-Screen* Screen::SetScreenInstance(Screen* instance) {
+Screen* Screen::SetScreenInstance(Screen* instance,
+                                  const base::Location& location) {
+  // Do not allow screen instance override. The screen object has a lot of
+  // states, such as current display settings as well as observers, and safely
+  // transferring these to new screen implementation is very difficult and not
+  // safe.  If you hit the DCHECK in a test, please look for other examples that
+  // that set a test screen instance in the setup process.
+  DCHECK(!g_screen || !instance || (instance && instance->shutdown_))
+      << "fail=" << location.ToString();
   return std::exchange(g_screen, instance);
 }
 
+// static
+bool Screen::HasScreen() {
+  return !!g_screen;
+}
+
 void Screen::SetCursorScreenPointForTesting(const gfx::Point& point) {
   NOTIMPLEMENTED_LOG_ONCE();
 }
@@ -213,4 +225,49 @@
   return result;
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+
+ScopedNativeScreen::ScopedNativeScreen(const base::Location& location) {
+  MaybeInit(location);
+}
+
+ScopedNativeScreen::ScopedNativeScreen(bool call_maybe_init,
+                                       const base::Location& location) {
+  if (call_maybe_init)
+    MaybeInit(location);
+}
+
+ScopedNativeScreen::~ScopedNativeScreen() {
+  Shutdown();
+}
+
+void ScopedNativeScreen::MaybeInit(const base::Location& location) {
+  maybe_init_called_ = true;
+  if (!Screen::HasScreen()) {
+#if BUILDFLAG(IS_IOS)
+    Screen::GetScreen();
+#else
+    screen_ = base::WrapUnique(CreateScreen());
+    // ScreenOzone and DesktopScreenWin sets the instance by itself.
+    if (Screen::GetScreen() != screen_.get())
+      Screen::SetScreenInstance(screen_.get(), location);
+#endif
+  }
+}
+
+void ScopedNativeScreen::Shutdown() {
+  DCHECK(maybe_init_called_);
+  if (screen_) {
+    DCHECK_EQ(screen_.get(), Screen::GetScreen());
+    Screen::SetScreenInstance(nullptr);
+    screen_.reset();
+  }
+}
+
+Screen* ScopedNativeScreen::CreateScreen() {
+  return CreateNativeScreen();
+}
+
+#endif
+
 }  // namespace display
diff --git a/ui/display/screen.h b/ui/display/screen.h
index 3771a345..a86c5b6 100644
--- a/ui/display/screen.h
+++ b/ui/display/screen.h
@@ -9,8 +9,9 @@
 #include <set>
 #include <vector>
 
+#include "base/location.h"
 #include "base/values.h"
-#include "build/chromeos_buildflags.h"
+#include "build/build_config.h"
 #include "ui/display/display.h"
 #include "ui/display/display_export.h"
 #include "ui/display/screen_infos.h"
@@ -47,13 +48,20 @@
 
   virtual ~Screen();
 
-  // Retrieves the single Screen object; this may be null (e.g. in some tests).
+  // Retrieves the single Screen object; this may be null if it's not already
+  // created, except for IOS where it creates a native screen instance
+  // automatically.
   static Screen* GetScreen();
 
+  // Returns whether a Screen singleton exists or not.
+  static bool HasScreen();
+
+  // [Deprecated] as a public method. Do not use this.
   // Sets the global screen. Returns the previously installed screen, if any.
   // NOTE: this does not take ownership of |screen|. Tests must be sure to reset
   // any state they install.
-  static Screen* SetScreenInstance(Screen* instance);
+  static Screen* SetScreenInstance(Screen* instance,
+                                   const base::Location& location = FROM_HERE);
 
   // Returns the current absolute position of the mouse pointer.
   virtual gfx::Point GetCursorScreenPoint() = 0;
@@ -198,6 +206,8 @@
   virtual bool SetScreenSaverSuspended(bool suspend);
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
 
+  void set_shutdown(bool shutdown) { shutdown_ = shutdown; }
+
  private:
   friend class ScopedDisplayForNewWindows;
 
@@ -208,6 +218,9 @@
 
   static gfx::NativeWindow GetWindowForView(gfx::NativeView view);
 
+  // A flag indicates that the instance is a special one used during shutdown.
+  bool shutdown_ = false;
+
   int64_t display_id_for_new_windows_;
   int64_t scoped_display_id_for_new_windows_ = display::kInvalidDisplayId;
 
@@ -216,7 +229,41 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
 };
 
-Screen* CreateNativeScreen();
+// TODO(crbug.com/1317416): Make this static private member of
+// ScopedNativeScreen.
+DISPLAY_EXPORT Screen* CreateNativeScreen();
+
+// Android does not have `CreateNativeScreen()`.
+#if !BUILDFLAG(IS_ANDROID)
+
+// ScopedNativeScreen creates a native screen if there is no screen created yet
+// (e.g. by a unit test).
+class DISPLAY_EXPORT ScopedNativeScreen {
+ public:
+  explicit ScopedNativeScreen(const base::Location& location = FROM_HERE);
+  ScopedNativeScreen(const ScopedNativeScreen&) = delete;
+  ScopedNativeScreen& operator=(const ScopedNativeScreen&) = delete;
+  virtual ~ScopedNativeScreen();
+
+  // Create and initialize the screen instance if the screen instance does not
+  // exist yet.
+  void MaybeInit(const base::Location& location = FROM_HERE);
+  void Shutdown();
+
+  Screen* screen() { return screen_.get(); }
+
+  virtual Screen* CreateScreen();
+
+ protected:
+  explicit ScopedNativeScreen(bool call_maybe_init,
+                              const base::Location& location = FROM_HERE);
+
+ private:
+  bool maybe_init_called_{false};
+  std::unique_ptr<Screen> screen_;
+};
+
+#endif
 
 }  // namespace display
 
diff --git a/ui/display/screen_base.cc b/ui/display/screen_base.cc
index 03d89f0..2e9e375 100644
--- a/ui/display/screen_base.cc
+++ b/ui/display/screen_base.cc
@@ -75,6 +75,10 @@
   display_list_.RemoveObserver(observer);
 }
 
+bool ScreenBase::HasDisplayObservers() const {
+  return !display_list_.observers()->empty();
+}
+
 void ScreenBase::SetPanelRotationForTesting(int64_t display_id,
                                             Display::Rotation rotation) {
   Display display = *display_list_.FindDisplayById(display_id);
diff --git a/ui/display/screen_base.h b/ui/display/screen_base.h
index 1b63863..ef3f7013 100644
--- a/ui/display/screen_base.h
+++ b/ui/display/screen_base.h
@@ -45,6 +45,8 @@
   void SetPanelRotationForTesting(int64_t display_id,
                                   Display::Rotation rotation) override;
 
+  bool HasDisplayObservers() const;
+
  protected:
   // Invoked when a display changed in some way, including being added.
   // If |is_primary| is true, |changed_display| is the primary display.
diff --git a/ui/display/test/scoped_screen_override.h b/ui/display/test/scoped_screen_override.h
index 0ba1c31..aba5307f 100644
--- a/ui/display/test/scoped_screen_override.h
+++ b/ui/display/test/scoped_screen_override.h
@@ -11,6 +11,8 @@
 
 namespace test {
 
+// [Deprecated] Do not use this in new code.
+//
 // This class represents a RAII wrapper for global screen overriding. An object
 // of this class restores original display::Screen instance when it goes out of
 // scope. Prefer to use it instead of directly call of
diff --git a/ui/display/test/test_screen.cc b/ui/display/test/test_screen.cc
index e2ae5bb5..af96e29 100644
--- a/ui/display/test/test_screen.cc
+++ b/ui/display/test/test_screen.cc
@@ -10,18 +10,33 @@
 
 namespace display {
 namespace test {
+namespace {
+TestScreen* test_screen = nullptr;
+}
 
 // static
 constexpr gfx::Rect TestScreen::kDefaultScreenBounds;
 
 TestScreen::TestScreen(bool create_display) {
+  DCHECK(!test_screen);
+  test_screen = this;
+
   if (!create_display)
     return;
   Display display(1, kDefaultScreenBounds);
   ProcessDisplayChanged(display, /* is_primary = */ true);
 }
 
-TestScreen::~TestScreen() {}
+TestScreen::~TestScreen() {
+  DCHECK_EQ(test_screen, this);
+  test_screen = nullptr;
+}
+
+// static
+TestScreen* TestScreen::Get() {
+  DCHECK_EQ(Screen::GetScreen(), test_screen);
+  return test_screen;
+}
 
 void TestScreen::set_cursor_screen_point(const gfx::Point& point) {
   cursor_screen_point_ = point;
diff --git a/ui/display/test/test_screen.h b/ui/display/test/test_screen.h
index ff7fe07..9962e07 100644
--- a/ui/display/test/test_screen.h
+++ b/ui/display/test/test_screen.h
@@ -21,6 +21,8 @@
  public:
   static constexpr gfx::Rect kDefaultScreenBounds = gfx::Rect(0, 0, 800, 600);
 
+  static TestScreen* Get();
+
   // TODO(weili): Split this into a protected no-argument constructor for
   // subclass uses and the public one with gfx::Size argument.
   explicit TestScreen(bool create_display = true);
diff --git a/ui/display/win/test/scoped_screen_win.cc b/ui/display/win/test/scoped_screen_win.cc
index 84c1b4ca..edb39b8c 100644
--- a/ui/display/win/test/scoped_screen_win.cc
+++ b/ui/display/win/test/scoped_screen_win.cc
@@ -20,10 +20,6 @@
         gfx::Vector2dF(96.0, 96.0), DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER}});
 }
 
-ScopedScreenWin::~ScopedScreenWin() {
-  Screen::SetScreenInstance(old_screen_);
-}
-
 }  // namespace test
 }  // namespace win
 }  // namespace display
diff --git a/ui/display/win/test/scoped_screen_win.h b/ui/display/win/test/scoped_screen_win.h
index ca6cb2c..0633d2e 100644
--- a/ui/display/win/test/scoped_screen_win.h
+++ b/ui/display/win/test/scoped_screen_win.h
@@ -12,6 +12,10 @@
 namespace win {
 namespace test {
 
+// [Deprecated]
+// TODO(crbug.com/1317416): The initialization code of this class should be
+// moved to the test that depends on it.
+//
 // ScopedScreenWin construct a instance of ScreenWinDisplay with bounds
 // (1920,1080). This will allow unittests to query the details about ScreenWin
 // using static methods. ScopedScreenWin needs to be initialized before running
@@ -23,10 +27,7 @@
   ScopedScreenWin(const ScopedScreenWin&) = delete;
   ScopedScreenWin& operator=(const ScopedScreenWin&) = delete;
 
-  ~ScopedScreenWin() override;
-
- private:
-  raw_ptr<Screen> old_screen_ = Screen::SetScreenInstance(this);
+  ~ScopedScreenWin() override = default;
 };
 
 }  // namespace test
diff --git a/ui/events/ozone/evdev/event_converter_evdev.cc b/ui/events/ozone/evdev/event_converter_evdev.cc
index 907ec24..d63905f 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -103,6 +103,10 @@
   NOTREACHED();
 }
 
+KeyboardType EventConverterEvdev::GetKeyboardType() const {
+  return KeyboardType::NOT_KEYBOARD;
+}
+
 bool EventConverterEvdev::HasKeyboard() const {
   return false;
 }
diff --git a/ui/events/ozone/evdev/event_converter_evdev.h b/ui/events/ozone/evdev/event_converter_evdev.h
index e1007d2..d607811 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.h
+++ b/ui/events/ozone/evdev/event_converter_evdev.h
@@ -19,6 +19,7 @@
 #include "ui/events/devices/haptic_touchpad_effects.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/devices/stylus_state.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/events/ozone/evdev/touch_evdev_types.h"
 #include "ui/gfx/geometry/size.h"
@@ -101,6 +102,10 @@
   // Dump recent events into a file.
   virtual void DumpTouchEventLog(const char* filename);
 
+  // Returns value corresponding to keyboard status (No Keyboard, Keyboard in
+  // Blocklist, ect.).
+  virtual KeyboardType GetKeyboardType() const;
+
   // Returns true if the converter is used for a keyboard device.
   virtual bool HasKeyboard() const;
 
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index 4ad96a1..7eaaa48 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -53,7 +53,7 @@
                           devinfo.product_id(),
                           devinfo.version()),
       input_device_fd_(std::move(fd)),
-      has_keyboard_(devinfo.HasKeyboard()),
+      keyboard_type_(devinfo.GetKeyboardType()),
       has_touchpad_(devinfo.HasTouchpad()),
       has_numberpad_(devinfo.HasNumberpad()),
       has_stylus_switch_(devinfo.HasStylusSwitch()),
@@ -96,8 +96,12 @@
   ProcessEvents(inputs, read_size / sizeof(*inputs));
 }
 
+KeyboardType EventConverterEvdevImpl::GetKeyboardType() const {
+  return keyboard_type_;
+}
+
 bool EventConverterEvdevImpl::HasKeyboard() const {
-  return has_keyboard_;
+  return keyboard_type_ == KeyboardType::VALID_KEYBOARD;
 }
 
 bool EventConverterEvdevImpl::HasTouchpad() const {
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.h b/ui/events/ozone/evdev/event_converter_evdev_impl.h
index 11aca32b..f277e27 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.h
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -45,6 +45,7 @@
 
   // EventConverterEvdev:
   void OnFileCanReadWithoutBlocking(int fd) override;
+  KeyboardType GetKeyboardType() const override;
   bool HasKeyboard() const override;
   bool HasTouchpad() const override;
   bool HasCapsLockLed() const override;
@@ -83,8 +84,10 @@
   // Input device file descriptor.
   const base::ScopedFD input_device_fd_;
 
+  // KeyboardType
+  KeyboardType keyboard_type_;
+
   // Input modalities for this device.
-  bool has_keyboard_;
   bool has_touchpad_;
   bool has_numberpad_;
   bool has_stylus_switch_;
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
index 59ac8dd..ff50794 100644
--- a/ui/events/ozone/evdev/event_device_info.cc
+++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -742,20 +742,24 @@
 }
 
 bool EventDeviceInfo::HasKeyboard() const {
+  return GetKeyboardType() == KeyboardType::VALID_KEYBOARD;
+}
+
+KeyboardType EventDeviceInfo::GetKeyboardType() const {
   if (!HasEventType(EV_KEY))
-    return false;
+    return KeyboardType::NOT_KEYBOARD;
   if (IsInKeyboardBlockList(input_id_))
-    return false;
+    return KeyboardType::IN_BLOCKLIST;
   if (IsStylusButtonDevice())
-    return false;
+    return KeyboardType::STYLUS_BUTTON_DEVICE;
 
   // Check first 31 keys: If we have all of them, consider it a full
   // keyboard. This is exactly what udev does for ID_INPUT_KEYBOARD.
   for (int key = KEY_ESC; key <= KEY_D; ++key)
     if (!HasKeyEvent(key))
-      return false;
+      return KeyboardType::NOT_KEYBOARD;
 
-  return true;
+  return KeyboardType::VALID_KEYBOARD;
 }
 
 bool EventDeviceInfo::HasMouse() const {
diff --git a/ui/events/ozone/evdev/event_device_info.h b/ui/events/ozone/evdev/event_device_info.h
index 35dabc4..4bab8ae 100644
--- a/ui/events/ozone/evdev/event_device_info.h
+++ b/ui/events/ozone/evdev/event_device_info.h
@@ -45,6 +45,14 @@
   DT_ALL,
 };
 
+// Status of Keyboard Device
+enum COMPONENT_EXPORT(EVDEV) KeyboardType {
+  NOT_KEYBOARD,
+  IN_BLOCKLIST,
+  STYLUS_BUTTON_DEVICE,
+  VALID_KEYBOARD,
+};
+
 // Device information for Linux input devices
 //
 // This stores and queries information about input devices; in
@@ -137,6 +145,9 @@
   // Has stylus EV_KEY events.
   bool HasStylus() const;
 
+  // Determine status of keyboard device (No keyboard, In blocklist, ect.).
+  KeyboardType GetKeyboardType() const;
+
   // Determine whether there's a keyboard on this device.
   bool HasKeyboard() const;
 
diff --git a/ui/events/ozone/evdev/keyboard_imposter_checker_evdev.cc b/ui/events/ozone/evdev/keyboard_imposter_checker_evdev.cc
index 9d8461c2..33c8bb01 100644
--- a/ui/events/ozone/evdev/keyboard_imposter_checker_evdev.cc
+++ b/ui/events/ozone/evdev/keyboard_imposter_checker_evdev.cc
@@ -35,6 +35,11 @@
     EventConverterEvdev* converter) {
   if (!base::FeatureList::IsEnabled(kEnableFakeKeyboardHeuristic))
     return false;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (converter->GetKeyboardType() == KeyboardType::IN_BLOCKLIST) {
+    fake_keyboard_heuristic_metrics_.RecordUsage(false);
+  }
+#endif
 
   if (!converter->HasKeyboard() ||
       (!converter->HasMouse() &&
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index b5dbeea..64ece47 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -163,6 +163,8 @@
     "host/wayland_window_manager.h",
     "host/wayland_window_observer.cc",
     "host/wayland_window_observer.h",
+    "host/wayland_zaura_output.cc",
+    "host/wayland_zaura_output.h",
     "host/wayland_zaura_shell.cc",
     "host/wayland_zaura_shell.h",
     "host/wayland_zcr_cursor_shapes.cc",
@@ -471,6 +473,8 @@
     "test/test_wp_pointer_gestures.h",
     "test/test_xdg_popup.cc",
     "test/test_xdg_popup.h",
+    "test/test_zaura_output.cc",
+    "test/test_zaura_output.h",
     "test/test_zcr_stylus.cc",
     "test/test_zcr_stylus.h",
     "test/test_zcr_text_input_extension.cc",
@@ -535,6 +539,7 @@
     "host/wayland_window_drag_controller_unittest.cc",
     "host/wayland_window_manager_unittests.cc",
     "host/wayland_window_unittest.cc",
+    "host/wayland_zaura_output_unittest.cc",
     "host/wayland_zaura_shell_unittest.cc",
     "host/wayland_zwp_pointer_gestures_unittest.cc",
     "test/wayland_drag_drop_test.cc",
diff --git a/ui/ozone/platform/wayland/common/wayland_object.cc b/ui/ozone/platform/wayland/common/wayland_object.cc
index bf6b5c7..3c04508 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.cc
+++ b/ui/ozone/platform/wayland/common/wayland_object.cc
@@ -168,6 +168,7 @@
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_surface)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_toplevel)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(xdg_wm_base)
+IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_output)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_shell)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_surface)
 IMPLEMENT_WAYLAND_OBJECT_TRAITS(zaura_toplevel)
diff --git a/ui/ozone/platform/wayland/common/wayland_object.h b/ui/ozone/platform/wayland/common/wayland_object.h
index d07dcd2..924716c 100644
--- a/ui/ozone/platform/wayland/common/wayland_object.h
+++ b/ui/ozone/platform/wayland/common/wayland_object.h
@@ -148,6 +148,7 @@
 DECLARE_WAYLAND_OBJECT_TRAITS(xdg_surface)
 DECLARE_WAYLAND_OBJECT_TRAITS(xdg_toplevel)
 DECLARE_WAYLAND_OBJECT_TRAITS(xdg_wm_base)
+DECLARE_WAYLAND_OBJECT_TRAITS(zaura_output)
 DECLARE_WAYLAND_OBJECT_TRAITS(zaura_shell)
 DECLARE_WAYLAND_OBJECT_TRAITS(zaura_surface)
 DECLARE_WAYLAND_OBJECT_TRAITS(zaura_toplevel)
diff --git a/ui/ozone/platform/wayland/host/wayland_output.cc b/ui/ozone/platform/wayland/host/wayland_output.cc
index 2186d6a..4acb597f 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 
+#include <aura-shell-client-protocol.h>
 #include <xdg-output-unstable-v1-client-protocol.h>
 
 #include "base/logging.h"
@@ -11,6 +12,7 @@
 #include "ui/gfx/color_space.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_output.h"
 #include "ui/ozone/platform/wayland/host/xdg_output.h"
 
 namespace ui {
@@ -66,6 +68,12 @@
       zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output_.get()));
 }
 
+void WaylandOutput::InitializeZAuraOutput(zaura_shell* aura_shell) {
+  DCHECK(!aura_output_);
+  aura_output_ = std::make_unique<WaylandZAuraOutput>(
+      zaura_shell_get_aura_output(aura_shell, output_.get()));
+}
+
 void WaylandOutput::Initialize(Delegate* delegate) {
   DCHECK(!delegate_);
   delegate_ = delegate;
@@ -84,22 +92,49 @@
              : scale_factor();
 }
 
+int32_t WaylandOutput::logical_transform() const {
+  if (aura_output_ && aura_output_->logical_transform()) {
+    return *aura_output_->logical_transform();
+  }
+  return panel_transform();
+}
+
+gfx::Point WaylandOutput::origin() const {
+  if (xdg_output_ && xdg_output_->logical_position()) {
+    return *xdg_output_->logical_position();
+  }
+  return origin_;
+}
+
+gfx::Size WaylandOutput::logical_size() const {
+  return xdg_output_ ? xdg_output_->logical_size() : gfx::Size();
+}
+
+gfx::Insets WaylandOutput::insets() const {
+  return aura_output_ ? aura_output_->insets() : gfx::Insets();
+}
+
+zaura_output* WaylandOutput::get_zaura_output() const {
+  return aura_output_ ? aura_output_->wl_object() : nullptr;
+}
+
 void WaylandOutput::TriggerDelegateNotifications() {
   if (xdg_output_ && connection_->surface_submission_in_pixel_coordinates()) {
-    DCHECK(!rect_in_physical_pixels_.IsEmpty());
+    DCHECK(!physical_size_.IsEmpty());
     const gfx::Size logical_size = xdg_output_->logical_size();
     if (!logical_size.IsEmpty()) {
-      if (logical_size.width() >= logical_size.height()) {
-        scale_factor_ = rect_in_physical_pixels_.width() /
-                        static_cast<float>(logical_size.width());
-      } else {
-        scale_factor_ = rect_in_physical_pixels_.height() /
-                        static_cast<float>(logical_size.height());
-      }
+      // We calculate the fractional scale factor from the long sides of the
+      // physical and logical sizes, since their orientations may be different.
+      const float max_physical_side =
+          std::max(physical_size_.width(), physical_size_.height());
+      const float max_logical_side =
+          std::max(logical_size.width(), logical_size.height());
+      scale_factor_ = max_physical_side / max_logical_side;
     }
   }
-  delegate_->OnOutputHandleMetrics(output_id_, rect_in_physical_pixels_,
-                                   scale_factor_, transform_);
+  delegate_->OnOutputHandleMetrics(output_id_, origin(), logical_size(),
+                                   physical_size_, insets(), scale_factor_,
+                                   panel_transform_, logical_transform());
 }
 
 // static
@@ -115,8 +150,8 @@
                                          int32_t output_transform) {
   WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
   if (wayland_output) {
-    wayland_output->rect_in_physical_pixels_.set_origin(gfx::Point(x, y));
-    wayland_output->transform_ = output_transform;
+    wayland_output->origin_ = gfx::Point(x, y);
+    wayland_output->panel_transform_ = output_transform;
   }
 }
 
@@ -129,7 +164,7 @@
                                      int32_t refresh) {
   WaylandOutput* wayland_output = static_cast<WaylandOutput*>(data);
   if (wayland_output && (flags & WL_OUTPUT_MODE_CURRENT))
-    wayland_output->rect_in_physical_pixels_.set_size(gfx::Size(width, height));
+    wayland_output->physical_size_ = gfx::Size(width, height);
 }
 
 // static
diff --git a/ui/ozone/platform/wayland/host/wayland_output.h b/ui/ozone/platform/wayland/host/wayland_output.h
index c36c7c7..709f4a6 100644
--- a/ui/ozone/platform/wayland/host/wayland_output.h
+++ b/ui/ozone/platform/wayland/host/wayland_output.h
@@ -16,6 +16,7 @@
 
 class XDGOutput;
 class WaylandConnection;
+class WaylandZAuraOutput;
 
 // WaylandOutput objects keep track of the current output of display
 // that are available to the application.
@@ -32,9 +33,13 @@
   class Delegate {
    public:
     virtual void OnOutputHandleMetrics(uint32_t output_id,
-                                       const gfx::Rect& new_bounds,
+                                       const gfx::Point& origin,
+                                       const gfx::Size& logical_size,
+                                       const gfx::Size& physical_size,
+                                       const gfx::Insets& insets,
                                        float scale_factor,
-                                       int32_t transform) = 0;
+                                       int32_t panel_transform,
+                                       int32_t logical_transform) = 0;
 
    protected:
     virtual ~Delegate() = default;
@@ -51,19 +56,25 @@
 
   void Initialize(Delegate* delegate);
   void InitializeXdgOutput(struct zxdg_output_manager_v1* manager);
+  void InitializeZAuraOutput(zaura_shell* aura_shell);
   float GetUIScaleFactor() const;
 
   uint32_t output_id() const { return output_id_; }
   bool has_output(wl_output* output) const { return output_.get() == output; }
   float scale_factor() const { return scale_factor_; }
-  int32_t transform() const { return transform_; }
-  gfx::Rect bounds() const { return rect_in_physical_pixels_; }
+  int32_t panel_transform() const { return panel_transform_; }
+  int32_t logical_transform() const;
+  gfx::Point origin() const;
+  gfx::Size logical_size() const;
+  gfx::Size physical_size() const { return physical_size_; }
+  gfx::Insets insets() const;
 
   // Tells if the output has already received physical screen dimensions in the
   // global compositor space.
-  bool is_ready() const { return !rect_in_physical_pixels_.IsEmpty(); }
+  bool is_ready() const { return !physical_size_.IsEmpty(); }
 
-  wl_output* get_output() { return output_.get(); }
+  wl_output* get_output() const { return output_.get(); }
+  zaura_output* get_zaura_output() const;
 
  private:
   static constexpr int32_t kDefaultScaleFactor = 1;
@@ -97,9 +108,13 @@
   const uint32_t output_id_ = 0;
   wl::Object<wl_output> output_;
   std::unique_ptr<XDGOutput> xdg_output_;
+  std::unique_ptr<WaylandZAuraOutput> aura_output_;
   float scale_factor_ = kDefaultScaleFactor;
-  int32_t transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
-  gfx::Rect rect_in_physical_pixels_;
+  int32_t panel_transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
+  // Origin of the output in DIP screen coordinate.
+  gfx::Point origin_;
+  // Size of the output in physical pixels.
+  gfx::Size physical_size_;
 
   Delegate* delegate_ = nullptr;
   WaylandConnection* connection_ = nullptr;
diff --git a/ui/ozone/platform/wayland/host/wayland_output_manager.cc b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
index a7ccee03..87542ed 100644
--- a/ui/ozone/platform/wayland/host/wayland_output_manager.cc
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.cc
@@ -11,6 +11,7 @@
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
 #include "ui/ozone/platform/wayland/host/wayland_output.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h"
 
 namespace ui {
 
@@ -45,6 +46,10 @@
   wayland_output->Initialize(this);
   if (connection_->xdg_output_manager_v1())
     wayland_output->InitializeXdgOutput(connection_->xdg_output_manager_v1());
+  if (connection_->zaura_shell()) {
+    wayland_output->InitializeZAuraOutput(
+        connection_->zaura_shell()->wl_object());
+  }
   DCHECK(!wayland_output->is_ready());
 
   output_list_[output_id] = std::move(wayland_output);
@@ -74,6 +79,14 @@
     output.second->InitializeXdgOutput(connection_->xdg_output_manager_v1());
 }
 
+void WaylandOutputManager::InitializeAllZAuraOutputs() {
+  DCHECK(connection_->zaura_shell());
+  for (const auto& output : output_list_) {
+    output.second->InitializeZAuraOutput(
+        connection_->zaura_shell()->wl_object());
+  }
+}
+
 std::unique_ptr<WaylandScreen> WaylandOutputManager::CreateWaylandScreen() {
   auto wayland_screen = std::make_unique<WaylandScreen>(connection_);
   wayland_screen_ = wayland_screen->GetWeakPtr();
@@ -93,8 +106,10 @@
   for (const auto& output : output_list_) {
     if (output.second->is_ready()) {
       screen->OnOutputAddedOrUpdated(
-          output.second->output_id(), output.second->bounds(),
-          output.second->scale_factor(), output.second->transform());
+          output.second->output_id(), output.second->origin(),
+          output.second->logical_size(), output.second->physical_size(),
+          output.second->insets(), output.second->scale_factor(),
+          output.second->panel_transform(), output.second->logical_transform());
     }
   }
 }
@@ -114,12 +129,17 @@
 }
 
 void WaylandOutputManager::OnOutputHandleMetrics(uint32_t output_id,
-                                                 const gfx::Rect& new_bounds,
+                                                 const gfx::Point& origin,
+                                                 const gfx::Size& logical_size,
+                                                 const gfx::Size& physical_size,
+                                                 const gfx::Insets& insets,
                                                  float scale_factor,
-                                                 int32_t transform) {
+                                                 int32_t panel_transform,
+                                                 int32_t logical_transform) {
   if (wayland_screen_) {
-    wayland_screen_->OnOutputAddedOrUpdated(output_id, new_bounds,
-                                            scale_factor, transform);
+    wayland_screen_->OnOutputAddedOrUpdated(output_id, origin, logical_size,
+                                            physical_size, insets, scale_factor,
+                                            panel_transform, logical_transform);
   }
   auto* wayland_window_manager = connection_->wayland_window_manager();
   for (auto* window : wayland_window_manager->GetWindowsOnOutput(output_id))
diff --git a/ui/ozone/platform/wayland/host/wayland_output_manager.h b/ui/ozone/platform/wayland/host/wayland_output_manager.h
index 9f5711b4..23a34a88 100644
--- a/ui/ozone/platform/wayland/host/wayland_output_manager.h
+++ b/ui/ozone/platform/wayland/host/wayland_output_manager.h
@@ -38,6 +38,7 @@
   void RemoveWaylandOutput(const uint32_t output_id);
 
   void InitializeAllXdgOutputs();
+  void InitializeAllZAuraOutputs();
 
   // Creates a platform screen.
   std::unique_ptr<WaylandScreen> CreateWaylandScreen();
@@ -53,9 +54,13 @@
  private:
   // WaylandOutput::Delegate:
   void OnOutputHandleMetrics(uint32_t output_id,
-                             const gfx::Rect& new_bounds,
+                             const gfx::Point& origin,
+                             const gfx::Size& logical_size,
+                             const gfx::Size& physical_size,
+                             const gfx::Insets& insets,
                              float scale_factor,
-                             int32_t transform) override;
+                             int32_t panel_transform,
+                             int32_t logical_transform) override;
 
   using OutputList = base::flat_map<uint32_t, std::unique_ptr<WaylandOutput>>;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index c574965..67ff3ed 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -108,10 +108,15 @@
 WaylandScreen::~WaylandScreen() = default;
 
 void WaylandScreen::OnOutputAddedOrUpdated(uint32_t output_id,
-                                           const gfx::Rect& bounds,
+                                           const gfx::Point& origin,
+                                           const gfx::Size& logical_size,
+                                           const gfx::Size& physical_size,
+                                           const gfx::Insets& insets,
                                            float scale,
-                                           int32_t transform) {
-  AddOrUpdateDisplay(output_id, bounds, scale, transform);
+                                           int32_t panel_transform,
+                                           int32_t logical_transform) {
+  AddOrUpdateDisplay(output_id, origin, logical_size, physical_size, insets,
+                     scale, panel_transform, logical_transform);
 }
 
 void WaylandScreen::OnOutputRemoved(uint32_t output_id) {
@@ -141,22 +146,46 @@
 }
 
 void WaylandScreen::AddOrUpdateDisplay(uint32_t output_id,
-                                       const gfx::Rect& new_bounds,
+                                       const gfx::Point& origin,
+                                       const gfx::Size& logical_size,
+                                       const gfx::Size& physical_size,
+                                       const gfx::Insets& insets,
                                        float scale_factor,
-                                       int32_t transform) {
+                                       int32_t panel_transform,
+                                       int32_t logical_transform) {
   display::Display changed_display(output_id);
-  if (!display::Display::HasForceDeviceScaleFactor()) {
-    changed_display.SetScaleAndBounds(scale_factor, new_bounds);
-  } else {
-    changed_display.set_bounds(new_bounds);
-    changed_display.set_work_area(new_bounds);
-  }
 
-  DCHECK_GE(transform, WL_OUTPUT_TRANSFORM_NORMAL);
-  DCHECK_LE(transform, WL_OUTPUT_TRANSFORM_FLIPPED_270);
-  display::Display::Rotation rotation = WaylandTransformToRotation(transform);
+  DCHECK_GE(panel_transform, WL_OUTPUT_TRANSFORM_NORMAL);
+  DCHECK_LE(panel_transform, WL_OUTPUT_TRANSFORM_FLIPPED_270);
+  display::Display::Rotation panel_rotation =
+      WaylandTransformToRotation(panel_transform);
+  changed_display.set_panel_rotation(panel_rotation);
+
+  DCHECK_GE(logical_transform, WL_OUTPUT_TRANSFORM_NORMAL);
+  DCHECK_LE(logical_transform, WL_OUTPUT_TRANSFORM_FLIPPED_270);
+  display::Display::Rotation rotation =
+      WaylandTransformToRotation(logical_transform);
   changed_display.set_rotation(rotation);
-  changed_display.set_panel_rotation(rotation);
+
+  gfx::Size size_in_pixels(physical_size);
+  if (panel_rotation == display::Display::Rotation::ROTATE_90 ||
+      panel_rotation == display::Display::Rotation::ROTATE_270) {
+    size_in_pixels.Transpose();
+  }
+  changed_display.set_size_in_pixels(size_in_pixels);
+
+  if (!logical_size.IsEmpty()) {
+    changed_display.set_bounds(gfx::Rect(origin, logical_size));
+    changed_display.SetScale(scale_factor);
+  } else {
+    // Fallback to calculating using physical size.
+    // This can happen if xdg_output.logical_size was not sent.
+    changed_display.SetScaleAndBounds(scale_factor, gfx::Rect(size_in_pixels));
+    gfx::Rect new_bounds(changed_display.bounds());
+    new_bounds.set_origin(origin);
+    changed_display.set_bounds(new_bounds);
+  }
+  changed_display.UpdateWorkAreaFromInsets(insets);
 
   gfx::DisplayColorSpaces color_spaces;
   color_spaces.SetOutputBufferFormats(image_format_no_alpha_.value(),
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.h b/ui/ozone/platform/wayland/host/wayland_screen.h
index 5b59b77..87358f4 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.h
+++ b/ui/ozone/platform/wayland/host/wayland_screen.h
@@ -40,9 +40,13 @@
   ~WaylandScreen() override;
 
   void OnOutputAddedOrUpdated(uint32_t output_id,
-                              const gfx::Rect& bounds,
-                              float output_scale,
-                              int32_t output_transform);
+                              const gfx::Point& origin,
+                              const gfx::Size& logical_size,
+                              const gfx::Size& physical_size,
+                              const gfx::Insets& insets,
+                              float scale,
+                              int32_t panel_transform,
+                              int32_t logical_transform);
   void OnOutputRemoved(uint32_t output_id);
 
   void OnTabletStateChanged(display::TabletState tablet_state);
@@ -73,10 +77,16 @@
       const gfx::GpuExtraInfo& gpu_extra_info) override;
 
  private:
+  // All parameters are in DIP screen coordinates/units except |physical_size|,
+  // which is in physical pixels.
   void AddOrUpdateDisplay(uint32_t output_id,
-                          const gfx::Rect& bounds,
+                          const gfx::Point& origin,
+                          const gfx::Size& logical_size,
+                          const gfx::Size& physical_size,
+                          const gfx::Insets& insets,
                           float scale,
-                          int32_t transform);
+                          int32_t panel_transform,
+                          int32_t logical_transform);
 
   WaylandConnection* connection_ = nullptr;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index ca80363..47bb828 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <wayland-server-protocol.h>
 #include <wayland-server.h>
 #include <memory>
 
@@ -21,6 +22,7 @@
 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
 #include "ui/ozone/platform/wayland/test/mock_surface.h"
 #include "ui/ozone/platform/wayland/test/mock_wayland_platform_window_delegate.h"
+#include "ui/ozone/platform/wayland/test/mock_zaura_shell.h"
 #include "ui/ozone/platform/wayland/test/test_output.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
 #include "ui/ozone/platform/wayland/test/wayland_test.h"
@@ -90,6 +92,9 @@
 
     WaylandTest::SetUp();
 
+    mock_zaura_shell_ = std::make_unique<wl::MockZAuraShell>();
+    mock_zaura_shell_->Initialize(server_.display());
+
     output_->SetRect({kOutputWidth, kOutputHeight});
     output_->SetScale(1);
     output_->Flush();
@@ -124,6 +129,8 @@
     EXPECT_EQ(display_for_widget.id(), expected_display_id);
   }
 
+  std::unique_ptr<wl::MockZAuraShell> mock_zaura_shell_;
+
   wl::TestOutput* output_ = nullptr;
   WaylandOutputManager* output_manager_ = nullptr;
 
@@ -295,8 +302,8 @@
   TestDisplayObserver observer;
   platform_screen_->AddObserver(&observer);
 
-  gfx::Rect new_rect{100, 100};
-  output_->SetRect(new_rect);
+  const gfx::Rect physical_bounds{800, 600};
+  output_->SetRect(physical_bounds);
   output_->Flush();
 
   Sync();
@@ -304,8 +311,30 @@
   uint32_t changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
                             display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
   EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
-  EXPECT_EQ(observer.GetDisplay().bounds(), new_rect);
+  const gfx::Rect expected_bounds{800, 600};
+  EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds);
+  const gfx::Size expected_size_in_pixels{800, 600};
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels);
+  EXPECT_EQ(observer.GetDisplay().work_area(), expected_bounds);
 
+  // Test work area.
+  const gfx::Rect new_work_area{10, 20, 700, 500};
+  const gfx::Insets expected_inset = expected_bounds.InsetsFrom(new_work_area);
+  ASSERT_TRUE(output_->GetAuraOutput());
+  output_->GetAuraOutput()->SetInsets(expected_inset);
+  output_->Flush();
+
+  Sync();
+
+  changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+  EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
+  // Bounds should be unchanged.
+  EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds);
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels);
+  // Work area should have new value.
+  EXPECT_EQ(observer.GetDisplay().work_area(), new_work_area);
+
+  // Test scaling.
   const int32_t new_scale_value = 2;
   output_->SetScale(new_scale_value);
   output_->Flush();
@@ -318,7 +347,157 @@
       display::DisplayObserver::DISPLAY_METRIC_BOUNDS;
   EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
   EXPECT_EQ(observer.GetDisplay().device_scale_factor(), new_scale_value);
-  EXPECT_EQ(observer.GetDisplay().bounds(), gfx::Rect(50, 50));
+  // Logical bounds should shrink due to scaling.
+  const gfx::Rect scaled_bounds{400, 300};
+  EXPECT_EQ(observer.GetDisplay().bounds(), scaled_bounds);
+  // Size in pixel should stay unscaled.
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels);
+  gfx::Rect scaled_work_area(scaled_bounds);
+  scaled_work_area.Inset(expected_inset);
+  EXPECT_EQ(observer.GetDisplay().work_area(), scaled_work_area);
+
+  // Test rotation.
+  output_->SetTransform(WL_OUTPUT_TRANSFORM_90);
+  output_->Flush();
+
+  Sync();
+
+  changed_values = display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+                   display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+                   display::DisplayObserver::DISPLAY_METRIC_ROTATION;
+  EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
+  // Logical bounds should now be rotated to portrait.
+  const gfx::Rect rotated_bounds{300, 400};
+  EXPECT_EQ(observer.GetDisplay().bounds(), rotated_bounds);
+  // Size in pixel gets rotated too, but stays unscaled.
+  const gfx::Size rotated_size_in_pixels{600, 800};
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), rotated_size_in_pixels);
+  gfx::Rect rotated_work_area(rotated_bounds);
+  rotated_work_area.Inset(expected_inset);
+  EXPECT_EQ(observer.GetDisplay().work_area(), rotated_work_area);
+  EXPECT_EQ(observer.GetDisplay().panel_rotation(),
+            display::Display::Rotation::ROTATE_270);
+  EXPECT_EQ(observer.GetDisplay().rotation(),
+            display::Display::Rotation::ROTATE_270);
+
+  platform_screen_->RemoveObserver(&observer);
+}
+
+// Regression test for crbug.com/1310981.
+// Some devices use display panels built in portrait orientation, but are used
+// in landscape orientation. Thus their physical bounds are in portrait
+// orientation along with an offset transform, which differs from the usual
+// landscape oriented bounds.
+TEST_P(WaylandScreenTest, OutputPropertyChangesWithPortraitPanelRotation) {
+  TestDisplayObserver observer;
+  platform_screen_->AddObserver(&observer);
+
+  // wl_output.geometry origin is set in DIP screen coordinates.
+  const gfx::Point origin(50, 70);
+  // wl_output.mode size is sent in physical coordinates, so it has portrait
+  // dimensions for a display panel with portrait natural orientation.
+  const gfx::Size physical_size(1200, 1600);
+  output_->SetRect({origin, physical_size});
+
+  // Inset is sent in logical coordinates.
+  const gfx::Insets insets = gfx::Insets::TLBR(10, 20, 30, 40);
+  ASSERT_TRUE(output_->GetAuraOutput());
+  output_->GetAuraOutput()->SetInsets(insets);
+
+  // Display panel's natural orientation is in portrait, so it needs a transform
+  // of 90 degrees to be in landscape.
+  output_->SetTransform(WL_OUTPUT_TRANSFORM_90);
+  // Begin with the logical transform at 0 degrees.
+  output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_NORMAL);
+
+  output_->SetScale(2);
+  output_->Flush();
+
+  Sync();
+
+  uint32_t changed_values =
+      display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+      display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+      display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+      display::DisplayObserver::DISPLAY_METRIC_ROTATION;
+  EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
+
+  // Logical bounds should be in landscape.
+  const gfx::Rect expected_bounds(origin, gfx::Size(800, 600));
+  EXPECT_EQ(observer.GetDisplay().bounds(), expected_bounds);
+  const gfx::Size expected_size_in_pixels(1600, 1200);
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), expected_size_in_pixels);
+
+  gfx::Rect expected_work_area(expected_bounds);
+  expected_work_area.Inset(insets);
+  EXPECT_EQ(observer.GetDisplay().work_area(), expected_work_area);
+
+  // Panel rotation and display rotation should have an offset.
+  EXPECT_EQ(observer.GetDisplay().panel_rotation(),
+            display::Display::Rotation::ROTATE_270);
+  EXPECT_EQ(observer.GetDisplay().rotation(),
+            display::Display::Rotation::ROTATE_0);
+
+  // Further rotate the display to logical portrait orientation, which is 180
+  // with the natural orientation offset.
+  output_->SetTransform(WL_OUTPUT_TRANSFORM_180);
+  output_->GetAuraOutput()->SetLogicalTransform(WL_OUTPUT_TRANSFORM_90);
+  output_->Flush();
+
+  Sync();
+
+  changed_values = display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+                   display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
+                   display::DisplayObserver::DISPLAY_METRIC_ROTATION;
+  EXPECT_EQ(observer.GetAndClearChangedMetrics(), changed_values);
+
+  // Logical bounds should now be portrait.
+  const gfx::Rect portrait_bounds(origin, gfx::Size(600, 800));
+  EXPECT_EQ(observer.GetDisplay().bounds(), portrait_bounds);
+  const gfx::Size portrait_size_in_pixels(1200, 1600);
+  EXPECT_EQ(observer.GetDisplay().GetSizeInPixel(), portrait_size_in_pixels);
+
+  gfx::Rect portrait_work_area(portrait_bounds);
+  portrait_work_area.Inset(insets);
+  EXPECT_EQ(observer.GetDisplay().work_area(), portrait_work_area);
+
+  // Panel rotation and display rotation should still have an offset.
+  EXPECT_EQ(observer.GetDisplay().panel_rotation(),
+            display::Display::Rotation::ROTATE_180);
+  EXPECT_EQ(observer.GetDisplay().rotation(),
+            display::Display::Rotation::ROTATE_270);
+
+  platform_screen_->RemoveObserver(&observer);
+}
+
+TEST_P(WaylandScreenTest, OutputPropertyChangesMissingLogicalSize) {
+  TestDisplayObserver observer;
+  platform_screen_->AddObserver(&observer);
+
+  const uint32_t display_id = 7;
+  const gfx::Point origin(50, 70);
+  const gfx::Size physical_size(1200, 1600);
+  const wl_output_transform panel_transform = WL_OUTPUT_TRANSFORM_90;
+  const wl_output_transform logical_transform = WL_OUTPUT_TRANSFORM_NORMAL;
+  const gfx::Insets insets = gfx::Insets::TLBR(10, 20, 30, 40);
+  const float scale = 2;
+
+  // Test with missing logical size. Should fall back to calculating from
+  // physical size.
+  platform_screen_->OnOutputAddedOrUpdated(display_id, origin, gfx::Size(),
+                                           physical_size, insets, scale,
+                                           panel_transform, logical_transform);
+
+  const display::Display new_display(observer.GetDisplay());
+  EXPECT_EQ(new_display.id(), display_id);
+  EXPECT_EQ(new_display.bounds(), gfx::Rect(origin, gfx::Size(800, 600)));
+  EXPECT_EQ(new_display.GetSizeInPixel(), gfx::Size(1600, 1200));
+  gfx::Rect expected_work_area(new_display.bounds());
+  expected_work_area.Inset(insets);
+  EXPECT_EQ(new_display.work_area(), expected_work_area);
+  EXPECT_EQ(new_display.panel_rotation(), display::Display::ROTATE_270);
+  EXPECT_EQ(new_display.rotation(), display::Display::ROTATE_0);
+  EXPECT_EQ(new_display.device_scale_factor(), scale);
 
   platform_screen_->RemoveObserver(&observer);
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_output.cc b/ui/ozone/platform/wayland/host/wayland_zaura_output.cc
new file mode 100644
index 0000000..6fc1be01
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_output.cc
@@ -0,0 +1,55 @@
+// 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/ozone/platform/wayland/host/wayland_zaura_output.h"
+
+#include <aura-shell-client-protocol.h>
+
+#include "base/check.h"
+
+namespace ui {
+
+WaylandZAuraOutput::WaylandZAuraOutput(zaura_output* aura_output)
+    : obj_(aura_output) {
+  DCHECK(obj_);
+
+  static constexpr zaura_output_listener kZAuraOutputListener = {
+      &OnScale, &OnConnection, &OnDeviceScaleFactor, &OnInsets,
+      &OnLogicalTransform};
+  zaura_output_add_listener(obj_.get(), &kZAuraOutputListener, this);
+}
+
+WaylandZAuraOutput::~WaylandZAuraOutput() = default;
+
+void WaylandZAuraOutput::OnScale(void* data,
+                                 struct zaura_output* zaura_output,
+                                 uint32_t flags,
+                                 uint32_t scale) {}
+
+void WaylandZAuraOutput::OnConnection(void* data,
+                                      struct zaura_output* zaura_output,
+                                      uint32_t connection) {}
+
+void WaylandZAuraOutput::OnDeviceScaleFactor(void* data,
+                                             struct zaura_output* zaura_output,
+                                             uint32_t scale) {}
+
+void WaylandZAuraOutput::OnInsets(void* data,
+                                  struct zaura_output* zaura_output,
+                                  int32_t top,
+                                  int32_t left,
+                                  int32_t bottom,
+                                  int32_t right) {
+  if (auto* aura_output = static_cast<WaylandZAuraOutput*>(data))
+    aura_output->insets_ = gfx::Insets::TLBR(top, left, bottom, right);
+}
+
+void WaylandZAuraOutput::OnLogicalTransform(void* data,
+                                            struct zaura_output* zaura_output,
+                                            int32_t transform) {
+  if (auto* aura_output = static_cast<WaylandZAuraOutput*>(data))
+    aura_output->logical_transform_ = transform;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_output.h b/ui/ozone/platform/wayland/host/wayland_zaura_output.h
new file mode 100644
index 0000000..6f1eb38
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_output.h
@@ -0,0 +1,60 @@
+// 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_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_OUTPUT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_OUTPUT_H_
+
+#include <cstdint>
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/ozone/platform/wayland/common/wayland_object.h"
+
+namespace ui {
+
+// Wraps the zaura_output object.
+class WaylandZAuraOutput {
+ public:
+  explicit WaylandZAuraOutput(zaura_output* aura_output);
+  WaylandZAuraOutput(const WaylandZAuraOutput&) = delete;
+  WaylandZAuraOutput& operator=(const WaylandZAuraOutput&) = delete;
+  ~WaylandZAuraOutput();
+
+  zaura_output* wl_object() { return obj_.get(); }
+
+  const gfx::Insets& insets() const { return insets_; }
+  absl::optional<int32_t> logical_transform() const {
+    return logical_transform_;
+  }
+
+ private:
+  // zaura_output_listeners
+  static void OnScale(void* data,
+                      struct zaura_output* zaura_output,
+                      uint32_t flags,
+                      uint32_t scale);
+  static void OnConnection(void* data,
+                           struct zaura_output* zaura_output,
+                           uint32_t connection);
+  static void OnDeviceScaleFactor(void* data,
+                                  struct zaura_output* zaura_output,
+                                  uint32_t scale);
+  static void OnInsets(void* data,
+                       struct zaura_output* zaura_output,
+                       int32_t top,
+                       int32_t left,
+                       int32_t bottom,
+                       int32_t right);
+  static void OnLogicalTransform(void* data,
+                                 struct zaura_output* zaura_output,
+                                 int32_t transform);
+
+  wl::Object<zaura_output> obj_;
+  gfx::Insets insets_;
+  absl::optional<int32_t> logical_transform_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_ZAURA_OUTPUT_H_
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc b/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc
new file mode 100644
index 0000000..a29d9c68
--- /dev/null
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_output_unittest.cc
@@ -0,0 +1,130 @@
+// 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/ozone/platform/wayland/host/wayland_zaura_output.h"
+
+#include <aura-shell-client-protocol.h>
+#include <aura-shell-server-protocol.h>
+#include <wayland-server-protocol.h>
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/platform/wayland/host/wayland_connection.h"
+#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
+#include "ui/ozone/platform/wayland/host/wayland_output.h"
+#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
+#include "ui/ozone/platform/wayland/test/mock_zaura_shell.h"
+#include "ui/ozone/platform/wayland/test/server_object.h"
+#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/test_zaura_output.h"
+
+namespace ui {
+namespace {
+
+using ::testing::Values;
+
+class WaylandZAuraOutputTest : public ::testing::Test {
+ public:
+  WaylandZAuraOutputTest()
+      : task_environment_(
+            base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {}
+
+  WaylandZAuraOutputTest(const WaylandZAuraOutputTest&) = delete;
+  WaylandZAuraOutputTest& operator=(const WaylandZAuraOutputTest&) = delete;
+
+  ~WaylandZAuraOutputTest() override = default;
+
+  void SetUp() override {
+    ::testing::Test::SetUp();
+
+    ASSERT_TRUE(server_.Start({.shell_version = wl::ShellVersion::kStable}));
+    mock_zaura_shell_.Initialize(server_.display());
+
+    ASSERT_TRUE(connection_.Initialize());
+    connection_.event_source()->StartProcessingEvents();
+    base::RunLoop().RunUntilIdle();
+
+    // Set default values for the output.
+    wl::TestOutput* output = server_.output();
+    output->SetRect({800, 600});
+    output->SetScale(1);
+    output->Flush();
+
+    base::RunLoop().RunUntilIdle();
+    server_.Pause();
+
+    output_manager_ = connection_.wayland_output_manager();
+    ASSERT_TRUE(output_manager_);
+    EXPECT_TRUE(output_manager_->IsOutputReady());
+
+    // Initializing the screen also connects it to the primary output, so it's
+    // easier for us to get the associated WaylandOutput object later.
+    platform_screen_ = output_manager_->CreateWaylandScreen();
+    output_manager_->InitWaylandScreen(platform_screen_.get());
+  }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  wl::TestWaylandServerThread server_;
+  wl::MockZAuraShell mock_zaura_shell_;
+  WaylandConnection connection_;
+
+  WaylandOutputManager* output_manager_ = nullptr;
+  std::unique_ptr<WaylandScreen> platform_screen_;
+};
+
+TEST_F(WaylandZAuraOutputTest, HandleInsets) {
+  WaylandOutput* wayland_output = output_manager_->GetPrimaryOutput();
+  ASSERT_TRUE(wayland_output);
+  EXPECT_TRUE(wayland_output->is_ready());
+  EXPECT_EQ(wayland_output->physical_size(), gfx::Size(800, 600));
+  EXPECT_TRUE(wayland_output->insets().IsEmpty());
+  EXPECT_TRUE(wayland_output->get_zaura_output());
+
+  // Simulate server sending updated insets to the client.
+  wl_resource* zaura_output_resource =
+      server_.output()->GetAuraOutput()->resource();
+  ASSERT_TRUE(zaura_output_resource);
+  const gfx::Insets sent_insets =
+      gfx::Rect(800, 600).InsetsFrom(gfx::Rect(10, 10, 500, 400));
+  EXPECT_FALSE(sent_insets.IsEmpty());
+  zaura_output_send_insets(zaura_output_resource, sent_insets.top(),
+                           sent_insets.left(), sent_insets.bottom(),
+                           sent_insets.right());
+
+  server_.Resume();
+  base::RunLoop().RunUntilIdle();
+  server_.Pause();
+
+  // Verify that insets is updated.
+  EXPECT_TRUE(wayland_output->is_ready());
+  EXPECT_EQ(wayland_output->physical_size(), gfx::Size(800, 600));
+  EXPECT_EQ(wayland_output->insets(), sent_insets);
+}
+
+TEST_F(WaylandZAuraOutputTest, HandleLogicalTransform) {
+  WaylandOutput* wayland_output = output_manager_->GetPrimaryOutput();
+  ASSERT_TRUE(wayland_output);
+  EXPECT_TRUE(wayland_output->is_ready());
+  EXPECT_FALSE(wayland_output->logical_transform());
+  EXPECT_TRUE(wayland_output->get_zaura_output());
+
+  // Simulate server sending updated transform offset to the client.
+  wl_resource* zaura_output_resource =
+      server_.output()->GetAuraOutput()->resource();
+  ASSERT_TRUE(zaura_output_resource);
+  zaura_output_send_logical_transform(zaura_output_resource,
+                                      WL_OUTPUT_TRANSFORM_270);
+
+  server_.Resume();
+  base::RunLoop().RunUntilIdle();
+  server_.Pause();
+
+  EXPECT_TRUE(wayland_output->is_ready());
+  EXPECT_EQ(wayland_output->logical_transform(), WL_OUTPUT_TRANSFORM_270);
+}
+
+}  // namespace
+}  // namespace ui
\ No newline at end of file
diff --git a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
index bd5ba098..6c8b6454 100644
--- a/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
+++ b/ui/ozone/platform/wayland/host/wayland_zaura_shell.cc
@@ -20,7 +20,7 @@
 
 namespace {
 constexpr uint32_t kMinVersion = 1;
-constexpr uint32_t kMaxVersion = 32;
+constexpr uint32_t kMaxVersion = 34;
 }
 
 // static
@@ -48,6 +48,13 @@
   connection->zaura_shell_ =
       std::make_unique<WaylandZAuraShell>(zaura_shell.release(), connection);
   ReportShellUMA(UMALinuxWaylandShell::kZauraShell);
+
+  // Usually WaylandOutputManager is instantiated first, so any ZAuraOutputs it
+  // created wouldn't have been initialized, since the zaura_shell didn't exist
+  // yet. So initialize them now.
+  if (connection->wayland_output_manager()) {
+    connection->wayland_output_manager()->InitializeAllZAuraOutputs();
+  }
 }
 
 WaylandZAuraShell::WaylandZAuraShell(zaura_shell* aura_shell,
diff --git a/ui/ozone/platform/wayland/host/xdg_output.cc b/ui/ozone/platform/wayland/host/xdg_output.cc
index 5541032..e032673 100644
--- a/ui/ozone/platform/wayland/host/xdg_output.cc
+++ b/ui/ozone/platform/wayland/host/xdg_output.cc
@@ -28,7 +28,10 @@
     void* data,
     struct zxdg_output_v1* zxdg_output_v1,
     int32_t x,
-    int32_t y) {}
+    int32_t y) {
+  if (XDGOutput* xdg_output = static_cast<XDGOutput*>(data))
+    xdg_output->logical_position_ = gfx::Point(x, y);
+}
 
 // static
 void XDGOutput::OutputHandleLogicalSize(void* data,
diff --git a/ui/ozone/platform/wayland/host/xdg_output.h b/ui/ozone/platform/wayland/host/xdg_output.h
index d014f6f..441db68 100644
--- a/ui/ozone/platform/wayland/host/xdg_output.h
+++ b/ui/ozone/platform/wayland/host/xdg_output.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 
@@ -19,6 +21,9 @@
   XDGOutput& operator=(const XDGOutput&) = delete;
   ~XDGOutput();
 
+  absl::optional<gfx::Point> logical_position() const {
+    return logical_position_;
+  }
   gfx::Size logical_size() const { return logical_size_; }
 
  private:
@@ -40,6 +45,7 @@
                                       const char* description);
 
   wl::Object<zxdg_output_v1> xdg_output_;
+  absl::optional<gfx::Point> logical_position_;
   gfx::Size logical_size_;
 };
 
diff --git a/ui/ozone/platform/wayland/test/mock_zaura_shell.cc b/ui/ozone/platform/wayland/test/mock_zaura_shell.cc
index 7e5fae6..7bad5c3 100644
--- a/ui/ozone/platform/wayland/test/mock_zaura_shell.cc
+++ b/ui/ozone/platform/wayland/test/mock_zaura_shell.cc
@@ -5,12 +5,15 @@
 #include "ui/ozone/platform/wayland/test/mock_zaura_shell.h"
 
 #include "ui/ozone/platform/wayland/test/server_object.h"
+#include "ui/ozone/platform/wayland/test/test_output.h"
+#include "ui/ozone/platform/wayland/test/test_zaura_output.h"
 
 namespace wl {
 
 namespace {
 
-constexpr uint32_t kZAuraShellVersion = 26;
+constexpr uint32_t kZAuraShellVersion = 34;
+constexpr uint32_t kZAuraOutputVersion = 34;
 
 void GetAuraSurface(wl_client* client,
                     wl_resource* resource,
@@ -20,7 +23,12 @@
 void GetAuraOutput(wl_client* client,
                    wl_resource* resource,
                    uint32_t id,
-                   wl_resource* output_resource) {}
+                   wl_resource* output_resource) {
+  wl_resource* zaura_output_resource = CreateResourceWithImpl<TestZAuraOutput>(
+      client, &zaura_output_interface, kZAuraOutputVersion, nullptr, id);
+  auto* output = GetUserDataAs<TestOutput>(output_resource);
+  output->SetAuraOutput(GetUserDataAs<TestZAuraOutput>(zaura_output_resource));
+}
 
 void SurfaceSubmissionInPixelCoordinates(wl_client* client,
                                          wl_resource* resource) {}
diff --git a/ui/ozone/platform/wayland/test/test_output.cc b/ui/ozone/platform/wayland/test/test_output.cc
index 3d8b0d2..c0ec7a90 100644
--- a/ui/ozone/platform/wayland/test/test_output.cc
+++ b/ui/ozone/platform/wayland/test/test_output.cc
@@ -56,6 +56,10 @@
     scale_ = std::move(pending_scale_.value());
     wl_output_send_scale(resource(), scale_);
   }
+
+  if (aura_output_)
+    aura_output_->Flush();
+
   wl_output_send_done(resource());
 }
 
@@ -71,4 +75,12 @@
   Flush();
 }
 
+void TestOutput::SetAuraOutput(TestZAuraOutput* aura_output) {
+  aura_output_ = aura_output;
+}
+
+TestZAuraOutput* TestOutput::GetAuraOutput() {
+  return aura_output_;
+}
+
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_output.h b/ui/ozone/platform/wayland/test/test_output.h
index b8ed75c8..5b90dc0 100644
--- a/ui/ozone/platform/wayland/test/test_output.h
+++ b/ui/ozone/platform/wayland/test/test_output.h
@@ -11,6 +11,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/ozone/platform/wayland/test/global_object.h"
+#include "ui/ozone/platform/wayland/test/test_zaura_output.h"
 
 namespace wl {
 
@@ -32,6 +33,9 @@
 
   void Flush();
 
+  void SetAuraOutput(TestZAuraOutput* aura_output);
+  TestZAuraOutput* GetAuraOutput();
+
  protected:
   void OnBind() override;
 
@@ -43,6 +47,8 @@
   absl::optional<gfx::Rect> pending_rect_ = absl::nullopt;
   absl::optional<int32_t> pending_scale_ = absl::nullopt;
   absl::optional<wl_output_transform> pending_transform_ = absl::nullopt;
+
+  TestZAuraOutput* aura_output_ = nullptr;
 };
 
 }  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_zaura_output.cc b/ui/ozone/platform/wayland/test/test_zaura_output.cc
new file mode 100644
index 0000000..45d2cd1
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_zaura_output.cc
@@ -0,0 +1,30 @@
+// 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/ozone/platform/wayland/test/test_zaura_output.h"
+
+#include <aura-shell-server-protocol.h>
+
+namespace wl {
+
+TestZAuraOutput::TestZAuraOutput(wl_resource* resource)
+    : ServerObject(resource) {}
+
+TestZAuraOutput::~TestZAuraOutput() = default;
+
+void TestZAuraOutput::Flush() {
+  if (pending_insets_) {
+    insets_ = std::move(*pending_insets_);
+    pending_insets_.reset();
+    zaura_output_send_insets(resource(), insets_.top(), insets_.left(),
+                             insets_.bottom(), insets_.right());
+  }
+  if (pending_logical_transform_) {
+    logical_transform_ = std::move(*pending_logical_transform_);
+    pending_logical_transform_.reset();
+    zaura_output_send_logical_transform(resource(), logical_transform_);
+  }
+}
+
+}  // namespace wl
diff --git a/ui/ozone/platform/wayland/test/test_zaura_output.h b/ui/ozone/platform/wayland/test/test_zaura_output.h
new file mode 100644
index 0000000..386e8ef
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/test_zaura_output.h
@@ -0,0 +1,46 @@
+// 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_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_OUTPUT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_OUTPUT_H_
+
+#include <wayland-client-protocol.h>
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/ozone/platform/wayland/test/server_object.h"
+
+namespace wl {
+
+// Manages zaura_output object.
+class TestZAuraOutput : public ServerObject {
+ public:
+  explicit TestZAuraOutput(wl_resource* resource);
+
+  TestZAuraOutput(const TestZAuraOutput&) = delete;
+  TestZAuraOutput& operator=(const TestZAuraOutput&) = delete;
+
+  ~TestZAuraOutput() override;
+
+  const gfx::Insets& GetInsets() const { return insets_; }
+  void SetInsets(const gfx::Insets& insets) { pending_insets_ = insets; }
+
+  int32_t GetLogicalTransform() const { return logical_transform_; }
+  void SetLogicalTransform(int32_t logical_transform) {
+    pending_logical_transform_ = logical_transform;
+  }
+
+  void Flush();
+
+ private:
+  gfx::Insets insets_;
+  absl::optional<gfx::Insets> pending_insets_;
+
+  int32_t logical_transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
+  absl::optional<int32_t> pending_logical_transform_;
+};
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_ZAURA_OUTPUT_H_
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index b1180a8..252986e 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -151,6 +151,7 @@
     "//ui/base/x",
     "//ui/base/x:test_support",
     "//ui/base/x:unittests",
+    "//ui/display:test_support",
     "//ui/events:test_support",
     "//ui/events/devices/x11",
     "//ui/events/platform/x11",
diff --git a/ui/ozone/platform/x11/test/x11_window_unittest.cc b/ui/ozone/platform/x11/test/x11_window_unittest.cc
index f499dbe..cccb2e24 100644
--- a/ui/ozone/platform/x11/test/x11_window_unittest.cc
+++ b/ui/ozone/platform/x11/test/x11_window_unittest.cc
@@ -15,6 +15,7 @@
 #include "ui/base/x/x11_util.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/screen_base.h"
+#include "ui/display/test/test_screen.h"
 #include "ui/events/devices/x11/touch_factory_x11.h"
 #include "ui/events/event.h"
 #include "ui/events/platform/x11/x11_event_source.h"
@@ -215,8 +216,8 @@
     ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(pointer_devices);
 
     // X11 requires display::Screen instance.
-    test_screen_ = new TestScreen();
-    display::Screen::SetScreenInstance(test_screen_);
+    test_screen_.emplace();
+    display::Screen::SetScreenInstance(&test_screen_.value());
 
     // Make X11 synchronous for our display connection. This does not force the
     // window manager to behave synchronously.
@@ -226,6 +227,8 @@
  protected:
   void TearDown() override {
     x11::Connection::Get()->SynchronizeForTest(false);
+    display::Screen::SetScreenInstance(nullptr);
+    test_screen_.reset();
   }
 
   std::unique_ptr<X11Window> CreateX11Window(
@@ -252,7 +255,7 @@
   std::unique_ptr<base::test::TaskEnvironment> task_env_;
   std::unique_ptr<X11EventSource> event_source_;
 
-  TestScreen* test_screen_ = nullptr;
+  absl::optional<TestScreen> test_screen_;
 };
 
 // https://crbug.com/898742: Test is flaky.
diff --git a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
index f130507c..8f8953c 100644
--- a/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
+++ b/ui/ozone/platform/x11/x11_window_ozone_unittest.cc
@@ -78,12 +78,13 @@
   void SetUp() override {
     event_source_ = std::make_unique<X11EventSource>(x11::Connection::Get());
 
-    test_screen_ = new TestScreen();
-    display::Screen::SetScreenInstance(test_screen_);
+    display::Screen::SetScreenInstance(&test_screen_);
 
     TouchFactory::GetInstance()->SetPointerDeviceForTest({kPointerDeviceId});
   }
 
+  void TearDown() override { display::Screen::SetScreenInstance(nullptr); }
+
  protected:
   std::unique_ptr<PlatformWindow> CreatePlatformWindow(
       MockPlatformWindowDelegate* delegate,
@@ -112,7 +113,7 @@
     return window_manager;
   }
 
-  TestScreen* test_screen_ = nullptr;
+  TestScreen test_screen_;
 
  private:
   std::unique_ptr<base::test::TaskEnvironment> task_env_;
@@ -283,7 +284,7 @@
 // Verifies X11Window sets fullscreen bounds in pixels when going to fullscreen.
 TEST_F(X11WindowOzoneTest, ToggleFullscreen) {
   constexpr gfx::Rect screen_bounds_in_px(640, 480, 1280, 720);
-  test_screen_->SetScaleAndBoundsForPrimaryDisplay(2, screen_bounds_in_px);
+  test_screen_.SetScaleAndBoundsForPrimaryDisplay(2, screen_bounds_in_px);
 
   MockPlatformWindowDelegate delegate;
   gfx::AcceleratedWidget widget;
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index aa32ca5..30fcf86d 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -97,6 +97,11 @@
 }
 
 // static
+bool OzonePlatform::IsInitialized() {
+  return !!g_instance;
+}
+
+// static
 std::string OzonePlatform::GetPlatformNameForTest() {
   return GetOzonePlatformName();
 }
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index 22ba323..df6b551 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -240,6 +240,8 @@
 
   static OzonePlatform* GetInstance();
 
+  static bool IsInitialized();
+
   // Returns the current ozone platform name.
   // Some tests may skip based on the platform name.
   static std::string GetPlatformNameForTest();
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
index f786b1b..45189c7 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -820,30 +820,33 @@
     : public BubbleDialogDelegateViewTest,
       public testing::WithParamInterface<ArrowTestParameters> {
  public:
-  BubbleDialogDelegateViewArrowTest() : screen_override_(SetUpTestScreen()) {}
+  BubbleDialogDelegateViewArrowTest() { SetUpTestScreen(); }
 
   BubbleDialogDelegateViewArrowTest(const BubbleDialogDelegateViewArrowTest&) =
       delete;
   BubbleDialogDelegateViewArrowTest& operator=(
       const BubbleDialogDelegateViewArrowTest&) = delete;
 
-  ~BubbleDialogDelegateViewArrowTest() override = default;
+  ~BubbleDialogDelegateViewArrowTest() override {
+    display::Screen::SetScreenInstance(nullptr);
+  }
 
  private:
-  display::Screen* SetUpTestScreen() {
-    const display::Display test_display = test_screen_.GetPrimaryDisplay();
+  void SetUpTestScreen() {
+    DCHECK(!display::test::TestScreen::Get());
+    test_screen_ = std::make_unique<display::test::TestScreen>();
+    display::Screen::SetScreenInstance(test_screen_.get());
+    const display::Display test_display = test_screen_->GetPrimaryDisplay();
     display::Display display(test_display);
     display.set_id(0x2);
     display.set_bounds(gfx::Rect(0, 0, kScreenWidth, kScreenHeight));
     display.set_work_area(gfx::Rect(0, 0, kScreenWidth, kScreenHeight));
-    test_screen_.display_list().RemoveDisplay(test_display.id());
-    test_screen_.display_list().AddDisplay(display,
-                                           display::DisplayList::Type::PRIMARY);
-    return &test_screen_;
+    test_screen_->display_list().RemoveDisplay(test_display.id());
+    test_screen_->display_list().AddDisplay(
+        display, display::DisplayList::Type::PRIMARY);
   }
 
-  display::test::TestScreen test_screen_;
-  display::test::ScopedScreenOverride screen_override_;
+  std::unique_ptr<display::test::TestScreen> test_screen_;
 };
 
 TEST_P(BubbleDialogDelegateViewArrowTest, AvailableScreenSpaceTest) {
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
index 4c219d938..34b4af7 100644
--- a/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -24,6 +24,7 @@
 #import "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/ime/input_method.h"
 #import "ui/base/test/cocoa_helper.h"
+#include "ui/display/screen.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #import "ui/views/cocoa/native_widget_mac_ns_window_host.h"
@@ -385,6 +386,8 @@
 
  private:
   TestViewsDelegate test_views_delegate_;
+
+  display::ScopedNativeScreen screen_;
 };
 
 class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase,
diff --git a/ui/views/controls/base_control_test_widget.cc b/ui/views/controls/base_control_test_widget.cc
index 1bee91040..1131f0eb 100644
--- a/ui/views/controls/base_control_test_widget.cc
+++ b/ui/views/controls/base_control_test_widget.cc
@@ -23,8 +23,6 @@
 BaseControlTestWidget::~BaseControlTestWidget() = default;
 
 void BaseControlTestWidget::SetUp() {
-  ViewsTestBase::SetUp();
-
 #if BUILDFLAG(IS_MAC)
   test_screen_ = std::make_unique<display::test::TestScreenMac>(gfx::Size());
   // Purposely not use ScopedScreenOverride, in which GetScreen() will
@@ -32,6 +30,8 @@
   display::Screen::SetScreenInstance(test_screen_.get());
 #endif
 
+  ViewsTestBase::SetUp();
+
   widget_ = std::make_unique<Widget>();
   Widget::InitParams params =
       CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -47,10 +47,10 @@
 void BaseControlTestWidget::TearDown() {
   widget_.reset();
 
+  ViewsTestBase::TearDown();
 #if BUILDFLAG(IS_MAC)
   display::Screen::SetScreenInstance(nullptr);
 #endif
-  ViewsTestBase::TearDown();
 }
 
 void BaseControlTestWidget::CreateWidgetContent(View* container) {}
diff --git a/ui/views/test/test_desktop_screen_ozone.cc b/ui/views/test/test_desktop_screen_ozone.cc
index 7f018a7..61684a2 100644
--- a/ui/views/test/test_desktop_screen_ozone.cc
+++ b/ui/views/test/test_desktop_screen_ozone.cc
@@ -4,22 +4,20 @@
 
 #include "ui/views/test/test_desktop_screen_ozone.h"
 
-#include <memory>
-
-#include "base/memory/singleton.h"
-
-namespace views {
-namespace test {
-
+namespace views::test {
 namespace {
 TestDesktopScreenOzone* g_instance = nullptr;
 }
 
+// static
+std::unique_ptr<display::Screen> TestDesktopScreenOzone::Create() {
+  auto screen = std::make_unique<TestDesktopScreenOzone>();
+  screen->Initialize();
+  return screen;
+}
+
 TestDesktopScreenOzone* TestDesktopScreenOzone::GetInstance() {
-  if (!g_instance) {
-    g_instance = base::Singleton<TestDesktopScreenOzone>::get();
-    g_instance->Initialize();
-  }
+  DCHECK_EQ(display::Screen::GetScreen(), g_instance);
   return g_instance;
 }
 
@@ -27,8 +25,13 @@
   return cursor_screen_point_;
 }
 
-TestDesktopScreenOzone::TestDesktopScreenOzone() = default;
-TestDesktopScreenOzone::~TestDesktopScreenOzone() = default;
+TestDesktopScreenOzone::TestDesktopScreenOzone() {
+  DCHECK(!g_instance);
+  g_instance = this;
+}
 
-}  // namespace test
-}  // namespace views
+TestDesktopScreenOzone::~TestDesktopScreenOzone() {
+  g_instance = nullptr;
+}
+
+}  // namespace views::test
diff --git a/ui/views/test/test_desktop_screen_ozone.h b/ui/views/test/test_desktop_screen_ozone.h
index abaea86..1054c1c 100644
--- a/ui/views/test/test_desktop_screen_ozone.h
+++ b/ui/views/test/test_desktop_screen_ozone.h
@@ -5,12 +5,13 @@
 #ifndef UI_VIEWS_TEST_TEST_DESKTOP_SCREEN_OZONE_H_
 #define UI_VIEWS_TEST_TEST_DESKTOP_SCREEN_OZONE_H_
 
+#include <memory>
+
 #include "ui/gfx/geometry/point.h"
 #include "ui/views/widget/desktop_aura/desktop_screen_ozone.h"
 
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
+namespace display {
+class Screen;
 }
 
 namespace views {
@@ -26,6 +27,7 @@
   TestDesktopScreenOzone(const TestDesktopScreenOzone&) = delete;
   TestDesktopScreenOzone& operator=(const TestDesktopScreenOzone&) = delete;
 
+  static std::unique_ptr<display::Screen> Create();
   static TestDesktopScreenOzone* GetInstance();
 
   // DesktopScreenOzone:
@@ -35,12 +37,10 @@
     cursor_screen_point_ = point;
   }
 
- private:
-  friend struct base::DefaultSingletonTraits<TestDesktopScreenOzone>;
-
   TestDesktopScreenOzone();
   ~TestDesktopScreenOzone() override;
 
+ private:
   gfx::Point cursor_screen_point_;
 };
 
diff --git a/ui/views/test/views_test_helper_mac.h b/ui/views/test/views_test_helper_mac.h
index a9abea1..3d5eb38 100644
--- a/ui/views/test/views_test_helper_mac.h
+++ b/ui/views/test/views_test_helper_mac.h
@@ -7,9 +7,11 @@
 
 #include <memory>
 
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/test/scoped_fake_full_keyboard_access.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/test_context_factories.h"
+#include "ui/display/screen.h"
 #include "ui/views/test/views_test_helper.h"
 
 namespace ui {
@@ -58,6 +60,8 @@
   // more consistent with other platforms, where most views are focusable by
   // default.
   ui::test::ScopedFakeFullKeyboardAccess faked_full_keyboard_access_;
+
+  display::ScopedNativeScreen screen_;
 };
 
 }  // namespace views
diff --git a/ui/views/test/widget_test.cc b/ui/views/test/widget_test.cc
index ac1e3a965..9c31b522 100644
--- a/ui/views/test/widget_test.cc
+++ b/ui/views/test/widget_test.cc
@@ -12,8 +12,11 @@
 #include "ui/views/test/native_widget_factory.h"
 #include "ui/views/widget/root_view.h"
 
-namespace views {
-namespace test {
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "ui/views/test/test_desktop_screen_ozone.h"
+#endif
+
+namespace views::test {
 
 namespace {
 
@@ -130,9 +133,19 @@
 
 void DesktopWidgetTestInteractive::SetUp() {
   SetUpForInteractiveTests();
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  screen_ = views::test::TestDesktopScreenOzone::Create();
+#endif
   DesktopWidgetTest::SetUp();
 }
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+void DesktopWidgetTestInteractive::TearDown() {
+  DesktopWidgetTest::TearDown();
+  screen_.reset();
+}
+#endif
+
 TestDesktopWidgetDelegate::TestDesktopWidgetDelegate()
     : TestDesktopWidgetDelegate(nullptr) {}
 
@@ -270,5 +283,4 @@
   widget_observation_.Reset();
 }
 
-}  // namespace test
-}  // namespace views
+}  // namespace views::test
diff --git a/ui/views/test/widget_test.h b/ui/views/test/widget_test.h
index 24b792f..c8da09d 100644
--- a/ui/views/test/widget_test.h
+++ b/ui/views/test/widget_test.h
@@ -19,6 +19,10 @@
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/widget/widget_observer.h"
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "ui/display/screen.h"
+#endif
+
 namespace ui {
 namespace internal {
 class InputMethodDelegate;
@@ -156,6 +160,11 @@
 
   // DesktopWidgetTest
   void SetUp() override;
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  void TearDown() override;
+  std::unique_ptr<display::Screen> screen_;
+#endif
 };
 
 // A helper WidgetDelegate for tests that require hooks into WidgetDelegate
diff --git a/ui/views/widget/desktop_aura/desktop_screen_win.cc b/ui/views/widget/desktop_aura/desktop_screen_win.cc
index 7c352dd..b5ad964 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_win.cc
@@ -13,10 +13,13 @@
 
 namespace views {
 
-DesktopScreenWin::DesktopScreenWin() = default;
+DesktopScreenWin::DesktopScreenWin() {
+  DCHECK(!display::Screen::HasScreen());
+  display::Screen::SetScreenInstance(this);
+}
 
 DesktopScreenWin::~DesktopScreenWin() {
-  display::Screen::SetScreenInstance(old_screen_);
+  display::Screen::SetScreenInstance(nullptr);
 }
 
 HWND DesktopScreenWin::GetHWNDFromNativeWindow(gfx::NativeWindow window) const {
diff --git a/ui/views/widget/desktop_aura/desktop_screen_win.h b/ui/views/widget/desktop_aura/desktop_screen_win.h
index 6ab217c..c2cbf5a 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_win.h
+++ b/ui/views/widget/desktop_aura/desktop_screen_win.h
@@ -23,9 +23,6 @@
   HWND GetHWNDFromNativeWindow(gfx::NativeWindow window) const override;
   gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override;
   bool IsNativeWindowOccluded(gfx::NativeWindow window) const override;
-
-  const raw_ptr<display::Screen> old_screen_ =
-      display::Screen::SetScreenInstance(this);
 };
 
 }  // namespace views
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn
index 660b5a3..d006f7979 100644
--- a/ui/wm/BUILD.gn
+++ b/ui/wm/BUILD.gn
@@ -100,10 +100,15 @@
   sources = [
     "test/testing_cursor_client_observer.cc",
     "test/testing_cursor_client_observer.h",
-    "test/wm_test_helper.cc",
-    "test/wm_test_helper.h",
   ]
 
+  if (is_chromeos_ash) {
+    sources += [
+      "test/wm_test_helper.cc",
+      "test/wm_test_helper.h",
+    ]
+  }
+
   public_deps = [ "//ui/base/cursor" ]
 
   deps = [
diff --git a/ui/wm/test/wm_test_helper.cc b/ui/wm/test/wm_test_helper.cc
index 5088317..6e09afb6 100644
--- a/ui/wm/test/wm_test_helper.cc
+++ b/ui/wm/test/wm_test_helper.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
 #include "ui/aura/client/default_capture_client.h"
 #include "ui/aura/test/test_focus_client.h"
 #include "ui/aura/test/test_screen.h"
@@ -21,10 +22,10 @@
 
 WMTestHelper::WMTestHelper(const gfx::Size& default_window_size) {
   wm_state_ = std::make_unique<WMState>();
-
-  // Install a screen, like TestWindowService's AuraTestHelper for InitMusHost.
-  test_screen_ = base::WrapUnique(aura::TestScreen::Create(gfx::Size()));
-  display::Screen::SetScreenInstance(test_screen_.get());
+  if (!display::Screen::HasScreen()) {
+    test_screen_ = base::WrapUnique(aura::TestScreen::Create(gfx::Size()));
+    display::Screen::SetScreenInstance(test_screen_.get());
+  }
 
   host_ = aura::WindowTreeHost::Create(
       ui::PlatformWindowInitProperties{gfx::Rect(default_window_size)});
@@ -46,8 +47,7 @@
 
 WMTestHelper::~WMTestHelper() {
   host_->window()->RemovePreTargetHandler(root_window_event_filter_.get());
-
-  if (display::Screen::GetScreen() == test_screen_.get())
+  if (test_screen_)
     display::Screen::SetScreenInstance(nullptr);
 }
 
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc
index d9456e9..cb033a0 100644
--- a/weblayer/app/content_main_delegate_impl.cc
+++ b/weblayer/app/content_main_delegate_impl.cc
@@ -235,10 +235,11 @@
   return false;
 }
 
-bool ContentMainDelegateImpl::ShouldCreateFeatureList() {
+bool ContentMainDelegateImpl::ShouldCreateFeatureList(InvokedIn invoked_in) {
 #if BUILDFLAG(IS_ANDROID)
-  // On android WebLayer is in charge of creating its own FeatureList.
-  return false;
+  // On android WebLayer is in charge of creating its own FeatureList in the
+  // browser process.
+  return invoked_in == InvokedIn::kChildProcess;
 #else
   // TODO(weblayer-dev): Support feature lists on desktop.
   return true;
@@ -297,8 +298,9 @@
 #endif
 }
 
-void ContentMainDelegateImpl::PostEarlyInitialization(bool is_running_tests) {
-  browser_client_->CreateFeatureListAndFieldTrials();
+void ContentMainDelegateImpl::PostEarlyInitialization(InvokedIn invoked_in) {
+  if (invoked_in != InvokedIn::kChildProcess)
+    browser_client_->CreateFeatureListAndFieldTrials();
 }
 
 absl::variant<int, content::MainFunctionParams>
diff --git a/weblayer/app/content_main_delegate_impl.h b/weblayer/app/content_main_delegate_impl.h
index 5da2e80..151ecc6 100644
--- a/weblayer/app/content_main_delegate_impl.h
+++ b/weblayer/app/content_main_delegate_impl.h
@@ -29,10 +29,10 @@
 
   // ContentMainDelegate implementation:
   bool BasicStartupComplete(int* exit_code) override;
-  bool ShouldCreateFeatureList() override;
+  bool ShouldCreateFeatureList(InvokedIn invoked_in) override;
   variations::VariationsIdsProvider* CreateVariationsIdsProvider() override;
   void PreSandboxStartup() override;
-  void PostEarlyInitialization(bool is_running_tests) override;
+  void PostEarlyInitialization(InvokedIn invoked_in) override;
   absl::variant<int, content::MainFunctionParams> RunProcess(
       const std::string& process_type,
       content::MainFunctionParams main_function_params) override;
diff --git a/weblayer/browser/webui/net_export_ui.cc b/weblayer/browser/webui/net_export_ui.cc
index a1cbf3d..1ad56ca 100644
--- a/weblayer/browser/webui/net_export_ui.cc
+++ b/weblayer/browser/webui/net_export_ui.cc
@@ -41,7 +41,7 @@
   NetExportMessageHandler(const NetExportMessageHandler&) = delete;
   NetExportMessageHandler& operator=(const NetExportMessageHandler&) = delete;
 
-  ~NetExportMessageHandler() override { file_writer_->StopNetLog(nullptr); }
+  ~NetExportMessageHandler() override { file_writer_->StopNetLog(); }
 
   // content::WebUIMessageHandler implementation.
   void RegisterMessages() override {
@@ -88,9 +88,7 @@
     StartNetLog(base::FilePath());
   }
 
-  void OnStopNetLog(const base::ListValue* list) {
-    file_writer_->StopNetLog(nullptr);
-  }
+  void OnStopNetLog(const base::ListValue* list) { file_writer_->StopNetLog(); }
 
   void OnSendNetLog(const base::ListValue* list) {
     file_writer_->GetFilePathToCompletedLog(